In this blog post we will cover a recent version of the multi-purpose Neutrino Bot (AKA Kasidet) which ironically was distributed by an exploit kit of the same name. Earlier in January this year, we had described Neutrino Bot that came via spam so we won’t go over those details again, but instead will focus on an interesting loader.
Anti VM detection is complemented by multiple layers hiding the actual core which made extraction of the final payload a bit of challenge.
Once the initial check has passed, the next step is to launch a specially crafted Flash file containing a bunch of exploits for Internet Explorer and the Flash Player (similar to what was described here). The final step is the download and execution of the RC4 encoded payload via wscript.exe to bypass proxies.
The overall infection flow is summarized in the diagram below (click to enlarge):
A script from Maciej Kotowicz was used to extract artifacts from the Flash file.
- b2be7836cd3edf838ca9c409ab92b36d – original sample (dropped by the EK)
The sample was well protected against being deployed in a controlled environment. When it detects that it is being run in a VM/sandbox it just deletes itself:
If the environment passed the checks, it drops its copy into: %APPDATA%/Y1ViUVZZXQxx/<random_name>.exe (during tests we observed the following names: abgrcnq.exe, uu.exe):
The folder and the sample are hidden.
Persistence is achieved via the Task Scheduler:
The malware adds and modifies several registry keys. It adds some basic settings, including the installation date:
It modifies some keys in order to remain hidden in the system. Hidden/SuperHidden features allows its dropped copy to remain unnoticed by the user. It disables viewing such files by modifying the following registry keys:
It also adds itself into the firewall’s whitelist with this command:
cmd.exe " /a /c netsh advfirewall firewall add rule name="Y1ViUVZZXQxx" dir=in action=allow program=[full_executable_path]
Similarly, path to the malware is added to Windows Defender’s exclusions:
It disables reporting incidents to Microsoft’s cloud service (SpyNet):
It modifies settings of terminal services, setting MaxDisconnectionTime and MaxIdleTime to 0. Modified keys:
HKLMSOFTWAREPoliciesMicrosoftWindows NTTerminal ServicesMaxDisconnectionTime HKLMSOFTWAREPoliciesMicrosoftWindows NTTerminal ServicesMaxIdleTime
If the full installation process went successfully, it finally loads the malicious core, and we can see a traffic typical for the Neutrino Bot. You can see below the beacon “enter” and the response “success”, encoded in base64. The response is sent as a comment in the retrieved blank html page, in order to avoid being noticed:
In the next request the bot sends information about itself, and in response the CnC gives it commands to be executed. Requests and responses are also base64 encoded. Example after decoding:
The first command was to take a screenshot, and indeed, soon after we can see the bot sending a screenshot in JPG format:
From the sent version number we can conclude, that the version of the bot is 5.2 (similarly to this campaign).
The first layer is a stub of a crypter, that overwrites the initial PE in memory by the image of the loader. Unpacking it is demonstrated in this video: https://www.youtube.com/watch?v=m_xh33M_CRo.
The second layer is a loader that prevents from running the core bot in a controlled environment (i.e. on VM or under a debugger). This element is probably new (we didn’t observe it so far in previous campaigns of Neturino Bot, i.e. the one described here). We found the loader very effective in its protective task. Most of the sandboxes and test VMs used during tests failed to provide any useful results.
The final payload had features typical for Neutrino Bot family.
The loader code shows that it is an integral part of the full Neutrino Bot package – not yet another layer added by an independent crypter. Both, the payload and the loader are written in C++, use similar functions and contain overlapping strings. It will be demonstrated in details later in this article. They both also have very close compilation timestamps: payload: 2017-02-16 17:15:43, loader: 2017-02-16 17:15:52.
A patched version of the loader, with environment checks disabled can be viewed here.
The code inside contains some level of obfuscation. A few strings are visible:
- Directory name
- Some functions
- Registry keys related with Windows Security features that are going to be disabled
- Strings used to add a new scheduled task.
However, that is not all. Most of the strings are decrypted at runtime. Here is an example of loading an encrypted string:
First, the obfuscated string is written to the dynamically loaded memory by a dedicated function. Then, it is decrypted using a simple, XOR-based algorithm:
def decode(data): maxlen = len(data) decoded = bytearray() for i in range(0, maxlen): dec = data[i] ^ 1 decoded.append(dec) return decoded
The same string after decryption:
Most of the API calls are also dynamically resolved. Example:
Tracing API calls helps to understand the programs’s functionality. For this reason, the authors of this malware file implemented some of the functions without using API calls at all. In the below example you can see the function GetLastError() implemented by reading a low-level structure: Thread Envioroment Block (TEB):
In order to prevent from being executed more than once, the loader creates a mutex with a name that is hardcoded in the binary: 1ViUVZZXQxx.
The primary task of the loader is to check the environment, in order to make sure that the execution is not being watched. But, in contrary to most of the malware, the check is not just done once. There is a dedicated thread deployed:
It runs checks in a never ending loop:
If at any time, the loader detects i.e. some blacklisted process being deployed, execution is terminated.
Examples of the checks performed:
1. Enumerates through the list of the running processes (using dynamically loaded functions CreateToolhelp32Snapshot – Process32First– Process32Next). Calculates checksum from each retrieved process name and compares it with the built-in blacklist:
The blacklisted checksums:
Implementation of the function searching blacklisted processes – as we can see, every function is loaded dynamically with the help of a corresponding checksum:
2. Searches blacklisted modules within the current process (using dynamically loaded functions CreateToolhelp32Snapshot – Module32First– Module32Next). Similarly, it calculates the checksum from each retrieved process name and compares it with the built-in blacklist.
Checksum calculation algorithm (implementation):
The blacklisted checksums:
3, Checking if the process is under the debugger, using: IsDebuggerPresent, CheckRemoteDebuggerPresent
4. Detecting single-stepping with the help of time measurement, using GetTickCount – Sleep – GetTickCount
5. Anti-VM check with the help of detecting blacklisted devices – using QueryDosDevices i.e. VBoxGuest
6. Searching and hiding blacklisted windows by their classes – using EnumWindows – GetClassName (i.e. procexpl)
The blacklisted checksums:
In another thread, the malware performs operations related to the bot installation – adding a task to the Windows Scheduler, adding exclusions to the Firewall etc.
Finally, it unpacks the final payload and runs it with the help of the Run PE method. First, it creates another instance of its own:
Then, it maps a new PE file on this place:
The loaded payload is a Neutrino Bot, with very similar features to the one that we described in a previous post. However, we can find some similar elements like in the loader, for example matching strings:
Neutrino Bot has been on the market for a few years. It is rich in features but its internal structure was never impressive. This time also, the malware authors did not make any significant improvements to the main bot’s structure. However, they added one more protection layer which is very scrupulous in its task of fingerprinting the environment and not allowing the bot to be discovered.