Neurevt bot analysis

2013-11-04

Zhongchun Huo

Fortinet, China
Editor: Helen Martin

Abstract

Neurevt is a relatively new HTTP bot that already has a lot of functionalities along with an extendable and flexible infrastructure. Zhongchun Huo takes a detailed look at its infrastructure, communication protocol and encryption scheme.


Neurevt (also known as Beta Bot) is an HTTP bot [1] which entered the underground market around March 2013 and which is priced relatively cheaply [2]. Though still in its testing phase, the bot already has a lot of functionalities along with an extendable and flexible infrastructure. Upon installation, the bot injects itself into almost all user processes to take over the whole system. Moreover, it utilizes a mechanism that makes use of Windows messages and the registry to coordinate those injected codes. The bot communicates with its C&C server through HTTP requests. Different parts of the communication data are encrypted (mostly with RC4) separately. In this article, we will take a detailed look at this bot’s infrastructure, communication protocol and encryption schemes. (This analysis is based on samples that were collected from March to June 2013.)

Installation/deployment

Installation process

Just like most malware, the installation of Neurevt starts with it copying itself to a system folder. The folder is selected according to the machine’s characteristics such as the version of Windows, the service pack installed, and whether the OS is 64-bit.

For example, on an x86 machine running Windows XP SP2, the chosen folder is %PROGRAM FILES%\COMMON FILES. The installer creates a sub-folder named ‘winlogon.{2227A280-3AEA-1069-A2DE-08002B30309D}’.

The first part of the folder name, ‘winlogon’, is obtained from the configuration of the bot, and the second part is a special GUID which makes the folder link to the ‘Printers and Faxes’ folder in Windows Explorer. This folder will act as the launching point each time the malware restarts. The installer then launches the new file and exits.

The newly launched copy creates a process of a system application, which also varies under different circumstances, and starts to inject. The injected data is within a continuous block of memory and has the following data layout:

  1. A copy of the whole PE image of the malware process.

  2. A block of data which contains states used by the code of the PE image in part 1.

  3. A buffer that contains the file data of the malware.

  4. Encrypted configuration data.

Layout of injected data.

Figure 1. Layout of injected data.

Since this is the first time the malware has injected something into another process, the injected content runs as an independent application. I refer to it as the ‘primary instance’ to distinguish it from other instances that are injected into other processes.

The primary instance searches for all running processes, and injects into those that fulfil the following conditions:

  1. The creator of the process is not services.exe.

  2. The user that creates the process is not NT AUTHORITY\SYSTEM.

  3. It is not one of the following system processes:

    • csrss.exe

    • smss.exe

    • lsass.exe

    • services.exe

    • spoolsv.exe

    • winlogon.exe

  4. It is not created by the current process.

This time, the injected data has the same layout as the primary instance. The only difference is in the ‘local cfg’ part – in which some data fields are modified to act differently since some components should be loaded in the primary instance only.

After injection, there should be one instance of the malware in every running user process. I refer to these as ‘assistant instances’. There is code in every assistant instance that monitors the status of the primary instance. Once, for whatever reason, the primary instance exits, the assistant instance will attempt to restart the malware from its launch point.

After the malware has finished its deployment, the primary instance will start to communicate with the C&C server. The whole process looks like a traditional virus infecting a file system, but instead of infecting files, the malware infects running processes.

Gather local information

The malware performs a system scan to gather information about the system and installed software. The gathered information will be stored in four separate flags, each of which is a single DWORD-length bit-flag.

The first flag contains information about the Windows version, installed service pack, and whether the OS is 32- or 64-bit.

The second flag contains information about the following software or vendors: .Net Framework, Java, Steam, SysInternals tools, mIRC, Hex-Rays, Immunity Inc., CodeBlocks, 7-Zip, PrestoSoft, Nmap, Perl, Visual Studio and Wireshark. It also contains information that indicates if the system:

  1. Has battery

  2. Has RDP records

  3. Has UAC enabled.

The third flag contains information about the following software or vendors: Steam, EA Origin, RuneScape, Minecraft, Blizzard, League of Legends, VMware, Skype and Visual Studio.

