The OrangeWorm group was named and described by the Symantec Company in different blog entries [1] [2]. We would highlight from these entries that it is a group that has been operational since 2015 and is focused on attacking the health, pharmaceutical, technological, manufacturing and logistics sectors. The sector most affected is healthcare as described by Symantec.

Based on this information, Lab52 has carried out an in-depth study of the Kwampirs tool (OrangeWorm’s main tool) used by this group.

Next, the RAT (Remote Administration Tool) in Dll format and the main binary or orchestrator of the infection will be analyzed.

Technical analysis of Kwampirs Dropper

Within its arsenal, OrangeWorm has a RAT in DLL format whose execution and lateral movement is carried out by an executable together with the one that composes the threat known as Kwampirs.

Regarding the executable, which we will call “Kwampirs Dropper” initially highlight its resources, among which are two images with corrupt sections. One of which consists of the DLL with RAT capabilities encrypted with an XOR key that in each execution extracts, decrypts and executes:

This threat has a first execution block, in charge of decrypting all the text strings that it will use and which are encrypted in its “.data” section with a relatively obfuscated XOR algorithm in order to make detection and decryption difficult. After deciphering its strings, it extracts the creation and modification dates from User32.dll and collects information about the operating system it is on. From this point, its logic can be divided into 4 different paths, depending on the number of parameters, which provide different functionalities for each stage of infection of the threat.

In order to provide the greatest clarity to this report, the order of description of the 4 possible ways of execution of the Kwampirs dropper will follow that of an infection of this threat, instead of the number of parameters incrementally:

Execution with a parameter

The logic that contains the section of code that is executed when it receives a single parameter, is that of a hypothetical installation of the threat, manually, or through a dropper.

It should be noted that this section is completely dependent on having administrator privileges, and in case of not having them, in many points of the execution jumps directly to the end of the logic, thus ending its execution.

First, check the existence of the file “C:\Windows\inf\IE11.PNF”, its size (66Bytes) and if it has enough privileges to access it.
If it detects that it already exists (which would indicate that the computer is already infected) or that it does not have enough privileges (which would prevent it from performing the rest of the logic) it ends the execution. If it does not exist and has sufficient privileges, it creates the persistence service.

This service generates it with a hardcoded name and data in the strings that it has decrypted at the beginning of its execution, and emphasizes that it points to an executable with the name it has at that moment, but in %System32% even though it has not been observed that it copies itself to that route at any time. This implies that along with being run with administrator privileges, it also requires having been installed on that route by other means.

After creating the service, it starts it, this time without any parameter, which gives way to another execution path within its logic.
Finally, it creates the file called ie11.PNF in which it writes 66 random bytes:

In the previous capture, you can see how it creates a buffer of 66Bytes, which it fills with random bytes, and passes it as a parameter to a function that we have called “CreateFileWith2tmp” along with a string, which in this case contains “C:\Windows\inf\ie11.PNF”.

The function “CreateFileWith2tmp” uses it constantly for the creation of each one of the files related to this threat, and is in charge of generating two temporary files, in one it stores the first Byte of the buffer it receives as the second parameter, in the second file it stores the rest of the buffer, after which, it executes the following command to concatenate the content of both, and store it in a new file with the name that it has received as the third parameter.

After generating this file, it finishes its execution, having started another instance of its own, as a service, and without parameters.

Execution without parameters

When the threat starts without parameters, after its first string decryption block and collection of system information, it makes a call to the Microsoft API “StartServiceCtrlDispatcherW” responsible for initiating the logic of a Windows service, after which it ends. Therefore, if it is not started as a service, it is not able to perform any action.

If it is loaded as a service, after a first execution of its binary with a parameter, for example, the API “StartServiceCtrlDispatcherW” passes the execution flow of the application to a function of the binary.

This function consists in a first verification of the existence and capacity of access to the file “C:\Windows\inf\mtmndkb32.PNF” if it finds a recent and accessible version of this one, it continues its normal execution, in case of not finding it or having problems of access to it, it goes through the processes in search of the copies of itself that it generates to run with 2 and 3 parameters, and in search of its modules to finish these processes and later, to eliminate these executables, as a cleanup.

Regardless of whether it finds the PNF file or not, it enters an infinite “while (! 0)” loop, which is in charge of keeping its module in DLL format running and maintaining a copy of itself, running with two parameters, which is in charge of the lateral movement by SMB of the threat.

