Reversing Cerber - RaaS

Cerber has established itself as one of the most successful ransomware families to date. Distributed as Raas (Ransomware as a Service), the malware has retained popularity with over 6 known variants.

The malware is packed with Nullsoft PiMP (plugin Mini Packager) which hides much of the malware's true functionality.


As a whole, the malware's entropy is quite high (6.1), indicating packed code.



The malware contains an anomalous PE section ".ndata" which has a virtual size much higher than its physical/raw size.  This indicates that there is a good chunk of code that won't present itself until runtime, once the malware is loaded in memory.


pestudio marks the .text/.code section as highly entropic (6.4), this is where the actual code/instructions are stored in a PE.


I conducted this analysis in a host-only virtual network with a Windows 10 VM routing its network traffic to a REMnux VM running fakedns, iNetSim, and Wireshark. The malware happily runs in the VM with security tools running, dropping several files to disk. The number of bytes written to the file 'collages.dll' is the same as the virtual size of the '.ndata' section. 




The malware then makes a few modifications to the registry. A couple of these modifications have to do with what the user is presented with (Wallpaper), the rest have to do with network activity. This malware (interestingly enough) does not establish persistence, just encrypts and exits.




The malware spawns an instance of itself, which then opens the ransom note '_HELP_DECRYPT_N0BR8ST0_.hta'. The filename for this ransom note appears to be unique to the system, format is '_HELP_DECRYPT_[A-Z0-9]{8}_.hta' <- simple regex for the 8 digit alphanumeric string.



Like most ransomware, a ransom note is dropped to the desktop, the Wallpaper is changed, and encrypted files are tagged with a weird file extension '.94d4'.  Another file extension found during analysis was '.bde6' - this value appears to be randomly generated.


The malware contacts hundreds of hosts over port 6892.



The same UDP packet is sent over and over.


The first half of the string is the same as the unique string at the end of the provided URL in the ransom note.


LET THE REVERSING COMMENCE!!!

The process tree from behavioral analysis showed the original instance of cerber launching a new cerber, this turned out to be pretty interesting. Notice the sixth value pushed onto the stack for the CreateProcess API Call, the value 4 is passed for the dwCreationFlags argument. The 4 indicates that this process is created in a suspended state.  Do I sense code injection?


The malware then takes a fairly common path for the injection. Reads memory of the newly spawned cerber.exe, the parameter '2F4' is a handle to said cerber.


The malware then hollows out the suspended process through the WinAPI call 'UnMapViewOfSection'. The parameter '400000' is passed as the base address as to where begin hollowing/unmapping, which is the very beginning/start of the PE.


A buffer is then filled via 'RtlDecompressBuffer', which stores the contents that will be injected into the suspended process. Notice the 'MZ' header, this an executable that will be injected into the target process.


The buffer is then written to the target process via 'WriteProcessMemory'.  A pointer to the executable seen in the dump window is passed as the data to be written.  The base address '400000', which was the start address of the hollowing, is now passed as the base address for this executable to be written to in the hollowed out process.

To intercept this executable, I followed the base address in the memory map and then dumped it. When attempting to load it into IDA, it is not recognized as a valid PE. Looking at the file in HxD, there are around 32 bytes of noise before the magic bytes of the executable.


Deleting up until the 'MZ'/'4D5A' fixes the problem. This looks to be where the true payload/ransomware code lies, this is the first time we have seen crypt-related APIs. So essentially, the malware uses code injection as a way to unpack itself.


Now that the code has been injected/written, the malware must start a thread of execution to invoke the code. The context of the thread is set via 'SetThreadContext'.


And finally, the thread is resumed and the code begins executing in the target process.


Just before taking the instruction to allow 'ResumeThread' to execute, I spawned a new instance of x64dbg and attached to the still suspended cerber.exe.  I then set breakpoints on thread entry and thread start to halt execution once 'ResumeThread' is called. Next, I set break points on all crypt-related APIs, as well as GetProcAddress, so that I can identify any additional code that may be dynamically loaded.  The first function to be dynamically resolved via 'GetProcAddress' is 'CryptEncrypt'.



The next interesting code block was the usage of the API 'CryptStringToBinary'.  This API converts a string to an array of bytes.  The data to be converted is a very long base64 string.


Decoded, the string looks to be a hard-coded Public Key.



