It took me quite a bit to finally find time to work through this amazing course made by @0verfl0w_ and @VK_Intel. If you always wanted to get started into malware analysis or enhance your skills as SOC analyst, don’t hesitate to enroll into this course, they dive as deep as possible into analysis and have a LOT of samples to analyze during course.
Custom Sample background
During an ongoing investigation, one of our IR team members managed to locate an unknown sample on an infected machine belonging to one of our clients. We cannot pass that sample onto you currently as we are still analyzing it to determine what data was exfiltrated. However, one of our backend analysts developed a YARA rule based on the malware packer, and we were able to locate a similar binary that seemed to be an earlier version of the sample we’re dealing with. Would you be able to take a look at it? We’re all hands on deck here, dealing with this situation, and so we are unable to take a look at it ourselves.
We’re not too sure how much the binary has changed, though developing some automation tools might be a good idea, in case the threat actors behind it start utilizing something like Cutwail to push their samples.
I have uploaded the sample alongside this email.
Thanks, and Good Luck!
Before diving into analysis I would recommend to check out one of the articles I have wrote before to get more familiar with malware analysis techniques and tips from amazing people who are doing malware analysis and incident response for living — How to avoid falling down the rabbit hole while analyzing malware.
Sandbox can provide a lot of useful intel about sample behavior like Command&Control communication, injection technics, persistence etc. It is really good practice to start malware analysis with running malware sample inside sandbox, unless you have reasons not to, then you can either configure own instance of cuckoo sandbox or skip this part and jump straight to manual analysis.
Process tree shows that our sample spawns another instance of itself so lets make a note to check for possible process injection techniques.
From network connection information we have 2 suspicious connections to pastebin.com and i.ibb.co made by svchost.exe process. Two other connections to ocsp.digicert.com and isrg.trustid.ocsp.identrust.com are related to TLS certificate validation and are benign. Process svchost.exe is child of the second instance of our sample. Usually svchost.exe runs with “-k” parameter and doesn’t make any outgoing connection which indicates that another instance of process injection could take place.
Quick look at PEstudio gives following takeaways:
- There are no useful strings which indicates some sort of obfuscation used
- Lack of useful imports(for example process injection related imports from sandbox analysis report) indicates dynamic import resolution
- Resource data rcdata with quite large size and high entropy could indicate possible encrypted payload
Now, when we have basic understanding of key points we want to take a look lets dive into disassembly view.
Right after jumping into main function we notice string encryption routine sub_401300 and dynamic import resolution using LoadLibraryA and GetProcAddress.
String encryption routine is simple substitution cipher which corresponds to the following python code.
First part of the main function is responsible for loading resource rcdata using its id 101. Then memory region is allocated and data from just loaded resource with offset 0x1C is copied there. Size of copied data is calculated using dword at offset 8 of rcdata multiplied by 10.
Second part of the main function decrypts copied data using RC4 algorithm with key at offset 0xC of rcdata and key size 0xF. Decrypted data is passed to the function sub_401000.
Function sub_401000 spawns another instance of itself in suspended state using CreateProcessA and GetModuleFileNameA which returns full path to the binary.
Then function sub_401000 performs PE injection of the decrypted data using WriteProcessMemory and VirtualAllocEx. After writing PE sections to remote process, new entry point is set using SetThreadContext and ResumeThread.
Decrypted PE analysis
At first decrypted executable checks if it is running as svchost.exe using crc32 hashing algorithm. This can be easily recognized with crc32’s constant 0xEDB88320
Decrypted executable also uses dynamic import resolution, but this time it uses PE header offsets to ExportTable and AddressOfNames to get export functions names and then it uses crc32 hashing for import resolution.
To speed up analysis process I have wrote small IDA script which puts comment with function name alongside each resolved import. If you want to know more about IDA scripting for IAT resolution take a look at amazing video from OALabs [https://youtu.be/R4xJou6JsIE]. Script code will be provided in the end of the article.
Let’s go back to main function after we resolved all imports. Mentioned before check for running process name svchost.exe will execute Command&Control communication routine if it is true, otherwise it runs multiple anti-debugging and anti-analysis checks, spawns svchost.exe process in suspended state and performs self-injection into svchost.exe process.
As anti-debugging check it simply runs IsDebuggerPresent and for anti-analysis it enumerates running processes using CreateToolhelp32Snapshot, calculates hashes for process names using crc32 algorithm and compares them to the list of hardcoded hashes.
If process name is svchost.exe we enter Command&Control communication routine. Communication routine resolves internet communication related imports, decrypts pastebin URL and makes connection to it. Response is passed to sub_4013A0 function.
In the beginning function sub_4013A0 executes same routine to retrieve data at URL which means that mentioned before pastebin URL should contain another URL and if we visit it, we can see that it is indeed contains [https://i.ibb.co/KsfqHym/PNG-02-Copy.png] which points to the picture.
After that function sub_4013A0 creates directory inside temp folder with the name cruloader and saves retrieved image there.
Then function sub_4013A0 calculates offset to redaolurc string inside retrieved image (cruloader reversed).
After calculating offset to redaolurc string, function sub_4013A0 decrypts data after offset using XOR with key aaaaaaaaaaaaaaaa. Then it resolves process injection related functions, creates svchost.exe process in suspended state and performs process hollowing with decrypted PE file appended to image.
Decrypted PE is simple program which only spawns message box.
Payload extraction script
To extract final payload we need to make next steps:
- Extract second executable from resources at offset 0x1C and decrypt it using RC4 algorithm with the key at offset 0xF
- From extracted PE file we need to extract URL. First we should find cruloader string, calculate aligned zero bytes and split rest with 0x00 byte, second element in result list will be our encrypted URL
- Decrypt URL, make http request to get second URL and download image
- Find offset to inversed cruloader string inside image and XOR everything after offset with key, in our case we can use just “a”
- Save decrypted content to the file and that would be our final payload
Full code for final payload extraction script will be provided in the end of the article.
From time to time pastebin takes down payload delivery link which is very common. So I have decided find workaround how I can host second link or final payload by own webserver. You can easily hook communication to C2 using fakenet-ng tool, but it becomes very tricky when you are dealing with HTTPs. Next solution which came to my mind was to patch URL in memory with debugger, but that sounds far from automation so I decided to take a look at DBI framework frida.
For my frida hooking script I have reused code from HawkEye, malware dynamic instrumentation tool based on frida.re framework. It already intercepts network communication WinAPI calls and handles dynamic import resolution. The only thing needed is to allocated new URL string with Memory.allocUtf16String and replace current URL with new one using Memory.copy. Full code for the script is provided in the end of the article.
If we run our script we can see that hooked function changed URL to abc.txt hosted on local webserver.