The infinite loop, first, looks for instances of its module in DLL format in execution, in case of not finding it, it calls a function that takes charge of extracting from its resources the image mentioned at the beginning of the report, trimming the corrupt section, decrypting it with an XOR key of 16Bytes, using the following algorithm:

and store the result in System32 with one of the following names with extension “.dll”:

Once you have the module on disk, run it through Microsoft executable “rundll32.exe” passing the following parameters:

It then calls a function whose sole purpose is to call a one-minute “Sleep” 20 times, causing his execution to pause for a period of 20 minutes.

After 20 minutes, it makes a call to a function that if it does not find an instance of itself running with 2 parameters, it makes a copy of its own binary with one of the following names:

And it executes it with two parameters using the Microsoft API CreateProcessAsUserW, which allows it to add the token of the current user as the creator of the process, so that the process is executed in its session:

After this, it performs a Sleep with a random value between 1 and 3 minutes, and repeats the same execution flow, thus ensuring that both its module in DLL format and its replica running with two parameters are kept running.

At this point, we are running the process of the main Kwampirs dropper, loaded as System by the persistence service, an instance of rundll32, also as System generated by the process itself without parameters, and a second instance of the executable, this time with the credentials of the user who has logged in, thanks to the use of the “CreateProcessAsUserW” API for its creation:

Execution with 2 parameters

When the threat is executed with two parameters, after its first string decryption block and collection of system information, it goes directly to a function in charge of scanning private IPs, which it tries to access by SMB in order to check its access and infection capacity.

To do this, it first generates a Thread, which through the Microsoft API “GetTcpTable” obtains the list of IPv4 connections of the system, from which it filters all those that are through ports 445 and 138, so it is able to isolate those related to SMB traffic, afterwards it tries to infect these IPs directly.

To make sure it does not miss any computer to which the user has access, but which is not found on the table, the main thread of the threat scans the entire subnet of the computer, trying to infect all its possible IP addresses.

When the main Thread finishes scanning the computer’s subnet. It enters a last zone of code, which generates random private “/ 24” subnets and scans them completely, in order to try to access subnets different from that of the infected computer, but accessible by it.

Each of the IP addresses generated by these three subnet scan approaches is passed to a function that attempts to infect them by trying to access any of the following units via SMB:

  • ADMIN$

To do this, it makes a call to the “CreateFile” API, passing as the file path the IP address to be infected with the following path “[IP]\ ADMIN $ \ system32 \ csrss.exe” replacing the first element after the IP address for each of the strings of the previous list, generating the following network traffic:

If it gets access to this file on any computer, it checks the existence of ie11.PNF, to see if it is already infected, otherwise it creates a new one on that computer and gives the date and time extracted from User32.dll :

If it is able to create that file, it tries to copy itself, for which it chooses some of the hardcoded names it has in its strings:

  • wmiapsrvce.exe
  • wmiapsvrce.exe
  • wmiapsvre.exe
  • wmiapvsre.exe
  • wmiaprvse.exe
  • wmiapsrve.exe
  • wmiapsrvcx.exe

And it generates a copy of itself with that name, on the remote computer through SMB:

Each time it is able to create both ie11.PNF and the Kwampirs executable, it calls a function that, depending on the SMB scanning routine used to generate it, passes a number to it as a parameter. If it has reached this IP from the scanning logic of the system subnet, it passes it a 0, if it has done it through the scanning routine of random private networks, it passes a 1, if it has reached this address to through the thread, it passes a 2.

This function generates a string like the following:
“Lucas-PC\Lucas\\0\Mon Dec 03 17:38:27 2018”

The string consists of the user and domain with which the other system has been infected, the IP address of the infected victim computer, the number that it has received as a parameter and that identifies the SMB scanning algorithm that detected the victim, and the date and time of infection. This string encrypts it with an XOR algorithm using a 203-byte hardcoded key and adds it to a temporary file called “Lb978YTy.tmp”

Finally, it creates a new copy of itself in System32 of the local computer, and executes it this time with 3 parameters, to which it passes, firstly the IP address of the computer it has just infected, and then two more parameters, similar to those it has received in its execution.

Execution with 3 parameters

This last branch of execution of the Kwampirs dropper, is in charge of generating persistence in remote computers infected by its replica executed with two parameters, and is also in charge of the execution of this persistence, which corresponds to the service called “WmiApSrvEx”.