The fourth flag contains information about installed AV software: Symantec, AVP, AVG, Avira, ESET, McAfee, Trend Micro, Avast, Microsoft Security Client, Bitdefender, BullGuard, Rising, Arcabit, Webroot, Emsisoft, F-Secure, Panda, PC Tools Internet Security and G Data AntiVirus.

Component thread

The malware creates threads to perform different kinds of jobs, such as communicating with the C&C server, checking data consistency, managing messages passing among threads (components), or monitoring and infecting USB drives. These threads are like software components. In order to load the threads properly, the malware defines a function to create them. The following is the function’s definition:

HANDLE NewComponentThread( 
   LPVOID ThreadProc, 
   LPVOID InputBuf, 
   int SizeOfInputBuf, 
   int idx, 
   int reserved, 
   int *pThreadId, 
   int flag
   );

ThreadProc is the routine that performs a particular job, while idx is the index assigned to it by the malware. 0-0x1E and 0x21 are idx values given to those unique routines for which there should be only one running thread. 0x1F and 0x20 are for multiple instance routines. If the NewComponentThread is called with idx set to these two values, the function will assign a new idx to ThreadProc, which is the first available (unassigned) number from 0x22.

The malware maintains a list to keep track of all the threads that are created by the function. Each ThreadProc takes an entry pointed to by its idx. The entry of the list has the following structure:

typedef struct THREAD_LIST_ENTRY { 
   WORD Size;
   WORD Index;
   DWORD reserved;
   DWORD CreateFlag;
   DWORD SizeOfInputBuffer;
   DWORD InputBuffer;
   CHAR EventName1[96];
   HANDLE Event1;
   HANDLE Event2;
   HANDLE ThreadHandle;
   DWORD ThreadId;
   DWORD StartAddress;
   DWORD StubAddress;
   DWORD CurrentId;
   };

Before actually starting the new ‘component thread’, NewComponentThread adds a short code stub and a wrapper function to ThreadProc.

The code stub will be written into ntdll’s image, at a random location within the MZ header. This random location will serve as the StartAddress when NewComponentThread calls CreateThread. So, the start address of the ‘component thread’ is within the memory range of ntdll’s image. This feature is used when the malware passes messages among its threads.

Code stub

Figure 2. Code stub

The wrapper function attempts to hide the thread from debuggers and updates the thread list before and after it calls ThreadProc. It also sets a specific TLS slot with a specific value, 1234. Since the malware’s code is always running in an injected process, the API hook will be applied to monitor and manipulate the behaviour of the host process. The specific TLS slot value is used to identify the malware’s own threads for which the API hook should not be applied.

API hook

The malware applies the Ring 3 hook in two ways.

First, the malware adds a pre-operation filter for each of the following Zw* APIs:

  • ZwCreateFile

  • ZwOpenFile

  • ZwDeleteFile

  • ZwSetInformationFile

  • ZwQueryDirectoryFile

  • ZwCreateKey

  • ZwOpenKey

  • ZwSetValueKey

  • ZwOpenProcess

  • ZwTerminateProcess

  • ZwCreateThread

  • ZwCreateThreadEx

  • ZwResumeThread

  • ZwSuspendThread

  • ZwSetContextThread

  • ZwOpenThread

  • ZwUnmapViewOfSection

  • ZwDeviceIoControlFile

  • ZwQueueApcThread

The filter first checks the specified TLS slot. If its value is 1234, this means that the calling thread belongs to the malware. The filter will do nothing and let the thread call the real API. If the TLS slot is not 1234, the filter examines the object (process, thread, file, registry) on which operation will be performed, if the object belongs to the malware, then the filter will return an error status to the calling thread.

The second way it applies the Ring 3 hook is by applying an inline hook on the following two groups of APIs:

  1. getaddrinfo, GetAddrInfoW, DnsQuery_W

  2. HttpSendRequestW, PR_Write

The malware hooks APIs in group 1 to block unwanted hosts. The host list is received from the bot server. Most of the unwanted hosts are the web servers of anti-virus software vendors.