The Public Key Info suggests that this is 'RSA 1.2.840.113549.1.1 - PKCS-1' encryption.


Next, the malware creates a directory in the AppData folder where it stores some housekeeping data.


Then a mutex is created. The name of the mutex is resolved dynamically ---- 'shell.{FB79CB8E-F0B4-4B09-A183-601B6025EC35}' and is created just before network activity occurs ('WSAStartup').


A UDP socket is created and will be used to blast that single string to hundreds of IPs.


'sendto' function is included in a loop to contact the external hosts.


Next, the encryption commences.  Traversing directories via 'FindFirstFile' and 'FindNextFile'.  The malware also looks for network resources to encrypt via 'WNetOpenEnum'.


Once encryption completes, the ransom note is opened via 'ShellExecute' with parameters 'Open' and '_HELP_DECRYPT_N0BR8ST0_.hta'.  This ransom note is far more robust than most. Most ransom notes are a simple text file, this is an .hta that has several functions, and is apparently quite universally accommodating. The ransom note even has a button to change the language.



Another interesting code segment is that the .hta file checks the victim's MAC address against a few MAC addresses associated with VMware and some popular network technology companies.  If there is a match, the URL in the ransom note is updated to English. Interesting!


The most interesting part of this malware to me was how it unpacked itself through code injection and process hollowing. This malware just performs the encryption and then exits, no persistence! Most filenames are randomized to evade signature based detection, so regex will be our friends when sweeping for/detecting these artifacts. A Snort rule may be plausible due to the port (6892), but UDP can be noisy. The rule would use PCRE to match the unique long string passed over 6892.

Key Takeaways:
- Encrypts files on disk and in network shares
- Modifies registry
- Drops files on disk
- Performs code injection
- Contacts external hosts

Host-based IOCs:
cerber.exe

2d6ace7910f84eb775272a6590453a0e - md5
\AppData\Local\Temp\collages.dll
2A4BF3D01B6C84A2130C110D02C772AC - md5
\AppData\Local\Temp\floppy_disk.png
\AppData\Local\Temp\floppy_disk_disabled.png
\AppData\Local\Temp\flat.xsl
\AppData\Local\Temp\tmpCBD8.bmp
\AppData\Local\Temp\0ad3e319\4f11.tmp
\AppData\Local\Temp\0ad3e319\280c.tmp
\AppData\Local\Temp\nshBD76.tmp\System.dll
3E6BF00B3AC976122F982AE2AADB1C51 - 
md5
\Desktop\_HELP_DECRYPT_N0BR8ST0_.hta - Ransom note

\Desktop\_HELP_DECRYPT_N0BR8ST0_.jpg - Wallpaper

*.94d4 - file extension tagged onto encrypted files (randomly generated)
*.bde6 - file extension tagged onto encrypted files (randomly generated)
*.[a-z0-9]{4} - regex for file extension
shell.{FB79CB8E-F0B4-4B09-A183-601B6025EC35} - Mutex
\Sessions\1\BaseNamedObjects\SM0:6064:168:WilStaging_02 - Based named object
HKEY_CURRENT_USER\Control Panel\Desktop\WallPaper -REG_SZ - C:\Users\REM\AppData\Local\Temp\tmpCBD8.bmp

Hard-coded Public Key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvkty5qhqEydR9076Fevp
0uMP7IZNms1AA7GPQUThMWbYiEYIhBKcT0/nwYrBq0Ogv79K1tta04EHTrXgcAp/
OJgBhz9N58aewd4yZBm2coeaDGvcGRAc9e72ObFQ/TME/Io7LZ5qXDWzDafI8LA8
JQmSz0L+/G+LPTWg7kPOpJT7WSkRb9T8w5QgZRJuvvhErHM83kO3ELTH+SoEI53p
4ENVwfNNEpOpnpOOSKQobtIw56CsQFrhac0sQlOjek/muVluxjiEmc0fszk2WLSn
qryiMyzaI5DWBDjYKXA1tp2h/ygbkYdFYRbAEqwtLxT2wMfWPQI5OkhTa9tZqD0H
nQIDAQAB
-----END PUBLIC KEY-----

Network-based IOCs:
97.15.12.xxx:6892 - UDP
91.239.24.xxx: 6892 - UDP
xxx.12.15.97: 6892 - UDP
xxx.24.239.91: 6892 - UDP


Comments