Monday, January 11, 2021

Malware Analysis - Learning about Graftor malware with Ghidra and x64dbg

This post and all others for this month are part of the series which I used to help me prepare for my GIAC Reverse Engineer Malware (GREM) certification.

As always, the static and dynamic analysis was completed before any attempts to learn about this sample via Ghidra and x64dbg.

Taking a look at this from the perspective of both Ghidra and x64dbg by poking at a few function calls.

Ghidra Static Code Analysis

Looking at the GetCurrentProcess function, we see this function is called and the return value is pushed unto the stack.

        00406205 ff d6           CALL       ESI=>KERNEL32.DLL::GetCurrentProcess
        00406207 50              PUSH       EAX                                              ; HANDLE hTargetProcessHandle fo

Wanting to understand what the SHGetSpecialFolderPathA function is about, below we see:

        00401f84 6a 00           PUSH       0x0                                                     ; BOOL fCreate for SHGetSpecialF
        00401f86 6a 1a           PUSH       0x1a                                                    ; int csidl for SHGetSpecialFold
        00401f88 8d 44 24 08     LEA        EAX=>file_path, [ESP + 0x8]
        00401f8c 50              PUSH       EAX                                                     ; LPSTR pszPath for SHGetSpecial
        00401f8d 6a 00           PUSH       0x0                                                     ; HWND hwnd for SHGetSpecialFold
        00401f8f ff 15 74        CALL       dword ptr [->SHELL32.DLL::SHGetSpecialFolderPathA]

My understanding is that the value 0x1a which is associated with the csidl determines the folder. This value 0x1a represents the APPDATA folder. Alternatively, can confirm this folder in the debugger. Note, from Ghidra's perspective, this call was made twice. 

After finding the special folder, a call is made to CreateDirectoryA

        00401fff 6a 00           PUSH       0x0                                                     ; LPSECURITY_ATTRIBUTES lpSecuri
        00402001 50              PUSH       EAX=>DAT_004342ac                                       ; LPCSTR lpPathName for CreateDi
        00402002 ff 15 38        CALL       dword ptr [->KERNEL32.DLL::CreateDirectoryA]

Next up, we see a call is made to GetComputerNameA to learn the computer name.

        00403580 68 f8 41        PUSH       nSize_004341f8                                          ; LPDWORD nSize for GetComputerNameA                                                                                                ; = 00000010
        00403585 68 d4 6d        PUSH       lpBuffer_00436dd4                                       ; LPSTR lpBuffer for GetComputerNameA                                                                ; = ??
        0040358a ff 15 18        CALL       dword ptr [->KERNEL32.DLL::GetComputerNameA]

Once the function to get computer name has executed, we then see a call to GetUserNameA.

        00403580 68 f8 41        PUSH       nSize_004341f8                                          ; LPDWORD nSize for GetComputerNameA                                                                                                    ; = 00000010
        00403585 68 d4 6d        PUSH       lpBuffer_00436dd4                                       ; LPSTR lpBuffer for GetComputerNameA                                                                                    ; = ??
        0040358a ff 15 18        CALL       dword ptr [->KERNEL32.DLL::GetComputerNameA]

Another function of interest relates to CreateFileA. Looking in Ghidra, there are multiple calls to this function. Specifically 5 calls. Looking at one of them, we see a normal file being created with read permission and the file should be opened only if it already exists.

                             LAB_00406729                                    XREF[1]:     00406721(j)  
        00406729 6a 00           PUSH       0x0                                                     ; HANDLE hTemplateFile for CreateFileA
        0040672b 51              PUSH       this                                                    ; DWORD dwFlagsAndAttributes for CreateFileA
        0040672c 50              PUSH       EAX                                                     ; DWORD dwCreationDisposition for CreateFileA
        0040672d 8d 85 e0        LEA        EAX=>local_124, [EBP + 0xfffffee0]
        00406733 50              PUSH       EAX                                                     ; LPSECURITY_ATTRIBUTES lpSecurityAttributes f
        00406734 52              PUSH       EDX                                                     ; DWORD dwShareMode for CreateFileA
        00406735 ff b5 f0        PUSH       dword ptr [EBP + dwDesiredAccess]                       ; DWORD dwDesiredAccess for CreateFileA
        0040673b ff b5 f4        PUSH       dword ptr [EBP + lpFileName]                            ; LPCSTR lpFileName for CreateFileA
        00406741 ff 15 b0        CALL       dword ptr [->KERNEL32.DLL::CreateFileA]

Seeing a call to PathAppendA, we see this below this requires a pointer to the original path and another point to the string which will be appended. Looking forward to see what x64dbg shows us here.

        004043a1 8d 4c 24 24     LEA        ECX=>local_310, [ESP + 0x24]
        004043a5 51              PUSH       ECX                                                     ; LPCSTR pMore for PathAppendA
        004043a6 8d 94 24        LEA        EDX=>local_20c, [ESP + 0x12c]
        004043ad 52              PUSH       EDX                                                     ; LPSTR pszPath for PathAppendA
        004043ae ff 15 88        CALL       dword ptr [->SHLWAPI.DLL::PathAppendA]