The malware hooks the APIs in group 2 only if the injected process is one of the following browser processes:

  • firefox.exe

  • iexplore.exe

  • chrome.

The malware receives a list of URLs to be monitored from the bot server. If the browser sends requests to these URLs, the malware will capture the request data and send it back to the bot server.

Handling messages

There are multiple instances of the malware running in the system. To coordinate these instances, the malware creates a thread in each as a handler of application-defined messages. Most of the messages are sent from the primary instance after it has received something from the bot server to notify other instances to update their local data, such as the blocked host list and the monitored URL list mentioned earlier.

If a malware’s thread is about to send a message, it enumerates all the running threads in the system, searching for those that have a start address within ntdll’s image. As described in the ‘Component thread’ section, all the threads created by NewComponentThread fulfil this condition. The sending thread will call PostThreadMessage to send the message to them. Among these threads, only the message handlers (in all the malware instances) have a message queue (by calling IsGuiThread) for messages that are not associated with any window (a feature of messages sent by PostThreadMessage). So the handlers will retrieve the message and response accordingly.

Before a message is sent out, the sending thread will add a pre-defined modifier to the message identifier. This modifier is calculated based on the signature string in the bot configuration and the computer name. Its value is within the range from 0 to 31. The wParam and lParam are also modified since they often carry values with specific meanings like process id or thread id.

Modify message before sending.

Figure 3. Modify message before sending.

In the handler thread, these values will be restored by a reverse calculation before the message is handled. This means that, even if the messages passing among the malware’s threads are being monitored, it’s hard to understand their meanings.

Restore the message before handling.

Figure 4. Restore the message before handling.

The messages supported by the handler thread are listed in Table 1:

uMsgOperation
0xECDUpdate the process ID of the primary instance.
0xECBUpdate the thread ID of the thread that sends the captured HTTP request back to the bot server, also update the handle of the window created by the thread. The captured data will be sent to the window by the WM_COPYDATA message.
0xEC9Perform operation (search or insert) on a pid list and a tid list. These two lists are used by hooked Zw* functions. The pids and tids in these two lists belong to the malware and will be protected.
0xEEDStore the Control flag value in the last received bot response.
0xEE9Update the local blocked host list.
0xEE7Update the local monitored URL list.
0xEC7Kill all of the malware’s threads in an inject instance.

Table 1. Messages supported by the handler thread.

Sharing data in registry

The malware stores shared data for all instances in registry values. The values will be created under the key HKCU\Software\CLSID\{random guid}\{hash of configuration signature string}. The following are important values used by the malware:

  • CS1\S02: Encrypted data that stores the last received blocked host list.

  • CS1\S03: Encrypted data that stores the last received monitored URL list.

  • CS1\S01: The last received configuration.

  • CG1\CF01: Value of the DWORD at offset 0x20 in the last received response.

  • CG1\CF02:Value of the DWORD at offset 0x24 in the last received response.

  • CG1\CF03: Value of the DWORD at offset 0x28 in the last received response.

  • CG1\BIS: Flag that indicates that the process is running on a removable disk.

  • CG1\BID: The first launch time.

  • CG1\HAL: DWORD, set to 0xEE05 after it has been installed successfully.

  • CG1\LCT: Time of last received bot response.

Bot communication

Neurevt communicates with its C&C server through HTTP. Both the request and response are encrypted with the RC4 algorithm. The communication starts as the malware on an infected machine sends its first request to the bot server. Then the communication goes on in a ‘Q & A’ manner.

Bot configuration

Neurevt has a built-in configuration. The configuration data and the decryption code are both encrypted with RC4. The malware allocates a block of memory on the heap, and decrypts and copies the decryption code into the memory. Then it creates a thread to decrypt the configuration.

The argument passed to the thread is a pointer to the following structure:

