Norse Labs on the Dyre banking Trojan
Because of the infrastructure required to build Dyre, the manpower needed to execute the attacks, and the knowledge of banking systems demonstrated— the group behind Dyre is a well-funded, intelligent, and a sophisticated cybercrime organization. The group likely operates out of Eastern Europe, possibly in the Ukraine and/or Russia.
In 2014, the takedown of banking Trojans such as Gameover, Zeus, Shylock, and Ramnit created a void for cybercriminal groups. Since its first appearance in June 2014, the Dyre Trojan has effectively filled this void by targeting corporate and private banking accounts in a succession of phishing campaigns across the globe, including the Royal Bank of Scotland, Citigroup, JPMorgan Chase, and Bank of America. This makes Dyre, also known as Dyreza, Dyranges, or Battdil, one of the more potent banking trojans currently in operation. 1,2
Because of the infrastructure required to build Dyre, the manpower needed to execute the attacks, and the knowledge of banking systems demonstrated— the group behind Dyre is a well-funded, intelligent, and a sophisticated cybercrime organization. The group likely operates out of Eastern Europe, possibly in the Ukraine and/or Russia. This assessment is based on several factors: the attackers follow a Monday to Friday five-day work week; the group appears to operate in the UTC +2 or UTC +3 time zones; and over 80 percent of all Dyre servers come through Russian and Ukrainian IP addresses. Multiple teams could also be using the Dyre Trojan at the same time, attacking from different geographic locations. The attackers have primarily targeted banks in English-speaking countries, focusing on the US and UK. 1,3,4
The main purpose of Dyre is to steal banking credentials such as user name, password, and PIN number through spam/phishing emails that mimic the official banking sites. The stolen information is sent to either a predetermined email address, to drop sites, or to a URL via HTTP post. In reverse-engineering the sample that we are describing herein, Norse has also identified encrypted communications on TCP/4443. Some versions of Dyre download a worm that is capable of composing email messages in Microsoft Outlook with the “Upatre” malware attached, which is then used to send thousands of spam emails in order to spread. 1,5
Dyre has ability to steal login credentials by browser hooking and bypassing SSL, and uses a man-in-the-middle (MITM) proxy server. It also has Remote Access Trojan (RAT) capabilities, complex process injections, and Distributed Denial of Service (DDoS) capabilities. Dyre has a robust command-and-control backup system that can use I2P (the Invisible Internet Project), an overlay network similar to TOR, and uses time-dependent domain generation algorithms (DGAs). In our next blog post, we’ll be presenting data from sink-holing efforts using at least one such domain. 6,7
Dyre variants are wrapped with custom downloaders, which use some of the newest packers/protectors. Norse Fusion Analysts analyzed one such sample that was extracted from our malware pipeline. In this analysis, we will be presenting the most complicated part of the Dyre lifecycle, the initial infection vector. The custom obfuscators analyzed use constant unfolding, data-encoding schemes, extraneous/dead code insertion, and pattern obfuscation techniques. The more advanced packer/protectors use virtual machine obfuscation. The downloaders, or stage one installers, then push the binaries to the computer in a variety of different ways. The hash of the sample analyzed is:
MD5: 1DFF4F80F95FD272A73F79CA3382681D.
MD5: 1DFF4F80F95FD272A73F79CA3382681D.
Environmental differences:
Windows XP and Windows 7 x64
On Windows XP and Windows 7 – 64 Bit, Dyre will install and register a system service called “Google Update Service.” Looking inside the registry entry for the service will yield the entry for ““ImagePath”. This is the image path and name of the malware executable.
Since the malware is registered as a service, it automatically executes at Windows boot. 6
Dyre uses the generic service host process (svchost.exe) for all the communications with the command-and-control (C2s) server. The communications is encrypted over SSL on TCP ports 443 or 4443.
Windows 7 x86
On Windows 7 – 32 Bit, Dyre acts a bit differently. The malware writes an autorun key entry:: HKCU\Software\Microsoft\Windows\CurrentVersion\Run, pointing to the executable.
Dyre injects itself into Explorer.exe in order to communicate with the C2 server.
While analyzing stage one the (download/Installer). Norse ran into advanced polymorphism that swaps groups of instructions, calls to extraneous routines, multiple conditional jumps, and other calls into various sections of obfuscated code.
Opening the sample in IDA Pro we see:
Looking at the first two calls “Sleep” and “auxSetVolume()”. Sleep’s argument is for ten milliseconds. auxSetVolume is then called with two parameters which are both zero.
Looking at the header files, “mmsystem.h” and “mmsyscom.h” we see the return values are:
mmsyscom.h:
mmsystem.h:
The return value for “auxSetVolume()” is MMSYSERR_BADDEVICEID (device ID out of range).
Being that the return value is two (2) the code will not jump. So, we will enter the function 00401000. The function 00401000 is the beginning of the custom packer/protector. Starting at the beginning of the function, it will setup 624 bytes on the stack for local variables.
Qmemcpy is not in the windows SDK so the debugger only shows inline assembly for this function.
What we see inside IDA Pro:
What we see inside Ollydbg:
Qmemcpy copies a 25 byte string: “7HEvytGstrror……….”
The code then sets up local stack variables with the encoded APIs and modules like kernel32.dll. They’re stored in the “dwords_*******” below. We also see VirtualAlloc is used as one of the parameters and setup to be called by sub_40145D.
At this step, we dumped the buffer and reanalyzed it inside IDA Pro to analyze the graph below.
The function pointer at the end will be called. We will drop into another routine that grabs the encrypted buffer and decrypts it. Allowing us to dump the file:
Next would be the “Get File” routine:
It then sleeps for ten milliseconds and calls auxSetVolume() with two parameters, which are both zero.
Looking at the header file, “Mmsystem.h,” we see the return values are:
#define MMSYSERROR_BASE 0
The return value is MMSYSERR_BADDEVICEID (device ID out of range).
Being that the return value is two (2) the code will not jump into the function 00401000.
The function 00401000 is the beginning of the custom packer/protector. Starting at the beginning of the function, it will setup 624 bytes on the stack for local variables.
Qmemcpy is not in the windows SDK so the debugger only shows assembly for this function.
It copies a 25 byte string: 7HEvytGstrror……….
The code then sets up local stack variables with encoded APIs and modules like kernel32.dll.
VirtualAlloc is used as a parameter and is setup to be called by sub_40145D.
Inside sub_40145D we see:
According to MSDN ResumeThread() fails if the return value is ( -1 ).
The if statement needs (a1) to be present and ResumeThread() to not equal 75. This will satisfy the logical (&&) operator.
(a1) turns out to be VirtualAlloc ( 0, 0x1400, 0x1000, 0x40 )
The first parameter is Null; the system will determine where to allocate the region.
The second parameter is the size of the buffer.
The third parameter is the allocation type (MEM_COMMIT).
The fourth parameter is the memory protection for the region of pages to be allocated (0x40 is equal to PAGE_EXECUTE_READWRITE).
The second parameter is the size of the buffer.
The third parameter is the allocation type (MEM_COMMIT).
The fourth parameter is the memory protection for the region of pages to be allocated (0x40 is equal to PAGE_EXECUTE_READWRITE).
The empty buffer, which will be used later on:
Some dummy routines and extraneous code:
TerminateThread(), returns 0; which fails.
The SelectObject() returns the values below:
SelectObject() returns 0.
MSDN states that PulseEvent() will return zero if the function fails.
Locating the scrambled API “7HEvetGst?Eror”:
GetFileAttributesA() tries a long random string and fails:
The two while loops below will fill the newly acquired buffer above with new code, then it will call the new code with three (3) parameters.
This is what the above code looks like in IDA PRO.
It will run its polymorphic routine as seen here in green:
This is what the buffer looks like now, after the algorithm runs:
At this step, we dumped the buffer and reanalyzed it inside IDA Pro to get the graph below.
The function pointer at the end will be called and we are dropped into another routine that grabs the encrypted buffer and decrypts it, allowing us to dump the file:
This is the Get File routine:
It uses subtraction and a rotation decryption mechanism. At the end of this routine you can dump the buffer and analyze the payload.
The payload’s MD5 hash at this point is 3AE3DDDEF5F677145A59FA5B5E974760
Here is the actual payload:
The first thing we notice in the payload is a virtual machine check:
if ( *(_DWORD *)(__readfsdword(0x30) + 0x64) >= 2u )// NumberOfProcessors (PEB + 0x64) >= 2
It then locates and calls GetSystemPowerStatus and creates a 4 MB heap and sets a flag. It creates 100 SHA1 hashes based on random strings and then check the first 4 bytes of the 100th hash.
It will apply debug privileges and enumerate all the processes, searching for svchost. It will create a system SID, and store the process ID of the executable found.
Service setup is a code block that calls StartServiceCtrlDispatcher(). If we look into the MSDN description, we can read the following:
“When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher function.”
The service control manager uses this connection to send control and service start requests to the main thread of the service process.
If a service runs in its own process, the main thread of the service process should immediately call StartServiceCtrlDispatcher(). All initialization tasks are done in the service’s ServiceMain function when the service is started.
We have a Service which runs in its own process, so StartServiceCtrlDispatcher() gets immediately called. Again, if we look at MSDN:
BOOL WINAPI StartServiceCtrlDispatcher(
_In_ const SERVICE_TABLE_ENTRY *lpServiceTable
);
The function has a single pointer to the structure SERVICE_TABLE_ENTRY as a parameter. Now we look at this structure:
typedef struct _SERVICE_TABLE_ENTRY {
LPTSTR lpServiceName;
LPSERVICE_MAIN_FUNCTION lpServiceProc;
} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;
It has two pointers, one points to the name of the Service process, and the other points to the ServiceMain function. The ServiceMain description from MSDN:
“The entry point for a service. When the service control manager receives a request to start a service, it starts the service process (if it is not already running). The main thread of the service process calls the StartServiceCtrlDispatcher function with a pointer to an array of SERVICE_TABLE_ENTRY structures. Then the service control manager sends a start request to the service control dispatcher for this service process. The service control dispatcher creates a new thread to execute the ServiceMain function of the service being started.
The ServiceMain function should immediately call the RegisterServiceCtrlHandlerEx function to specify a HandlerEx function to handle control requests. Next, it should call the SetServiceStatus function to send status information to the service control manager. After these calls, the function should complete the initialization of the service. Do not attempt to start another service in the ServiceMain function.”
So the ServiceMain function is the entry point for a Service, just like WinMain() for a Windows-based application or DllMain() for a dynamic-link library (DLL). Now we follow ServiceMain in IDA Pro and end up in a bunch of random bytes. So what’s going on here? We see two function calls to RegisterServiceCtrlHandler() and SetServiceStatus() just as described by MSDN above, but IDA Pro doesn’t recognized the ServiceMain function as executable code, so here we have to convert the bytes into code manually! After doing this we can continue our analysis.
Here is ServiceMain:
The Handler:
Create_Process():
After the initialization of the service and handler, the sample will check its operational condition:
As we go into the function:
The function checks to see if the piece of malware is operating from the WINDOWS directory. If not, it will drop the exe and restart a new process. It also checks whether it should create the service.
If it passes both checks, it will check to see if there is an open mutex. If not, it will go into “Off_To_The_Wild_Blue_Yonder()” to inject into svchost.exe.
Before injecting into svchost two resources are needed: the payload and the key.
Get_Resource maps the payload into memory.
The Injection process happens in function 402DA0, which uses a method similar to Carberp.
Here is the Carberp injection process:
Source: Github 8
Using the resource file and key, we can decode the resource with this algorithm:
void substitutionCipher( unsigned char* pfile, streampos size, unsigned char* pkey )
{
int ifilesize = size;
pDecoded = new unsigned char [ ifilesize ];
for( int i = 0; i < ifilesize; ++i ){
pDecoded[ i ] = pkey[ pfile[ i ] ];
}
}
Here is the encoded resource:
And here it is decoded:
Looking into the decoded resource file, we can now see all the strings! Download here.
The Dyre Trojan emerged in 2015 to become one of the most credible and effective threats against the banking and financial services industry. The malware is backed by a skilled and resource-rich cybercrime group that has put considerable time and resources into developing a tool that can affect banks and customers worldwide.
As a result, Dyre is constantly evolving in order to evade detection, and this poses significant challenges to security professionals. The best defense against this type of threat is to educate employees about the dangers of clicking email links and attachments. As part of any comprehensive security program, which should include security awareness training, organizations may also consider proactively spear-phishing employees using real-world scenarios that culminate in a “teachable moment” to reinforce this idea.
In our next blog post, we’ll be presenting data from sink-holing efforts using DGAs (Domain Generation Algorithms) that are present in malware like Dyre to prevent C2 takedown.
References:
1 Symantec. (2015). Dyre: Emerging threat on financial fraud landscape (Version 1.0) [PDF file]. Retrieved from http://www.symantec.com/content/en/us/enterprise/media/security_response/whitepapers/dyre-emerging-threat.pdf
2 Protecting Against the Dyre Trojan: Don’t Bring a Knife to a Gunfight [Web log post]. (2014, December 8). Retrieved October 15, 2015, from https://securityintelligence.com/protecting-against-the-dyre-trojan-dont-bring-a-knife-to-a-gunfight/
3 IBM: Dyre Malware Takes Summer Holiday in Spain. Retrieved [Web log post]. (2015, July). Retrieved from http://www.globalsecuritymag.com/Limor-Kessem-Cybersecurity,20150720,54521.html
4 IBM. (April, 2015). The Dyre Wolf: Attacks on Corporate Banking Accounts. [PDF file]. Retrieved from https://portal.sec.ibm.com/mss/html/en_US/support_resources/pdf/Dyre_Wolf_MSS_Threat_Report.pdf
5 Trend Micro: A Closer Look At DYRE Malware, Part 1 Retrieved [Web log post]. (2014, October 8). Retrieved from http://blog.trendmicro.com/trendlabs-security-intelligence/a-closer-look-at-dyre-malware-part-1/
6 Dev Central: Dyer Malware Analysis Retrieved [Web log post]. (2014, November 10). Retrieved from https://devcentral.f5.com/articles/dyre-malware-analysis
7 Dell SecureWorks: Dyer Banking Trojan [Web log post]. (2014, December 17). Retrieved from http://www.secureworks.com/cyber-threat-intelligence/threats/dyre-banking-trojan/
8 GitHub:hzeroo/Carberp. [Web log post]. (2013, June 25). Retrieved from https://github.com/hzeroo/Carberp/blob/master/source%20-%20absource/pro/all%20source/RemoteCtl/hvnc2/core/svchost_inj.cpp
2 Protecting Against the Dyre Trojan: Don’t Bring a Knife to a Gunfight [Web log post]. (2014, December 8). Retrieved October 15, 2015, from https://securityintelligence.com/protecting-against-the-dyre-trojan-dont-bring-a-knife-to-a-gunfight/
3 IBM: Dyre Malware Takes Summer Holiday in Spain. Retrieved [Web log post]. (2015, July). Retrieved from http://www.globalsecuritymag.com/Limor-Kessem-Cybersecurity,20150720,54521.html
4 IBM. (April, 2015). The Dyre Wolf: Attacks on Corporate Banking Accounts. [PDF file]. Retrieved from https://portal.sec.ibm.com/mss/html/en_US/support_resources/pdf/Dyre_Wolf_MSS_Threat_Report.pdf
5 Trend Micro: A Closer Look At DYRE Malware, Part 1 Retrieved [Web log post]. (2014, October 8). Retrieved from http://blog.trendmicro.com/trendlabs-security-intelligence/a-closer-look-at-dyre-malware-part-1/
6 Dev Central: Dyer Malware Analysis Retrieved [Web log post]. (2014, November 10). Retrieved from https://devcentral.f5.com/articles/dyre-malware-analysis
7 Dell SecureWorks: Dyer Banking Trojan [Web log post]. (2014, December 17). Retrieved from http://www.secureworks.com/cyber-threat-intelligence/threats/dyre-banking-trojan/
8 GitHub:hzeroo/Carberp. [Web log post]. (2013, June 25). Retrieved from https://github.com/hzeroo/Carberp/blob/master/source%20-%20absource/pro/all%20source/RemoteCtl/hvnc2/core/svchost_inj.cpp
0 comments :
Post a Comment