To do this, it first extracts the last character from its second and third parameters, and passes it from “char” to “int”. The second parameter, can be a value between 0 and 3, (if it is something different, its execution ends). This value corresponds to the remote directory to which it has been able to access its replica of two parameters, thus obtaining the accessible remote path:

  • 0 = ADMIN$
  • 1 = C$\WINDOWS
  • 2 = D$\WINDOWS
  • 3 = E$\WINDOWS

The third parameter, can be a number between 0 and 6, and corresponds to the name that has put the copy of itself in the remote computer, as follows:

  • 0 = wmiapsrvce.exe
  • 1 = wmiapsvrce.exe
  • 2 = wmiapsvre.exe
  • 3 = wmiapvsre.exe
  • 4 = wmiaprvse.exe
  • 5 = wmiapsrve.exe
  • 6 = wmiapsrvcx.exe

With this, and the address of the remote computer that has as its first parameter, tries to create and start the service “WmiApSrvEx” on the remote computer, generating traffic like the following:

Depending on whether it is capable of generating and executing the service or not, it makes a call to the registration function in the “Lb978YTy.tmp” log of infected remote computers, but this time, the parameter can be a 3 if everything went well, or a 4 if it has not been able to generate or initiate persistence. Thus leaving in the “.tmp” file registry a record of the computers to which he has had access (logs with 0.1 or 2) and if it has been able to infect them or not with (3 or 4) logs.

If it is not able to infect the computer, it tries to eliminate the remote ie11.PNF file, obtaining in this way for it to try again to infect said computer in a future execution.

Technical analysis of Kwampirs RAT

OrangeWorm within its arsenal has a RAT in Dll format (from now on Kwampirs) that is executed by “Kwampirs Dropper”. This device has the following static characteristics:

In all the samples analyzed the ControlTrace () function is exported. This has not changed since the Symantec report. Kwampirs RAT depending on the number of parameters will have a different behavior. The possibilities implemented on this occasion are two, when three parameters and when four parameters are passed to the function.

The analysis will describe the behavior of Kwampirs RAT in each of the two existing execution branches:

Execution with three parameters

The actions that Kwampirs RAT performs once it starts with three parameters are:

  1. The first thing it does is to decipher the compromise indicators (IOCs from now on). Once deciphered we will see them reflected in memory:In the image above you can see the memory segment with all the URIs that the malware will try in order to communicate. To decipher the IOCs the malware uses the following logic:
  2. The next step is to obtain the MACTimes of the user32.dll Dll. This group modifies the times of certain files that it creates on the disk and fixes the times of the user32.dll Dll, as already mentioned “Kwampirs Dropper”. This is a measure to hinder the subsequent forensic analysis. In the example below we can see the file 3.tmp (random name) on the left, created by Kwampirs to store the identifiers of the handlers of the Named Pipes that it has created, and on the right the user32.dll dll of the system. If we look carefully, we see how the modification time coincides exactly:
  3. In the mtmndkb32.PNF file, a generated value is saved from the system date at the time of execution. In each execution (Kwampirs Dropper as Kwampirs RAT) it checks the exact date the file was created and if not enough time has passed since the file was created, it does not run again. This is already described by Symantec in its report and the “current” samples have not changed their behavior.
  4. In the event that Kwampirs RAT is downloaded, a module interacts with the mkdiawb3.PNF file before entering the network communication execution flow. This file stores hashes in md5 of the modules. An example of the file with the hash of the encrypted and unencrypted module can be seen below:This group calculates the hash on the file (module) after encrypting it and coding it in base64.
    If we do a hash to the downloaded module we will see how it matches with what is stored:

  5. Kwampirs RAT creates different files with extension “.TMP” in the temporary directory of the user and in the case of being executed with a user with administrator privileges renames the files and places it in the directory C:\windows\inf with extension PNF (of which we have spoken previously). To copy them, it uses the cmd.exe command as shown below in an execution:
  6. After moving the files, it launches a thread that contacts the command and control server (C2 from now on). This thread invokes the StartProcess () function. This thread receives modules from C2 with the hash of the signed module and checks it before executing them. During this thread, a temporary file is generated where information of the computer is stored and then used in the requests. This file is called digirps.PNF. Once the digirps.PNF file is decrypted you can see how it stores computer information such as the MAC Address:

    Again to decrypt the file we use the same algorithm but with a different key and the MAC of the computer where the sample was executed is indeed obtained. The analysis carried out has not shown that a first interaction with this file adds more useful information than the MAC Address.

    As already mentioned, network communications to C2 are performed in this function. Until it receives a “good” response, Kwampirs RAT sends the following type of packets (in this case you can see how a C2 sends a successful response):

    We see how the C2 has returned a code {XXX}: hash_md5_modulo. After receiving the module hash, the C2 sends it to the next GET:

    In this case what it has returned is a module (Dll as well) that it injects in memory and launches as a new thread of execution (these modules are not dumped to disk). In this case, the module allows executing commands in the operating system. In a first iteration the module executes commands to gather information:

    The module that Kwampirs RAT has downloaded is mapped into memory as follows:

    After loading it, a thread starts invoking a function named CF. For this sample it is necessary that all the modules come with the function CF () to start the logic. The name of the DLL once mapped on this occasion is cmdDLL.dll which confirms that it is a module ready to execute commands.

    Next you can see the module’s loop that reads the .data section with the commands and that will be launched with cmd.exe:

    And the following screenshot shows the part of the network that sends the POST request of the module whose capture of the network traffic was seen before:

  7. After exiting the thread, the Sleep () function is executed with a random time and returns to point 5 to repeat the process.