typedef struct DECRYPT_CONFIG_STRUCT {
   DWORD cbSize;
   DWORD lpConfigData;
   DWORD lpKey;
   DWORD lpGlobalData;
   DWORD lpKeyForReEncrypt;
   DWORD ImageBase;
   DWORD DecryptFunc;
   DWORD SearchFunc; // To search the PE image for config’s hash
   DWORD AllocMemory;
   DWORD ReleaseMemory;
   DWORD HashString; // To calculate the config’s hash
   DWORD GetCriticalSection;
   DWORD Win32APIList;
};

The fields between DecryptFunc and GetCriticalSection are functions that are used by the decryption function. First, the decryption thread will perform an integrity check by calculating the hash value of the key sequence and comparing it with a value that is embedded in the PE image. If the hash values are consistent, the thread allocates a block of memory and decrypts the configuration data into the memory.

lpKeyForReEncrypt is a pointer to a four-byte key sequence for re-encryption. It is generated randomly after the configuration data has been decrypted. The re-encryption also uses the RC4 algorithm. Its purpose is to protect the configuration data from being discovered in any memory dump. The re-encryption is done by the main thread after the decryption thread exits. Before the decryption thread exits, it stores the memory pointer and the re-encryption key in the memory block that is given by lpGlobalData.

Any access to the configuration data afterwards is carried out using the following steps:

  1. Allocate a block of memory and copy the re encrypted data into it.

  2. Decrypt and get the desired data.

  3. Re-encrypt the data.

  4. Release the memory.

Access configuration data.

Figure 5. Access configuration data.

Steps 2 and 3 are completed in one function. So, the configuration data remains plain text in the memory for only a short period of time.

The configuration data has a 718-byte header, which contains the fields shown in Table 2.

OffsetTypeMeaning
0x0WORDSize of the configuration data, 0x2ace
0x2DWORDMagic number
0x6BYTE[32]Signature string, used for creating names, such as event, registry
0x44CHAR[104]Backup URL
0x14eWCHAR[128]Name of the startup registry
0x24eWCHAR[128]Name of the folder where the installer self-copies itself

Table 2. Fields contained in the 718-byte header.

Configuration (header).

Figure 6. Configuration (header).

There is an array at 0x2ce of the configuration data. Each entry stores information about a C&C server. Normally there will be more than three entries in one configuration. The size of the entry is 0x280 bytes. The crucial fields are shown in Table 3.

OffsetTypeMeaning
0x0WORDEntry size, 0x280
0x0eDWORDHash of the domain name
0x12WORDNumber of attempts
0x14WORDServer port
0x16DWORD(Length of domain name) xor (0xa5f0 + (index in the array))
0x1EWORDOption
0x66CHAR[256]Host
0x166CHAR[256]Path
0x26eBYTE[8]RC4 key 1, for request and response header
0x277BYTE[8]RC4 key 2, for response body

Table 3. The crucial fields.

Configuration entry.

Figure 7. Configuration entry.

Request format

Each request contains a 128-byte data block, which contains the fields shown in Table 4.

OffsetTypeMeaning
0x00BYTE[8]Not used
0x08WORDSize of the block
0x0AWORDMagic, 0xC1E5
0x0cDWORDSoftware flag 1
0x10DWORDCount of CS fields in the request
0x14DWORDUnknown
0x18DWORDDWORD read from configuration, at offset 0x30
0x20DWORDSoftware flag 2
0x24DWORDSeconds since 1970
0x28DWORDTick count
0x2cDWORDTimeZone.Bias
0x30DWORDLocale info
0x34WORDData of registry value BK32
0x36WORDReserved
0x38BYTE[16]Guid
0x48DWORDData of registry value CF01
0x4cDWORDData of registry value CF02
0x50DWORDData of registry value CF03
0x54DWORDReserved
0x58DWORDSecurity software flag
0x5cDWORDSoftware flag 3
0x60DWORDUnknown
0x64BYTE[28]Reserved

Table 4. Fields contained in the 128-byte data block.

The malware encrypts the data block with RC4. It uses a 12-byte key sequence, which is a combination of two parts. The first is an eight-byte sequence obtained from the chosen entry of the configuration data, at offset 0x26e. The second part is a random sequence obtained by calling CryptGenRandom. The length of the sequence is within a range from eight to 27 bytes. This part of the key and encrypted data block will be inserted into the query string.

