We’re super excited to introduce a guest writer – Mizuho (@morimolymoly2 on X) today, a software engineer and malware analyst making their debut on the ANY.RUN blog. In today’s article, Mizuho guides us through surface, dynamic, and static analysis of DCRat. Let’s dive in.
In this article, I’ll guide you through the analysis process of DCRat using ANY.RUN.
This powerful malware has been available since 2018. Despite its low $5 price tag, it offers a wide array of malicious functions, such as full backdoor access to Windows systems, collection of sensitive personal information like usernames, passwords, and credit card details, capturing screenshots, and stealing Telegram, Steam, and Discord login credentials.
Given the complexity and the range of functions of DCRat, underestimating this malware could lead to significant security breaches and data loss.
Why I picked DCRat for this analysis
I noticed that DCRat seems to be gaining popularity as of late — it has been frequently mentioned in various underground online forums. This inexpensive, yet highly capable malware gives threat actors complete surveillance over their victims, and its potential to access and control social network accounts adds another layer of risk. It can compromise not just individual data but also potentially broader networks and contacts.
In the article I aim to cover:
- Distribution and ecosystem of DCRat.
- Surface and Dynamic analysis of DCRat.
- Static analysis of DCRat.
What is DCRat malware
DCRat, also known as Dark Crystal RAT, is both a Remote Access Trojan (RAT) and an information stealer. This dual functionality makes it an especially nasty tool in the hands of cybercriminals.
DCRat’s modular architecture allows for a high degree of customization, meaning that attackers can configure the malware for their specific objectives. Modularity also ensures that its code can be constantly mutated to bypass signature-based detection.
One of the most alarming aspects of DCRat is its low price of just $5. This low cost makes it accessible to a wide array of cybercriminals, and its use has been observed by both novices and organized threat actors.
This is our investigated infection chain of DCRat:
As you can see from the ANY.RUN Malware Trends Tracker, DCRat is ranked 9th among all malware as of January 18, 2024, and it’s on a rising trajectory. You can observe numerous detections of this malware in ANY.RUN’s Public Submissions, and there are also plenty of samples available on Malware Bazaar.
DCRat’s Ecosystem
DCRat is sold via a Telegram group, where it often goes on sale. It operates on a subscription model, and the standard prices are as follows:
- 2months: 5$
- 1year: 19$
- Lifetime: 39$
This is already quite inexpensive, but during promotions, the price drops even further. The creators of the malware launched a Telegram bot to sell DCRat “licenses”:
You can also receive support via the same TG bot. The presence of a formal payment page likely makes the process of purchasing malware less daunting for first-timers — DCRat’s creators are proficient businessmen and marketers.
The payment page for DCRat is hosted on crystalpay[.]io:
I looked into how BTC payments for DCRat are processed using a block explorer. Each payment goes to a temporary wallet address facilitated by crystalpay[.]io.
From how they operate, it seems that the DCRat team is quite cautious about their OPSEC.
- They do all communication though Telegram.
- They only accept crypto payments to burner wallets.
- They use crystalpay[.]io to further anonymize transactions.
Surface analysis of DCRat
Let’s begin exploring this threat by examining its external characteristics, such as its iconography.
In this case, the loader is disguised behind a printer’s driver icon.
The identification of the DCRat loader as an SFX (Self-Extracting Archive) file is detected by tools like Detect It Easy. SFX files are a type of executable that contains compressed data, often used for legitimate purposes such as simplifying the installation process of software.
The SFX file executes its embedded script that automatically extracts its contents and then executes these files without the user’s knowledge.
In the case of our sample, the SFX file is password-protected to evade detection and hinder reverse engineering. Cracking these passwords can be a time-consuming and resource-intensive process.
In cybersecurity research, we can use alternative methods to understand the threat, such as analyzing the malware’s behavior in a controlled environment, examining network traffic for anomalies, or using known indicators of compromise (IOCs) to detect its presence on affected systems.
Dynamic Analysis in ANY.RUN
I conducted dynamic analysis with ANY.RUN for ease. The detonation results are here.
Let’s first examine the executable file.
The file 76de703cc14b6c07efe92f8f73f9b91e91dc0a48a0024cfdf72fca09cacb5157.exe has a digital signature from ESET, as shown in the image below:
Note the description labeled “Uninstall WinRAR”. It is likely that the phishing strategy used by attackers involves tricking users into “uninstalling” this utility.
Modified files are shown in the image below. Dropped files are important artifacts, indicating that 7z.exe extracts a compressed file (file.bin).
Dropped files from DCRat show that it has 7-zip executables because it is an SFX file.
The scan results of 7z.dll and 7z.exe at VirusTotal reveal that both of the hashes are well-known and legitimate.
Next, let’s take a look at C:\Users\admin\AppData\Roaming\temp\main.bat. This is a configuration of a 7-zip SFX executable. You can check the content of the “main.bat” file on ANY.RUN as shown below:
This executable performs the following actions:
- Extract file.bin
- Launch C:\Users\admin\AppData\Roaming\temp\main.bat(configuration file)
- Extract file.bin(file.zip) and get portprovider.exe
- Make portprovider.exe hidden
- Launch portprovider.exe
- Delete portprovider.exe
Let’s take a closer look at what this portprovider.exe is:
“portprovider.exe” is a component of DCRat, masquerading as Spotify to blend in with legitimate processes on a user’s computer. DCRat aims to operate without users being aware of its presence on the computer.
portprovider.exe drops many executables, all of which have the same hash:
After dropping these files, cmd.exe executes C:\Users\admin\AppData\Local\Temp\vvGzDF3vOe.bat.
C:\Users\admin\AppData\Local\Temp\vvGzDF3vOe.bat performs the following actions:
- Starts C:\Users\admin\StartMenuExperienceHost.exe (DCRat)
- Deletes C:\Users\admin\AppData\Local\Temp\vvGzDF3vOe.bat (itself)
- StartMenuExperienceHost.exe (DCRat) connects to 019214cm[.]nyashland[.]top:80 (C2 address) and posts to path /EternalLineLowgameDefaultsqlbaseasyncuniversal.php.
“portprovider.exe” creates multiple scheduled tasks to ensure persistence:
When analyzing scheduled tasks, it’s helpful to pay attention to the following:
- The names of the scheduled tasks
- The actions specified in the tasks.
- The triggers for the tasks.
In our case the tasks created were as follows:
- C:\Users\All Users\dllhost.exe
- C:\Users\admin\StartMenuExperienceHost.exe
- C:\Users\Public\fontdrvhost.exe
- C:\Users\Public\Documents\My Videos\fontdrvhost.exe
- C:\Users\admin\Start Menu\explorer.exe
- C:\Users\admin\AppData\Roaming\temp\portprovider.exe
And we can see that one scheduled task was executed:
DCRat Static Analysis
Let’s dive into the static analysis of DCRat to better understand its functions, IOCs, and configuration details.
First, let’s take a look at the DCRat in Detect it Easy (DIE):
Nothing particularly noteworthy here; it appears to be an obfuscated .NET application.
Obfuscation in the context of a .NET application involves modifying the original source code to make it challenging to understand, though not impossible to analyze, especially with the right tools such as DnSpy.
As depicted in the screenshot above, DCRat gathers a substantial amount of data:
- Screen Capture
- Webcam
- Microphone
- Steam specific data
- Telegram specific data
- Discord specific data
- .NET specific data
Analyzing the “Upload” function in DCRat can help us identify the C2 server address. This process involves scrutinizing the decompiled source code to pinpoint the specific function responsible for data exfiltration:
In our case, the function ns21.F5x.w90 and the specific method ns12.sz3.method_0() are responsible for generating the C2. The function references dgz.x2l.x2l as the final executor of this action.
The code below calls KO4 and XT1. Let’s break down what they are responsible for:
The functionality of KO4 lies in generating a password and HMAC (Hash-based Message Authentication Code) to ensure secure communication and data integrity.
DCRat employs string0 as a password and byte_1 as a salt. The combination of a password and a salt is a common strategy to enhance the security of encryption and hashing.
XT1 (above) retrieves the first base64-like string from dgz.x2l.array, decodes it using base64, and then passes it to the Gi8 function. It appears that Gi8 serves as the decryption component.
The argument string is initially encoded in Base64 and subsequently encrypted using AES, with KO4.W7U acting as the key.
The string 2DR3p5K1MlSUp8vL (above) constitutes part of the salt. Finally, it becomes apparent that KO4 is a generator of configuration:
It combines two strings (circled in red). CtvQZH10ETJuAmYV2DR3p5K1MlSUp8vL represents the salt, while the password is array[2]. We wrote the decryption code for it. Please refer to the appendix for details.
Wrapping up
We’re finally on the home stretch.
The decompiled .NET code includes specific namespaces tailored to distinct functions pertaining to security and communication.
The ns12 namespace encompasses functionality for config decryption, tasked with decrypting configuration data utilized by the malware to operate.
On the other hand, the dgz namespace is linked to C2 decryption features, housing methods for decrypting communication between the malware and its C2 server.
You can see a decrypted config as follows:
["bj0UKX3O1fsx9BYPGXoKHqjvLayVva1jN63FIaBpzhY4ZE1D43om8NOuAFJtihcbnIkDHSHpW8UjRpWHjvb2vPk9sIFCRRHSF7QQdy5lw8PA2odUtBKwGkpYhlU9MEYF","DCR_MUTEX-11Fyfh7gXU61FzPB2sRh","0","VV??","","5","2","WyIxIiwiIiwiNSJd","WyIxIiwiV3lJaUxDSWlMQ0psZVVsM1NXcHZhV1V4VGxwVk1WSkdWRlZTVTFOV1drWm1VemxXWXpKV2VXTjVPR2xNUTBsNFNXcHZhVnB0Um5Oak1sVnBURU5KZVVscWIybGFiVVp6WXpKVmFVeERTWHBKYW05cFpFaEtNVnBUU1hOSmFsRnBUMmxLTUdOdVZteEphWGRwVGxOSk5rbHVVbmxrVjFWcFRFTkpNa2xxYjJsa1NFb3hXbE5KYzBscVkybFBhVXB0V1ZkNGVscFRTWE5KYW1kcFQybEtNR051Vm14SmFYZHBUMU5KTmtsdVVubGtWMVZwVEVOSmVFMURTVFpKYmxKNVpGZFZhVXhEU1hoTlUwazJTVzVTZVdSWFZXbE1RMGw0VFdsSk5rbHVVbmxrVjFWcFRFTkplRTE1U1RaSmJsSjVaRmRWYVV4RFNYaE9RMGsyU1c1U2VXUlhWV2xtVVQwOUlsMD0iXQ=="]
It’s worth noting the inclusion of a Mutex (mutual exclusion object) value. It prevents multiple instances of the same malware from running on the same host:
Here is the decrypted C2 address:
http://019214cm[.]nyashland[.]top/”,”EternalLineLowgameDefaultsqlbaseasyncuniversal
Decryption code is also provided in the Appendix.
ANY.RUN was highly useful for dynamic analysis. It helps trace network traffic, and easily collect IOCs such as domain names, IP addresses, and other network-based signatures. However, to see the internals of a .NET RAT you need static analysis and code deobfuscation skills.
In static analysis, you can use decompilers (such as dnSpy or ILSpy for .NET applications) to revert the obfuscated executable back into higher-level code.
Look for patterns and rely on your comprehension of common malware behavior and knowledge of the .NET framework to identify the malware’s operational logic.
Also, you can extract strings directly from the binary to obtain information such as hardcoded IP addresses, domain names, file paths, and other artifacts.
I recommend using FLOSS: https://github.com/mandiant/flare-floss
Flare FLOSS is helpful for extracting strings from binaries. It is designed to automatically deobfuscate and identify hidden strings that have been obfuscated to evade detection.
Should you prioritize static or dynamic analysis?
This depends entirely on the use case. For SOC analysts and incident responders, the primary focus is on swiftly identifying threats and implementing containment measures. In this context, static analysis of malware can be time-consuming, and tools like ANY.RUN are invaluable for rapidly understanding the malware’s impact.
On the other hand, for a malware analyst or researcher who dedicates significant time to unpacking every aspect of the malware’s operation, deep-dive static analysis is essential. This approach aims not only to comprehend and mitigate the current threat but also to anticipate future variations and contribute to the development of long-term defenses.
MITRE ATT&CK of DCRat
ANY.RUN automatically maps threats to the MITRE ATT&CK framework. This makes it easy for SOC analysts to quickly understand TTPs employed by a given piece of malware.
Conclusion
In the article, we’ve explored the functionalities of DCRat and its ecosystem. Notably, DCRat is accessible at a low cost and boasts a widespread user base. Of particular interest is its payment system, crystalpay[.]io, which helps attackers conceal transactions. We also saw that the DCRat team demonstrates a high level of OPSEC awareness.
About ANY.RUN
Trusted by over 400,000 security specialists, ANY.RUN empowers SOC and DFIR teams to efficiently investigate threats through its cloud-based malware sandbox.
Get started in ANY.RUN for free today →
Appendix
IOCs
DCRat SFX: 76de703cc14b6c07efe92f8f73f9b91e91dc0a48a0024cfdf72fca09cacb5157
DCRat: 5fe993c74d2fa4eb065149591af56011855a0a8f5471dab498d9e0f6641c6851
C2 domain: 019214cm[.]nyashland[.]top
C2: hxxp://019214cm[.]nyashland[.]top/EternalLineLowgameDefaultsqlbaseasyncuniversal[.]php
YARA rule
import "dotnet"
rule dcrat_yara {
meta:
description = "DCRat YARA"
author = "Mizuho Mori a.k.a. morimolymoly"
hash = "5fe993c74d2fa4eb065149591af56011855a0a8f5471dab498d9e0f6641c6851"
strings:
$1 = "Uninstall WinRAR"
$2 = "k786jutyhrtgj756h4tgrku6jyhrtgerjyhrtgerfwc"
$3 = "Alexander Roshalov"
$8 = "Webcams"
$9 = "TelegramPath"
$10 = "FrameworkVersion"
$11 = "Saving..."
$12 = "DarkCrystal RAT"
$13 = "[Screenshot] Saving screenshots from "
$14 = "[Clipboard] Saving information..."
$15 = "[SystemInfromation] Saving information..."
condition:
(dotnet.is_dotnet == 1) and
any of them
}
Decryption code for DCRat config
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from hashlib import sha256
import base64
import hmac
class KO4:
def __init__(self, password, salt):
kdf = PBKDF2HMAC(
algorithm=hashes.SHA1(),
length=96, # 32 + 64
salt=salt,
iterations=1024,
backend=default_backend()
)
key = kdf.derive(password)
self.key = key[:32]
self.hmac = key[32:96]
def decrypt_aes(encrypted_data, key, hmack):
hmac_sha256 = hmac.new(hmack, digestmod=sha256)
hmac_sha256.update(encrypted_data[32:])
computed_hmac = hmac_sha256.digest()
if computed_hmac != encrypted_data[:32]:
raise ValueError("HMAC verification failed")
iv = encrypted_data[32:48]
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
decrypted_data = decryptor.update(encrypted_data[48:]) + decryptor.finalize()
return decrypted_data
password = "1CeTYFnv0zFx9kGDpuTPGULeR1t2d5ZrjKJzJJ5oXZ6Re2Z6eQUbvJ8g19ChWvR4aXNybQ4fzp1rX3AZcwXMl76aMm8JHYSmHB1HokfNWymFRQJ89mEjXFTcbxmzSuXa".encode("utf-8")
salt = "CtvQZH10ETJuAmYV2DR3p5K1MlSUp8vL".encode("utf-8")
ko4_instance = KO4(password, salt)
key = ko4_instance.key
encrypted_data = base64.b64decode("twqziPMyOf6TnyOB/OK1jTdK956e34V42RMtGMVty6+ZbZ/0qhyPa51EFIbkOILnUmjGENz8Bsxp9j12/g0Zr3vpvrUnsOzV2cwwuEaLXKjVJIqSveHZfNuYG6F4zyNhcW8shTMg0VI7dKjnY1vGpJbwrXByPVnI4FBFnJoRImSAE1vNJjvzdOzHq5+w2xstewXQhRP4PqEtgiVd3odCEho1geLc70vkATTvkgk2FVbmSJAF1j6SSlWrBFBm8Bl2lLqol1r85lvAIjSpagTFIm8QKQfD05h5sXR17sKazsdKdP9ahYS+ldWkjEMLe8tV5boxfNV1gJDpi15NixjKJWS5myqzYOhSQn1JynlWh9ej0Y2YYlj3YEp/j+xqWYvOvnHPVdOt928Z9+jep98h0SxvkGnrNxLvcDIJI0VSVkC9eIU4XADkRe4hAMmJbvQ5671XQSoLJCsWxQ4IzS596vNXL7n+UKLx2LXD/fkJNE7NMMOKuFGBQ+IgdOffNUw9gOV3731cJ4WFYfMLMLuhZeQI4sDbY9xlAXD9Ha+7hY7Dx9sk3u9ybZZ0DP0nxW2w9zNad/GEX9+MklEXrRjLjGDD5iCQKCAMKaSVEsTvKPZ3RX2BtuRrL2egqdU531tZKbG4yJnXY12vrzJeS2Dg+1/IVQEoFVfNoWF0sPil1Dvmt28pC5+7+9v8/vIxVfn6LP4PbSpTW1qNSZK5LWQDiSAFyFfnO6Vpk7atHaYlb1+t9gBaPBOLJJQCwXLNUVhRwY271kvh8EUUwFo4ld7kPVv5zNIbe5oTVR8UewFIES2f4KGGLo4loJpBM+5dMvomDctqqFNCmASxLHikniRsOs+5ci4I0hig0khqu1JYM8hNxrlaTPI2BboP3f0gFhFN9YmTL1KicLWdh6ftKWRFQX0qPYd6Ww4oQuBAxEkKA76wEHdpoO5iDVCXoQhF+QPpXxRrxvIzbPlpmQsfPiZa+/N4P9zm0wmTv02102/UN+0=")
decrypted_data = decrypt_aes(encrypted_data, key, ko4_instance.hmac)
print(decrypted_data.decode("utf-8"))
Decryption of C2 address
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes, padding
from hashlib import sha256
import base64
import hmac
class KO4:
def __init__(self, password, salt):
kdf = PBKDF2HMAC(
algorithm=hashes.SHA1(),
length=96, # 32 + 64
salt=salt,
iterations=1024,
backend=default_backend()
)
key = kdf.derive(password)
self.key = key[:32]
self.hmac = key[32:96]
def decrypt_aes(encrypted_data, key, hmack):
hmac_sha256 = hmac.new(hmack, digestmod=sha256)
hmac_sha256.update(encrypted_data[32:])
computed_hmac = hmac_sha256.digest()
if computed_hmac != encrypted_data[:32]:
raise ValueError("HMAC verification failed")
iv = encrypted_data[32:48]
encrypted_data = encrypted_data[48:]
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
padded_plaintext = decryptor.update(encrypted_data) + decryptor.finalize()
unpadder = padding.PKCS7(128).unpadder()
plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
return plaintext
# decrypt Password
password = "bj0UKX3O1fsx9BYPGXoKHqjvLayVva1jN63FIaBpzhY4ZE1D43om8NOuAFJtihcbnIkDHSHpW8UjRpWHjvb2vPk9sIFCRRHSF7QQdy5lw8PA2odUtBKwGkpYhlU9MEYF".encode("utf-8")
salt = "CtvQZH10ETJuAmYV2DR3p5K1MlSUp8vL".encode("utf-8")
ko4_instance = KO4(password, salt)
key = ko4_instance.key
encrypted_data = base64.b64decode("6DuJThqLqhXMRndyjcrpSvR+NowgfgPUfadTAPLT7RzQEaQ3bZTS2B69cJ+6b9gMItPpYbJufWtQMjS77Qehab2Q+nE+hYfWDfb+T9kHg8KoSt+NAc00NmL95jbxX5qWdMKBiNsSTppEM/HD93PwYFKZCrLv7VhGHiQP8GV5/h8KKSZ+93DQTyTyXIU9kKzo6EM/bmELphag+kIO5kj28pRQY9kCOtzWU5LxezAmxJdrcp+EGjpZSgMpeynFIZE9")
decrypted_data = decrypt_aes(encrypted_data, key, ko4_instance.hmac)
print("decrypted password: " + decrypted_data.decode("utf-8"))
# decrypt C2
password = "XPkWC3v1QKzwU0J5dAKeTsPBsYp18q5mbMsCqw5G1NTNQgIkoqWSj2GpAinnN33kONVHHGPqEEnGZBvMQFMRTmCiGDCHIS37Ts8DKAchbqOfP9P8xbXIqlQlKxBEEHhv".encode("utf-8")
salt = "CtvQZH10ETJuAmYV2DR3p5K1MlSUp8vL".encode("utf-8")
ko4_instance = KO4(password, salt)
key = ko4_instance.key
encrypted_data = base64.b64decode("zCEl5MLNt1nWGMDkINJb16lVnQwVhHlbE0ON/jzps092WYVbsn8xXBFE1kAEM8FE6Zu4vZdIFAVDmeASNmk+Cal/saaZFTYrBzpD6gHAmeV/2nzMJLz3TeS9r66FgUt0rP/vImvRIfwAfOjcSrkD1sdkzQFiIyDJZ3lO3QnF4FxspW89vlhx6OBIISdDgT0h")
decrypted_data = decrypt_aes(encrypted_data, key, ko4_instance.hmac)
print("decrypted C2: " + decrypted_data.decode("utf-8"))
Mizuho Mori
Mizuho is a guest writer, software engineer, malware analyst. His background was a cyber threat intelligence analyst and cyber threat researcher. He currently spends time on researching malware trends and malware analysis. He has a passion for programming and researching and investigation.
Check his website out.
1 comments
Excellent first contribution!