When the Kwampirs RAT is executed with three parameters, the API that makes the HTTP request sometimes returns error 12029 (it could not establish the HTTP connection). In this case Kwampirs RAT will try to boot the malware with the CreateProcessAsUser () function as follows:

It looks like there are two instances of Kwampirs, but one with the user SYSTEM and another with the user Lucas. This makes sense since there are occasions where the user SYSTEM cannot exit through the proxy of the organization and with this technique aims to take the user who may have configured the proxy and thus exit. The user instance tries again to launch the HTTP requests.

Execution with four parameters

Kwampirs RAT when booted with 4 parameters is used to communicate through Named Pipes with another instance of Kwampirs RAT.

The last parameter is the one that will give the name to the file that will store the handles of the named pipes created by that same instance. When booting with this amount of parameters, it calls the CreatePipe () function twice to create two Named Pipes. The pipe handlers (in decimal) are stored in a file created in C:\Windows\Temp:

  • 232 = E8
  • 228 = E4

The handles of the process show that e8 and e4 are File handles:

This mode of operation, as seen during the analysis, is used to communicate the Kwampirs RAT process started as SYSTEM (starting with the service) with the process started as the user owner of the current session of the machine.

In the previous screenshot you can see how the process rundll32.exe (starting with SYSTEM, in this case it would be the master) that could not go to the internet is about to write in a pipe to send the data to the process that has been created with the CreateProcessAsUser () function. This data as you can see in the image is a numerical value and a URI. It is seen in the image how the handler where you write WriteFile () is 0x240 (it is seen at the top of the stack) that if we open the handles of the rundll32 master process we see that it is a Named Pipe:

If the handles of the rundll32 master process are opened with a tool like ProcessHacker, it will be seen how it has an open handle on the rundll32 process, created with the user without privileges (from now on rundll32 slave):

Another similar situation that occurs during execution to the previous one is when the master rundll32.exe opens the explorer.exe process. This is done with the OpenProcess () api and then OpenProcessToken () in order to obtain the token from the explorer.exe process (normally the owner of this process is the authenticated user and is the one most likely to have the configured proxy):

The following is a description of the entire sequence of actions carried out for the rundll32 master process to send information to the rundll32 slave after having seen some peculiarities previously. The following image shows the master process rundll32.exe that just opened the slave process with the OpenProcess and will open a temporary file with wfopen:

The temporary file contains the identifiers of the handles created in the rundll32 SLAVE process:

In memory of the master process we will find those handles in their hexadecimal value:

Once these handles are located, the master intends to duplicate them in order to obtain access to those handles in their process and that correspond to those of the slave process to communicate with each other:

In this execution, the value of lpTargetHandle was 0x290 and it is linked (or duplicated) with one of the rundll32.exe slave processes that it just read from the temporary file.

Summing up the operation, the master rundll32.exe opens the slave process. Then it reads the temporary one where the handles are (in decimal) of type pipe that the slave has created. The master makes a duplicate handle of the two pipes of the slave in its process and thus pass all the information through these pipes. A situation where this logic is used is when the master process initiated by the service cannot navigate. In this case, it creates the slave with the token of the user who owns the explorer.exe and tries to navigate with the URIs provided by the master due to the pipes created.


Compromise indicators
































Hashes analyzed