Monday, January 11, 2021

Continuing Dynamic Malware Analysis - DoomJuice - Static Analysis with Ghidra and Dynamic Analysis with x64dbg

While the majority of static analysis is not shown in this post, it was done. However, what I thought I should add from the static analysis was information relating to the imports.

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.


 Above registry entry confirms what we found during the static analysis of wsprintfA above.

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