First part of query string

Figure 8. First part of query string

If it is the first request sent to the bot servers, it will also contain the following three CS fields:

  1. A full file path of installed malware

  2. The username in NameSamCompatible format

  3. The name of the default web browser.

Data of CS fields.

Figure 9. Data of CS fields.

These strings are encrypted separately with a loop-XOR algorithm and concatenated into a URL query string.

Extra fields for the first request.

Figure 10. Extra fields for the first request.

Bot response header format

The bot response contains a 0x5c-byte header and a body which consists of at most eight streams (only four streams are actually used). Both the header and the body are encrypted with RC4 and they will be decrypted separately. The first four bytes in the header will be appended to the eight-byte sequence in the configuration to form a 12-byte key sequence for decrypting the header. The following four bytes in the header and another eight-byte sequence in the configuration are concatenated to form another 12-byte key sequence for the response body.

The response header has the structure shown in Table 5.

OffsetTypeMeaning
0x00BYTE[4]Key1
0x04BYTE[4]Key2
0x08DWORDSize of the header, 0x5C
0x0CDWORDResponse status. 0 if error occurs
0x10DWORDControls the sleeping time during the communication
0x14BYTE[8]Reserved
0x1CDWORDControl flag
0x20DWORDTo be saved into registry value CG1\CF01
0x24DWORDTo be saved into registry value CG1\CF02
0x28DWORDTo be saved into registry value CG1\CF03
0x2CBYTE[16]Reserved
0x3CDWORD[8]Length array

Table 5. Structure of response header.

The Control flag in the response header is a bit-flag which triggers different behaviours of the malware, such as invoking routines that disable security software or fake pop up warning windows to trick the user into giving permission for the malware to bypass the UAC.

Fields from 0x20 to 0x28 are three DWORDs which will be stored in the registry values. They will be copied to the bot server in the next request sent by the malware.

The length array at 0x3C has eight entries – each denotes the length of the corresponding stream in the response body.

Bot response body

According to the response header format, there should be eight streams in the body, but the malware only has handling routines for the first four streams.

The first stream contains bot commands sent back by the bot server. The first word of the stream is the count of the commands in the stream. Each command is stored as a null terminated string preceded by a data block. The size of the data block is 22 bytes. It is not used in any of the malware’s code.

First stream (commands).

Figure 11. First stream (commands).

The malware identifies the command keyword by hash value. It has a list of handling routines. Each entry in the list has the following structure:

typedef BotCmdEntry {
   DWORD dwHash;
   PVOID lpfnCmdProc;
   DWORD KeywordLength;
}
Handling routine list.

Figure 12. Handling routine list.

The second stream contains a list of hosts that will be blocked. The list is used in the following hooked functions:

  • DnsQuery_W

  • GetAddrInfoW

  • getaddrinfo

Second entry (blocked hosts).

Figure 13. Second entry (blocked hosts).

The third stream contains a list of URLs for which the malware will monitor the HTTP requests sent. The list will be used in the following hooked APIs:

  • HttpSendRequestW

  • PR_Write

Third entry (monitored URLs).

Figure 14. Third entry (monitored URLs).

The fourth stream in the response body contains data which could be used to generate a new configuration. The stream is in a format similar to that of an INI file. The malware compiles the stream into a binary data block which is organized in a structure described in the configuration section.

Fourth entry (new configuration).

Figure 15. Fourth entry (new configuration).

Spam through Skype

The malware uses Skype to spread any text material received from the bot server. There are two bot commands that will invoke the spreading job.

Bot commands involving Skype.

Figure 16. Bot commands involving Skype.

The bot server sends the command along with a URL parameter pointing to a text file. Each line of the text file contains a locale-message pair which is delimited by a semicolon:

{locale name};{spam content}

The malware chooses one line according to the locale of the system’s default language and sends the message in the line to all the Skype contacts except ‘echo123’, which is the name of Skype’s echo service.

To send the message, the malware creates a new process of itself with the command line parameters set to ‘/ssp {URL sent by bot server}’. The new process sets up a communication between itself and the Skype client with the Skype API. Then it starts to send Skype commands.