Looking at the InternetOpenA call, we see

        004072ed ff 75 1c        PUSH       dword ptr [EBP + dwFlags]                               ; DWORD dwFlags for InternetOpenA
        004072f0 ff 75 18        PUSH       dword ptr [EBP + lpszProxyBypass]                       ; LPCSTR lpszProxyBypass for InternetOpenA
        004072f3 ff 75 14        PUSH       dword ptr [EBP + lpszProxy]                             ; LPCSTR lpszProxy for InternetOpenA
        004072f6 ff 75 10        PUSH       dword ptr [EBP + dwAccessType]                          ; DWORD dwAccessType for InternetOpenA
        004072f9 50              PUSH       EAX                                                     ; LPCSTR lpszAgent for InternetOpenA
        004072fa ff 15 1c        CALL       dword ptr [->WININET.DLL::InternetOpenA]

x64dbg Dynamic Analysis

Looking at GetCurrentProcess we confirm what we saw in Ghidra that the return value FFFFFFFF  (-1) which is stored in EAX is pushed unto the stack, we also see this value is used as an argument to the GetProcessMitigationPolicy function which checks the mitigation policy of the calling process.  This call to GetProcessMitigationPolicy is made multiple times within this sample. 

Looking at the interactions, I seems this malware also interacts with the Clipboard as shown via RegisterClipboardFormatA. This call was also made multiple times.

Looking at the code before the return is executed, we see SHGetSpecialFolderPathA has a value of "C:\\Users\\SecurityNik\\AppData\\Roaming". Guess that confirms the 0x1A we learned about earlier via Ghidra points to Application Data folder. In another call, this function returned "C:\\Users\\SecurityNik\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"

Looking at the CreateDirectoryA function, we see a directory named DataBackup is created. 

Further confirmation that this directory has been created.

C:\Users\SecurityNik>dir %appdata%
Directory of C:\Users\SecurityNik\AppData\Roaming

12/09/2020  11:53 AM    <DIR>          .
12/09/2020  11:53 AM    <DIR>          ..
12/09/2020  11:18 AM    <DIR>          DataBackup

Looking at the call to GetComputerNameA. It seems that GetComputerNameA, ended up calling GetComputerNameW. The first parameter to GetComputerNameW is a pointer to a buffer that receives the computer name. Looking at the output from x64dbg, we see the address 0x0019FB84 points to the buffer which received the computer name which is reported as SECRUTIYNIK-WIN. Surprisingly the call for the computer is made multiple times.

GetUserNameA calls GetUserNameExA and ultimately returns current logged in user who is SecurityNik

We can further confirm the above two important as follows.



Looking at one of the calls to CreateFileA we see below a file named sed.ic being created in the previously created DataBackup folder. Later in the debugging, calls to CreateFileA resulted in the creation of a file named me.ic in the same folder.

After leaving the above code to run, I did not see the file created in the folder. 

Here is the contents of the me.ic file.

C:\Users\SecurityNik\AppData\Roaming\DataBackup>type me.ic

Active Window: Process Hacker [SECURITYNIK-WIN\SecurityNik]
SEESION 12/09/20 11:18:03

Paying attention to the PathAppendA function, we see below what seems like persistence is being added via the Startup folder of the Start Menu via a .LNK file.

Looking on the host to see if this artifact was created, we see bellow that the entry was created successfully.

C:\Users\SecurityNik\AppData\Roaming>wmic startup where "Caption like '%Data%'" list full


Looking at the OpenProcess call, we see a call to create a process which allows duplication of its handle. Additionally, we see the process has 000013F4.

Using Hex2Dec from Sysinternals, we convert 0x13f4 to decimal and get 5108.

C:\Users\SecurityNik\AppData\Roaming>hex2dec -nobanner 0x13f4
0x13F4 = 5108

Digging deeper, we see that the process with decimal 5108 as its process ID is expolorer.exe

C:\Users\SecurityNik\AppData\Roaming>wmic process where processID=5108 get ProcessID,name,CSName
CSName           Name          ProcessId
SECURITYNIK-WIN  explorer.exe  5108

If I know anything at this point, it is whenever malware is seen opening a process, especially a process such as explorer[.]exe, we can all but conclude this is more than likely going to be some type of process injection. Let's continue this journey.

While not shown below, there was a call to InternetOpenA thus initializing the application's use of this function.  

There was then another call to OpenProcess. However, this time it is an attempt to open its's own process with PID 0x794 which is decimal 1940.

C:\Users\SecurityNik\AppData\Roaming\DataBackup>hex2dec -nobanner 0x794
0x794 = 1940

