Malware analysis of EKANS ransomware
1. Summary
EKANS malware is a ransomware which was first detected in December 2019 and while ransomware attacks are nothing new, EKANS had a functionality which made it stand out. In the list of processes, that it tries to terminate, there were some which are related to Industrial Control Systems (ICS).[1]
During the security incidents last month, that hit the news, about the EKANS Ransomware, I decided to look at the inner workings of the malware and share my findings with the security community. My analysis was part of a research done in our ASOC team, part of TBS
We intended to publish the results earlier, but for various reasons, this blog post was delayed quite a bit. Nevertheless I think the information is still worth publishing.
The analyzed sample was obtained from the abuse.ch project, MalwareBazaar. Although the sample is publicly available, some parts of the analysis are anonymized to prevent harming victims reputation in any way.
If you’re interested, you can check the EKANS string decrypton tool I wrote:
https://github.com/idafchev/EKANS-String-Decryptor
2. Analysis
2.1. Basic static analysis
The binary contains lots of strings referencing Go source files. The reason for this is that the EKANS malware is written in the Go programming language.
I wasn’t familiar with Go, so before proceeding with the analysis, I had to learn to program in Go, read about the specific features that the language provides and understand how they’re implemented on the assembly level.
If you’re not familiar with Go, I recommend GOing through the official tutorial A Tour of Go. I went through all exercises to get some basic understanding of the language. Then, I compiled them locally and loaded them in a disassembler in order to compare the assembly with the actual code. Several online resources and blog posts explaning low level details about the Go compiler and how to reverse Go binaries also proved really helpful.
Information about the debugging symbols in Go binaries cannot easily be stripped completely, and so the original function names can be recovered.
I used the Go Reverse Engineering Toolkit library to write a script with which to restore the symbol names.
Unfortunately, EKANS has all its non-library functions obfuscated.
Another thing that can be seen from the strings is the Go project folder, which sits under the path C:\Users\Admin3\
, meaning that the username the attackers used on their development machine was Admin3
.
Checking the entropy with Detect It Easy, we can make an assumtion that the binary is not packed.
With the help of redress we check that it was compiled with go1.10.8.
2.2. Encrypted strings
Almost all strings which are used by the program logic of EKANS are encrypted using a simple XOR cipher. Every string is encrypted using different key and has its own dedicated function which decrypts that string specifically. This means that there are as many string decryption functions as there are strings (over 2000).
Below is the disassembly of the string decryption function used by EKANS.
And here’s the implementation in python:
I wrote a string decryption tool which decrypts all the strings in the binary. It can also create an IDA IDC script in order to rename all decryption routines. The script is available at: https://github.com/idafchev/EKANS-String-Decryptor
2.3 Environmental awareness
One of the first things EKANS ransomware does is to lookup the IP address of a hardcoded domain name, which belongs to the victim. Unlike other strings, the domain name is stored in plaintext.
The resolved IP address of the domain is then compared to a hardcoded IP address. In this specific sample the IP address was a private address, possibly belonging to an internal host.
If the resolved address does not match the hardcoded one, the ransomware terminates without doing anything.
After that, EKANS checks if the host it’s executing on is a domain controller. To do this it queries information from the Win32_ComputerSytem
Windows Management Instrumentation (WMI) class, using the WQL query select DomainRole FROM Win32_ComputerSytem
.
According to the Microsoft documentation DomainRole
property can have the following values:
0 – Standalone Workstation
1 – Member Workstation
2 – Standalone Server
3 – Member Server
4 – Backup Domain Controller
5 – Primary Domain Controller
In order to check if the host is a domain controller, EKANS compares if the value of DomainRole
property is larger than 3.
If the host is a domain controller the malware does not encrypt the files. Instead it drops the ransom note and exits. If the host is not a domain controller, then it proceeds with encrypting the files and without leaving a ransom note.
It also creates a global mutex called EKANS
in order to prevent several instances of the malware to run at the same time. If another instance is already running, the string "There can be only one"
, is decrypted and execution stops. The string looks like a reference to the movie Highlander, though it might not be intentional.
2.4 Ransom note
The ransom note is dropped only on domain controllers. It’s written in the paths C:\Users\Public\Desktop\Decrypt-Your-Files.txt
and C:\Decrypt-Your-Files.txt
Interestingly it does not contain how much ransom the attackers want.
2.5 Blocking network communication
Before proceeding further, the malware blocks all inbound and outbound network communication. In order to do this, it executes the following two commands:
netsh advfirewall set allprofiles firewallpolicy blockinbound,blockoutbound
netsh advfirewall set allprofiles state on
Below you can see the strings which get decrypted and then concatenated in order to construct the commands.
The resulting command is then executed with os.exec.Command().Run()
This behaviour can also be seen with Process Monitor, during basic dynamic analysis:
2.6 Service and process termination
Once all network communication is blocked, it starts searching for specific service and process names running on the host. If a match is found it tries to terminate them.
It contains an exhaustive list of services and processes. The number of services which are searched for is over 300 and the number of processes is over 1100. Only a very small subset of those are included in this blog post. Many of those are services/processes related to anti-malware software, backup and database software, log collectors and forwarders, etc. There are also some ordinary user processes in the list, like steam.exe, MS Office applications and web browsers.
If you’re interested, the full lists of processes and services which EKANS tries to stop are avaiable below:
Decrypted process names
Decrypted service names
Services are stopped using the WinAPI functions OpenServiceW
and ControlService
, while processes are terminated using OpenProcess
and TerminateProcess
.
Subset of the services:
Sophos File Scanner Service
BackupExecAgentBrowser
MSExchangeMTA
MSSQLSERVER
avast! Antivirus
SentinelAgent
Eventlog
NtLmSsp
AdobeARMservice
MySQL80
FireEye Endpoint Agent
nxlog
SplunkForwarder
Subset of the processes:
firefox.exe
chrome.exe
excel.exe
mysqld.exe
steam.exe
avastsvc.exe
avguard.exe
fortisslvpndaemon.exe
nortonsecurity.exe
auth8021x.exe
clamscan.exe
fortifw.exe
msmpeng.exe
2.7 Deleting Volume Shadow Copies
EKANS then queries WMI using the WQL query SELECT * FROM Win32_ShadowCopy
to enumerate any existing volume shadow copies (VSC). After the VSC enumeration, it proceeds with their deletion, again using WMI.
This can be seen from the output from API Monitor during dynamic analysis.
We’re approaching the end of EKANS. The final function calls in the main function are shown below:
2.8 Encryption
Before the actual encryption, strings representing file extensions, folders and files are decrypted. These are used to check which files to encrypt and which files or folder to exclude.
Some system files and folders are excluded from encryption to prevent the system from crashing and thus interrupting the encryption process.
EKANS enumerates the logical drives and then starts walking the filesystem on each drive. Each file is checked against the above-mentioned lists with extensions, filenames and folders in order to determine whether it should be encrypted.
When the encryption starts, EKANS waits for all encryption threads to finish and all files to be encrypted. After that it iterates through all encrypted files and starts renaming them.
Each file is checked if it is already encrypted by checking whether it has the "EKANS"
signature at the end of the file. Files which are already encrypted are skipped.
New 16-byte
Initialization Vector (IV) and 256bit
key are generated for each file, so each file is encrypted using different key. The IV and key are generated using the rand.Read()
function which on Windows systems uses the CryptGenRandom
WinAPI function internally.[2]
Files which are already encrypted are skipped:
Generating 16-byte IV using rand.Read()
:
Generating 256bit AES key using rand.Read()
:
The AES algorithm is used in CTR mode and the contents of the files are encrypted using the method ctr.XORKeyStream()
. The contents of the files are read in chunks of 0x19000
bytes and when all data in the file is encrypted, they get overwritten with the new content.
AES in CTR mode:
Files are read in 0x19000
byte chunks:
Encrypting the buffer with ctr.XORKeyStream
method:
After the file is encrypted, the AES key gets encrypted using the rsa.EncryptOAEP
function. OAEP stands for Optimal Asymmetric Encryption Padding which is a padding scheme for RSA which adds a level of randomness to the algorithm.
EKANS then appends a structure to the end of the file containing the original filename, IV and encrypted AES key. The structure is in a gob encoding which is a binary go-specific encoding used for serialization. The low level details about the encoding are described in the go documentation.[3][4]
The encryption of the AES key with the rsa.EncryptOAEP
function:
Data is appended at the end of the file using gob:
When encryption is finished, before the ransomware process terminates it restores network communication with to following commands:
netsh advfirewall set allprofiles state off
2.9 Encrypted files
The structure which is appended to the end of the encrypted files is shown below. At the end the “EKANS”
signature is appended and before that is the size of the gob structure in little-endian format.
The coloured regions in the picture are as follows:
- The “EKANS” Signature
- Length of the gob structure in little-endian format
- The RSA encrypted AES key
- The original filename before encryption.
3. Conclusions
No privilege escalation, network communication or spreading mechanisms were found. This means that the attackers who wrote EKANS, compromise the environment manually and probably make sure they have the necessary privileges to execute the malware.
The ransom note is dropped only on domain controllers which could mean that the attackers try to compromise the whole domain before deploying the malware.
The AES keys used to encrypt the files are encrypted with the public RSA key of the attackers. Decryption is not possible without the private RSA key.
4. Recommendations
It is not known how the attackers compromise the victims initially, but it is suspected that it’s probably through Internet exposed RDP. The general recommendations when it comes to a ransomware attack are:
- Maintain offline backups for critical systems.
- Use strong passwords.
- Monitor the servers and network environment for suspicious security events.
- Update software versions and apply patches whenever possible.
- Do regular vulnerability scans.
- Disable any services used for administration (SSH, RDP, etc.) accessible from the internet. Use VPN to connect to the internal network and then connect to the intended services.