The first command sent is ‘SEARCH FRIENDS’, which retrieves all the contacts of the logged-in user. For each contact, a ‘MESSAGE’ command will be sent to the Skype client to generate an IM message to send the chosen spam content.

Bypassing UAC

On a UAC-enabled system, if the malware needs to elevate its privilege, it doesn’t play some trick to avoid prompting the user or disable the UAC once and for all. Instead, it will directly ‘ask’ the user for approval.

The malware creates a process of ‘Cmd.exe’ and puts the malware’s file path in the command line argument. When the prompt window pops up, it shows that ‘Cmd.exe’, which is a Windows application, is asking for privilege elevation. Careless users tend to approve the request. Then a new process of the malware will be created by ‘Cmd.exe’ and it will inherit the system privileges of ‘Cmd.exe’.

Posing as ‘Cmd.exe’.

Figure 17. Posing as ‘Cmd.exe’.

Clicking ‘show detail’ reveals the trick (Figure 18).

Hidden in detail information.

Figure 18. Hidden in detail information.

Under some circumstances, the malware will give a fake warning about system corruption and ask the user to approve a ‘restoration utility’ to gain a high privilege (Figure 19).

Fake warning (1).

Figure 19. Fake warning (1).

If the user denies it, the malware will continue to pop up warnings and re-prompt the user several times.

Fake warning (2).

Figure 20. Fake warning (2).

The malware prepares warnings in the following languages: Russian, Portuguese, German, French, Dutch, Arabic, Hindi, Persian, simplified Chinese, Turkish, Indonesian, Italian, Spanish, Polish, Japanese and Vietnamese.

It will choose one of them according to the system’s default language locale to avoid language inconsistency raising the user’s suspicion.

Fake messages in different languages.

Figure 21. Fake messages in different languages.

Conclusion

As this analysis shows, the communication protocol has reserved enough space for new functionalities to be added in the future. There are unused fields in both the request and response structure and there are four streams in the response data that don’t have any code to handle. Though Neurevt has just entered the market, the bot’s author is likely to develop it rapidly – we will undoubtedly see new features of Neurevt soon.

Bibliography

[1] Beta Bot – Coded in C++ – Incredibly Advanced HTTP Bot. http://www.sinister.ly/showthread.php?tid=5234.

twitter.png
fb.png
linkedin.png
hackernews.png
reddit.png

 

Latest articles:

VB2019 paper: The push from fiction for increased surveillance, and its impact on privacy

Privacy is a major source of concern for people living in the digital age. Whether they are right in their suspicions or not, people have even started questioning whether their smart light bulbs are spying on them. The only certainty we have in all…

VB2019 paper: Oops! It happened again!

This paper will take you on a scenic tour spanning three decades of malware, three decades of digital ecosystems and three decades of history repeating itself. When will we ever learn?

VB2019 paper: A vine climbing over the Great Firewall: a long‑term attack against China

This paper discloses details of a little-known APT group, PoisonVine, and its long history of cyberespionage activities lasting 11 years. The group is keen on Chinese entities and aims to harvest political and military intelligence. The paper…

VB2019 paper: Fantastic Information and Where to Find it: A guidebook to open-source OT reconnaissance

This paper explains some of the main motivations that drive threat actors to perform reconnaissance on industrial networks. It then illustrates some of the tactics that have been used by threat actors to extract OT documentation from corporate IT…

VB2019 paper: Different ways to cook a crab: GandCrab Ransomware-as-a-Service (RaaS) analysed in depth

This paper examines the GandCrab ransomware, the biggest Ransomware-as-a-Service (RaaS) threat seen in 2018 and the first half of 2019. Through technical analysis, several mistakes and indicators were discovered in the malware. Armed with these…


Bulletin Archive

We have placed cookies on your device in order to improve the functionality of this site, as outlined in our cookies policy. However, you may delete and block all cookies from this site and your use of the site will be unaffected. By continuing to browse this site, you are agreeing to Virus Bulletin's use of data as outlined in our privacy policy.