C:\Users\SecurityNik\AppData\Roaming\DataBackup>wmic process where processID=1940 get ProcessID,name,CSName
CSName           Name        ProcessId
SECURITYNIK-WIN  msdsrv.exe  1940

The following is the call to InternetConnectA which is attempting to connect to visitorzilla[.]com on port 0x50 (80).

At this point, I modified my host file adding an entry for visitorzilla[.]com.

C:\Users\SecurityNik\AppData\Roaming>echo >>  c:\windows\System32\drivers\etc\hosts
C:\Users\SecurityNik\AppData\Roaming>type c:\windows\System32\drivers\etc\hosts | findstr /i visit

Next we see a call to HTTPOpenRequestA via POST attempting to communicate with /werdfghswepfdhfr.php. Later a call was made to HTTPAddRequestHeaderSA and  HTTPSendRequestA. These are not shown in this post.

Thsi above is followed by a call to InternetWriteFile for which 0x126 (294) bytes are to be written to a file named temp.txt.

Looking closer at the data pointed to in the buffer at 0x04557BB0 we see "--JW98YR8EHFUIEHFUEHFUHEUIFHEUFE93\r\nContent-Disposition: form-data; name=\"shfjshf\"\r\n\r\nU0VDVVJJVFlOSUstV0lOQFNlY3VyaXR5TmlrLw==\r\n--JW98YR8EHFUIEHFUEHFUHEUIFHEUFE93\r\nContent-Disposition: form-data; name=\"dssds\"; filename=\"temp.txt\"\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\n"

Looks like some of the above data is base64 encoded. Breaking this down a bit, we see the base64 content decoded as:


If nothing, we know above there is information about the computer name and the user.

Later, another call was made to InternetWriteFile, this time with the following:

"\r\n--JW98YR8EHFUIEHFUEHFUHEUIFHEUFE93\r\nContent-Disposition: form-data; name=\\Csubmit\\C value=\\Csubmit\\C\r\n\r\n\r\n--JW98YR8EHFUIEHFUEHFUHEUIFHEUFE93--\r\n"

Once completed, there was a call to InternetCloseHandleA.

Looking at the internet connection from INetSim's perspective, we see:

remnux@remnux:/tmp$ cat /var/log/inetsim/service.log | grep --perl-regexp "\:21822\]"
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] connect
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: POST /werdfghswepfdhfr.php HTTP/1.1
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: Content-Type: multipart/form-data; boundary=JW98YR8EHFUIEHFUEHFUHEUIFHEUFE93
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: User-Agent: Top
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: Host:
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: Content-Length: 440
[2020-12-11 09:37:45] [1920] [http_80_tcp 13190] [] recv: Cache-Control: no-cache
[2020-12-11 09:39:45] [1920] [http_80_tcp 13190] [] info: POST data stored to: /var/lib/inetsim/http/postdata/f6083d9fb7a9dac9efd47287f5f4a83d16380e03
[2020-12-11 09:39:45] [1920] [http_80_tcp 13190] [] disconnect (timeout)

Looking at the contents of one of the postdata files created, we see:

remnux@remnux:~/malware/day1$ sudo cat  /var/lib/inetsim/http/postdata/c317d7ab622a9ede0150aa8c6903d55fd2acd9ec 
Content-Disposition: form-data; name="shfjshf"

Content-Disposition: form-data; name="dssds"; filename="temp.txt"
Content-Type: text/plain
Content-Transfer-Encoding: binary

Content-Disposition: form-data; name=\Csubmit\C value=\Csubmit\C


I have not decoded the above. However, I'm sure if we did, it would be the same thing as we saw previously.

Continuing this journey, we see a call to DeleteFileA to delete the file sed.ic.

Verifying this file exists before this code executes. 

C:\Users\SecurityNik\AppData\Roaming\DataBackup>dir sed.ic
 Volume in drive C has no label.
 Volume Serial Number is 6C10-15EA

 Directory of C:\Users\SecurityNik\AppData\Roaming\DataBackup

12/10/2020  03:25 PM                 0 sed.ic
               1 File(s)              0 bytes
               0 Dir(s)  36,314,120,192 bytes free

Letting the call to DeleteFileA run, we see:

Confirming the file has been deleted, we see:

C:\Users\SecurityNik\AppData\Roaming\DataBackup>dir sed.ic
 Volume in drive C has no label.
 Volume Serial Number is 6C10-15EA

 Directory of C:\Users\SecurityNik\AppData\Roaming\DataBackup

File Not Found

After hitting a few more breakpoints, the process Terminated. I believe one of the anti-debugging mechanism probably kicked in. At this point, I've achieved my objective. I've learned a bit more and I was able to extract some IoCs. Enough to call it a day on this.


Microsoft GetCurrentProcess
Why does GetCurrentProcess return -1
CSIDL values

1 comment:

  1. Good post! Can you please point me to good books and resources where I can learn assembly and C for reverse engineering.