As I looked through the imports for the first 3 DLLs, I could see the functions which are being imported.
While above looks ok, looking at the WS2_32.dll which is associated with Windows Sockets, I see ordinal values instead.
Above suggests this process is doing tasks related to networking. However, I'm unable to be definitive on what the associated functions as I am unaware of what those ordinal values map to. Time to transition to Ghidra.
After setting up the Ghidra Project and letting Ghidra Analyze the file we have better insights into what those ordinals mean by looking at the Symbol Tree.
Now that we have those resolved, we can look a little closer into the associated functions.
Let's start with the socket function. First at the assembly code. If we review this function from Microsoft's website, we see it takes 3 parameters which are all integers. These parameters are af, type and protocol.
Let's see what was provided to the socket function via the assembly code.
1 2 3 4 5 | LAB_0040aa42 XREF[2]: 0040aa71(j), 0040aa97(j) 0040aa42 6a 06 PUSH 0x6 ; int protocol for socket 0040aa44 6a 01 PUSH 0x1 ; int type for socket 0040aa46 6a 02 PUSH 0x2 ; int af for socket 0040aa48 ff 15 a4 10 40 00 CALL dword ptr [->WS2_32.DLL::socket] |
As we see above, three arguments are passed to the WS2_32.dll::socket function. These are 2 (af), 1 (type) and 6 (protocol). Digging deeper into Microsoft's documentation. Let's break this down further.
2 (af) - This represents AF_INET - The IPv4 family of protocols
1 (type) - SOCK_STREAM - Provides reliable communication and uses TCP
6 (protocol) - IPPROTO_TCP - this says to use TCP.
At this point we know how the socket function is built and we know this malware uses TCP communication. Can we find the IPs. We will have to look deeper.
Still sticking with Ghidra and some other functions I think are interesting at this time, let's look at the call to CreateMutexA at address
Nik Comment: Function named changed by Nik Create_Mutex_0040a741 XREF[1]: entry:0040ac13(c) 0040a741 55 PUSH EBP 0040a742 8b ec MOV EBP,ESP 0040a744 83 ec 40 SUB ESP,0x40 0040a747 80 65 ce 00 AND byte ptr [EBP + local_36],0x0 0040a74b 8d 45 c0 LEA EAX=>local_44,[EBP + -0x40] 0040a74e 50 PUSH EAX ; LPCSTR lpName for CreateMutexA 0040a74f 6a 01 PUSH 0x1 ; BOOL bInitialOwner for CreateM Nik Comment: 1 byte values being moved into EBP. 0x73 hex = ASCII 's' 0x79 hex = ASCII 'y' 0x6e hex = ASCII 'n' 0x63 hex = ASCII 'c' 0x2d hex = ASCII '-' 0x5a hex = ASCII 'z' 0x2d hex = ASCII '-' 0x6d hex = ASCII 'm' 0x74 hex = ASCII 't' 0x78 hex = ASCII 'x' 0x5f hex = ASCII '_' 0x31 hex = ASCII '1' 0x33 hex = ASCII '3' 0x33 hex = ASCII '3' Note I could have instead "Set Equate" to represent the byte 0040a751 6a 00 PUSH 0x0 ; LPSECURITY_ATTRIBUTES lpMutexA 0040a753 c6 45 c0 73 MOV byte ptr [EBP + local_44],0x73 0040a757 c6 45 c1 79 MOV byte ptr [EBP + local_43],0x79 0040a75b c6 45 c2 6e MOV byte ptr [EBP + local_42],0x6e 0040a75f c6 45 c3 63 MOV byte ptr [EBP + local_41],0x63 0040a763 c6 45 c4 2d MOV byte ptr [EBP + local_40],0x2d 0040a767 c6 45 c5 5a MOV byte ptr [EBP + local_3f],0x5a 0040a76b c6 45 c6 2d MOV byte ptr [EBP + local_3e],0x2d 0040a76f c6 45 c7 6d MOV byte ptr [EBP + local_3d],0x6d 0040a773 c6 45 c8 74 MOV byte ptr [EBP + local_3c],0x74 0040a777 c6 45 c9 78 MOV byte ptr [EBP + local_3b],0x78 0040a77b c6 45 ca 5f MOV byte ptr [EBP + local_3a],0x5f 0040a77f c6 45 cb 31 MOV byte ptr [EBP + local_39],0x31 0040a783 c6 45 cc 33 MOV byte ptr [EBP + local_38],0x33 0040a787 c6 45 cd 33 MOV byte ptr [EBP + local_37],0x33 0040a78b ff 15 2c 10 40 00 CALL dword ptr [->KERNEL32.DLL::CreateMutexA] 0040a791 ff 15 30 10 40 00 CALL dword ptr [->KERNEL32.DLL::GetLastError] 0040a797 2d b7 00 00 00 SUB EAX,0xb7 0040a79c f7 d8 NEG EAX 0040a79e 1b c0 SBB EAX,EAX 0040a7a0 40 INC EAX 0040a7a1 c9 LEAVE 0040a7a2 c3 RET
From above, we see it seems the mutex being created is sync-Z-mtx_133.
Looking at the first call to GetSystemDirectoryA, we see the pointer to the buffer which will hold the information is stored in EAX register and the size of the buffer is 0x118 or 280 bytes decimal.
LAB_0040a812 XREF[1]: 0040a8ef(j) 0040a812 39 5d fc CMP dword ptr [EBP + local_8],EBX 0040a815 8d 85 d0 fe ff ff LEA EAX=>local_134,[EBP + 0xfffffed0] 0040a81b 75 0e JNZ LAB_0040a82b 0040a81d 68 18 01 00 00 PUSH 0x118 ; UINT uSize for GetSystemDirect 0040a822 50 PUSH EAX ; LPSTR lpBuffer for GetSystemDi 0040a823 ff 15 40 10 40 00 CALL dword ptr [->KERNEL32.DLL::GetSystemDirectoryA]
The call to wsprintfA at 0040a940 also is an interesting function call in this context. Looking at the wsprintfA call.
0040a915 68 a8 a0 40 00 PUSH DAT_0040a0a8 ; = 6Eh n 0040a91a 68 a4 a0 40 00 PUSH DAT_0040a0a4 ; = 72h r 0040a91f 68 9c a0 40 00 PUSH DAT_0040a09c ; = 72h r 0040a924 68 98 a0 40 00 PUSH DAT_0040a098 ; = 5Ch \ 0040a929 68 94 a0 40 00 PUSH DAT_0040a094 ; = 6Fh o 0040a92e 68 90 a0 40 00 PUSH DAT_0040a090 ; = 74h t 0040a933 68 88 a0 40 00 PUSH DAT_0040a088 ; = 72h r 0040a938 68 80 a0 40 00 PUSH s_ware\M_0040a080 ; = "ware\\M" 0040a93d 8d 45 d0 LEA EAX=>local_a8,[EBP + -0x30] 0040a940 68 5c a0 40 00 PUSH s_Soft%sic%sf%sind%ss%sr%sVe%so%su_0040a05c ; LPCSTR param_2 for wsprintfA ; = "Soft%sic%sf%sind%ss%sr%sVe%
Looking at above, you might be wondering what the hell is s_Soft%sic%sf%sind%ss%sr%sVe%so%su_0040a05c. Let's break this up for simplicity.
1- s_Soft%s
2- ic%s
3- f%s
4 - ind%ss%sr%s
5 - Ve%
6 - so%s
7- u_0040a05c.
Looking closely you can see the %s format specifiers which is consistent with format strings. We can now break this down further. Taking the first string pushed unto the stack which is at which is at 0040a080 (s_ware\M_0040a080).
s_ware\M_0040a080 XREF[1]: FUN_0040a908:0040a938(*) 0040a080 77 61 72 65 5c ds "ware\\M" 0040a087 00 ?? 00h
At this point we have Soft+ware\\M which gives us Software\\M
Looking at the next entry pushed DAT_0040a088 unto the stack. Looking for the string at 0040a088 we get:
s_roso_0040a088 XREF[1]: FUN_0040a908:0040a933(*) 0040a088 72 6f 73 6f 00 ds "roso" 0040a08d 00 ?? 00h 0040a08e 00 ?? 00h 0040a08f 00 ?? 00h
From above we had Software\\M adding the ic+roso we get Software\\Microso
Continuing with the 3rd entry DAT_0040a090 pushed unto the stack we see.
s_t\W_0040a090 XREF[1]: FUN_0040a908:0040a92e(*) 0040a090 74 5c 57 00 ds "t\\W"
At this point we now have Software\\Microso + f + t\\W. Putting it together we get Software\\Microsoft\W. We can continue going along this path. However, in the interest of time, here is what the final string looks like: Software\Microsoft\Windows\CurrentVersion\Run.
Looking further in to see what is being done with this registry key, we see below:
LAB_0040a995 XREF[1]: 0040a97d(j) 0040a995 ff 75 7c PUSH dword ptr [EBP + param_1] ; LPCSTR lpString for lstrlenA 0040a998 ff 15 4c 10 40 00 CALL dword ptr [->KERNEL32.DLL::lstrlenA] 0040a99e 40 INC EAX 0040a99f 50 PUSH EAX ; DWORD cbData for RegSetValueExA 0040a9a0 ff 75 7c PUSH dword ptr [EBP + param_1] ; BYTE * lpData for RegSetValueExA 0040a9a3 8d 45 50 LEA EAX=>local_28,[EBP + 0x50] 0040a9a6 6a 01 PUSH 0x1 ; DWORD dwType for RegSetValueExA 0040a9a8 6a 00 PUSH 0x0 ; DWORD Reserved for RegSetValue 0040a9aa 50 PUSH EAX ; LPCSTR lpValueName for RegSetV 0040a9ab ff 75 70 PUSH dword ptr [EBP + local_8] ; HKEY hKey for RegSetValueExA 0040a9ae ff 15 08 10 40 00 CALL dword ptr [->ADVAPI32.DLL::RegSetValueExA]
Most important for me above is the value which is going to be set. Cheating a bit, I looked at the disassembly and noticed a call to lsstrcpyA and the string Gremlin.
Here is what this looks like in the disassembly.
0040a94f 68 54 a0 40 00 PUSH s_Gremlin_0040a054 ; LPCSTR lpString2 for lstrcpyA ; = "Gremlin" 0040a954 8d 45 50 LEA EAX=>local_28,[EBP + 0x50] 0040a957 50 PUSH EAX ; LPSTR lpString1 for lstrcpyA 0040a958 ff 15 14 10 40 00 CALL dword ptr [->KERNEL32.DLL::lstrcpyA]
Looking at the memory address 0040a054 we see
************************************************************** * lpString2 parameter of lstrcpyA * * * ************************************************************** s_Gremlin_0040a054 XREF[1]: FUN_0040a908:0040a94f(*) 0040a054 47 72 65 6d 6c ds "Gremlin"
Before I transition to x64dbg, I thought I should look at ProcDot output, to see if I can match what is done..
Above we see files were not only written to my local system in different locations but also to shares which are accessible. We also see it created and deleted a file named C:\Users\SecurityNik\AppData\Local\Temp\intrenat[.]exe.
However, upon verification of this, we see the file is actually on the file system. Maybe the file got deleted and I did not pay attention to that entry in ProcDOT.
C:\Users\SecurityNik\Desktop\Malware\day1>dir C:\Users\SecurityNik\AppData\Local\Temp\intrenat.exe Volume in drive C has no label. Volume Serial Number is 6C10-15EA Directory of C:\Users\SecurityNik\AppData\Local\Temp 02/09/2004 01:16 PM 43,008 intrenat.exe 1 File(s) 43,008 bytes 0 Dir(s) 35,435,905,024 bytes free
Looking closer at the files it seems it is the same file written to multiple locations as seen from the hash values below.
PS C:\tmp> Get-FileHash C:\users\SecurityNik\sync-src-1.00.tbz ; get-filehash c:\users\securitynik\appdata\local\virtualstore\windows\sync-src-1.00.tbz ; get-f ilehash C:\Users\SecurityNik\AppData\Local\Temp\sync-src-1.00.tbz Algorithm Hash Path --------- ---- ---- SHA256 6CD0666EE68849E57E054C6A009366868494C4EC73723F607473375518591496 C:\users\SecurityNik\sync-src-1.00.tbz SHA256 6CD0666EE68849E57E054C6A009366868494C4EC73723F607473375518591496 C:\users\securitynik\appdata\local\virtualstore\windows\sync-src-1.0... SHA256 6CD0666EE68849E57E054C6A009366868494C4EC73723F607473375518591496 C:\Users\SecurityNik\AppData\Local\Temp\sync-src-1.00.tbz
Looking deeper into one of the files from a Hex perspective, we see.
At this point, I don't know what to make of this file. Maybe I will learn more about it when the file is being accessed via x64dbg.
To finally get going with x64dbg, here are the breakpoints I set.
SetBPX Kernel32.CopyFileA SetBPX Kernel32.DeleteFileA SetBPX Kernel32.CreateMutexA SetBPX Kernel32.CopyFileA SetBPX Kernel32.GetDriveTypeA SetBPX Kernel32.GetSystemDirectoryA SetBPX Kernel32.GetTempPathA SetBPX Kernel32.ReadFile SetBPX Kernel32.CreateFileA SetBPX Kernel32.WriteFile SetBPX Advapi32.RegOpenKeyExA SetBPX Advapi32.RegCloseKey SetBPX Advapi32.RegSetValueExA SetBPX user32.wsprintfA SetBPX ws2_32.send
Here is what that looks like
After hitting run, the first breakpoint to be hit was CreateMutexA. Looking at the Handles within x64dbg, we see the Mutex created with the name sync-Z-mtx_133. Remember this was the same name we found during static code analysis with Ghidra.
Continuing to run the program, the next breakpoint was GetSystemDirectoryA, which returned: C:\\Windows\\system32
Continuing to run we next hit breakpoint CreateFileA which shows the creation of a file named intrenat[.]exe in the c:\windows\system32 folder. Remember this was returned from GetSystemDirectoryA above.
Running the program again, the next breakpoint to get hit was CopyFileA.
Above we see the original file juice[.]exe was copied to the c:\windows\system32\intrenat[.]exe file. Note also the third parameter 0x00000000 means if the file exists it will simply be overwritten. Interestingly, at this point I did not see the file in my c:\windows\system32 folder. Maybe I missed something or I will see it later.
Next up, we hit wsprintfA function which is writes formatted data to the specified buffer. Here is what this looks like.
Continuing to run, we next hit RegOpenKeyExA breakpoint. I'm skipping this as we focus on RegSetValueExA below.
Above shows the registry value Gremlin is being written in the Run key. We also see 0x21 (33 decimal) bytes are being written and the data contains the intrenat.exe file and path we saw earlier.
Ok. I've done enough for this post. I believe I've learned what I wanted to for this post.
References:
No comments:
Post a Comment