Key Takeaways
- Kroll has observed a new loader for SPARKRAT malware used in ongoing campaigns.
- While SPARKRAT development has officially ceased, unofficially it has continued to be modified by threat actors as needed.
- One of these new changes is a previously undocumented loader, identified by the AES key “LeslieCheungKwok”.
Summary
Kroll observed the use of SPARKRAT in conjunction with a previously undocumented loader written in Golang. The loader assists in the initial infection and deployment of the malicious payload, enabling SPARKRAT to execute on a system. This process allows the payload to reach the target system undetected and unquarantined. The loader achieves its goal by decoding and decrypting a secondary payload binary, then injecting it into a notepad.exe instance. This injection allows the malware to blend with legitimate system activity as it shares the memory space of a legitimate application. Despite detection tools’ ability to mitigate process injections, they remain a common evasion tactic.
GitHub developer XZB-1248 wrote and released SPARKRAT, a Golang binary compiled for multiple platforms, as an open-source, feature-rich remote admin tool on GitHub on March 18, 2022. Even though the developer abandoned the project in February 2023, intrusion investigations continue to discover modified versions of SPARKRAT. The “DRAGONSPARK” campaign, notorious for its attacks against organizations in East Asia, frequently uses this malware. SPARKRAT interprets its embedded Golang source code at runtime, which complicates analysis and static detections.
A source code repository very similar to LESLIELOADER has been identified alongside with instructions on how to utilize the loader for any payload necessary, originally timestamped June 7, 2022. Steps include generating a shellcode payload, AES encrypting the payload, and generating the executable. Additionally, the author posted proofs of running the samples against various antivirus and sandbox tools. However, there are some key differences from LESLIELOADER. Unlike the samples observed by Kroll, this loader does not beacon out a network connection. Additionally, this loader does not use process injection for code execution or a secondary file for payload.
Figure 1: Similar Code Repository
Later forks of this repository show modified versions of the initial loader, which begin to implement Base64 decoding. Continued modification of this original source code likely resulted in the version covered within this article.
Figure 2: Forked Repository Showing Addition of Base64 Decoding Stage
Kroll has identified and triaged additional LESLIELOADER samples and has observed them to contain Cobalt Strike configurations as well as other payloads, so this loader is not limited to SPARKRAT.
First Loader Stage
The loader begins with two files, Ntmssvc.dll and RemovableStorage.dll. Upon execution of Ntmssvc.dll with the /runcode flag, RemovableStorage.dll is read from C:\\Windows\System32\. Ntmssvc.dll contains the loader functionality, and RemovableStorage.dll functions as the payload.
Figure 3: RemovableStorage.dll File Read into Memory
RemovableStorage.dll is not a true PE file and does not contain the structure needed by the Windows PE loader to run independently. Instead, it serves as a payload data file that has undergone both Base64 encoding and AES 192-bit encryption.
Ntmssvc.dll initially attempts to beacon out to 209.141.50[.]215:443, however, this execution can be skipped in favor of overwriting the instruction pointer to the storage decoding function.
Figure 4: HTTP Beacon Attempt
Figure 5: Jumping to the Loader Function
Stepping through the storage decoding function, the last 32 bytes of RemovableStorage.dll are Base64 decoded and loaded into the RDI register, with LeslieCheungKwok loaded into the RCX register. The system then Base64 decodes RemovableStorage.dll and uses LeslieCheungKwok as the AES key to decrypt the resulting payload of data, with the 32 bytes from the end of RemovableStorage.dll serving as the IV. The resulting payload contains additional Base64 encoded data.
Figure 6: AES Key and IV are Loaded into Memory
Second Loader Stage
Stepping into the loader for this decrypted and decoded output, we continue to see Base64 decoding occur to portions of our file.
Figure 7: Further Base64 Decoding
Inspecting this, we see snippets of what appears to be shellcode using CyberChef.
Figure 8: CyberChef Recipe and Output
To continue observing the loader’s behavior to the memory pages containing these payloads, we set hardware breakpoints for memory access to them. Ultimately, we can observe the final payload for process injection dynamically calculated to have the size of 83DA50 in registers RCX and RDX.
Figure 9: Preparing for process injection.
Figure 10: Final Payload Size in RAX and RDX
Process injection to notepad.exe begins with a matching payload size in register r8 when memory is being allocated.
Notepad.exe is launched as a suspended process, however, there are additional artifacts of note within the loader indicating other processes such as calc.exe and cmd.exe. While they do not appear to be used in this sample for injection, the analysis of the use of these processes is out of scope.
Figure 11: Acquiring Pointer to notepad.exe
Once notepad.exe is created as a suspended process, Ntmssvc.dll overwrites the process memory for notepad.exe to manipulate the entry point. Prior to overwriting the entry point, notepad.exe proceeds as follows:
Figure 12: Original Entry Point
Once the notepad.exe entry point has been overwritten, the memory address of our SPARKRAT payload is loaded into RAX and jumped to, beginning execution of the malware.
Figure 13: Modified entry point
This now allows for the injected payload to be executed as notepad.exe.
File Information
Filename | Ntmssvc.dll |
---|---|
MD5 | a8164d4d4c7c0669f01f0cec11db5c23 |
SHA1 | 524d1042f6834b5d5af6fc8361d25eb3c5e0925c |
SHA-256 | ec45da0ca70a9b71652cc95d51665f7ad568294bd5652c395a119bccd613e9b4 |
SSDeep | 49152:NzPXvD233tOrb/TgvO90d7HjmAFd4A64nsfJaZmq59X4uv+J9mqBAhmm9tHaF90V:o3l/1MEUkz6h+ |
File Size | 5.2M |
Go Version | 1.19.6 |
Go Build ID | CkXRLYLV5G2q6zLSX2ow/XDMcRiYChHDh4RhVcflB/AvlcOAk9US3h4x7V9sBS/D-1jdZnavCSSXOMBjnmk |
Filename | RemovableStorage.dll |
---|---|
MD5 | d8ed87bccf4ff55b98ee6fd229427a45 |
SHA1 | 1e0d10e17bf5fc2b1dd7cfc717767d87e5fd4489 |
SHA-256 | b8cab11421eb4731c16cf3c34ca2b3f2a758d5e112f877b90a18b3e146c8add0 |
SSDeep | 49152:wTJSBSikp+WKZvBSVAYk5d606sKhdu6XAPf48ud5cFCz0/cef1Y0Ei7Mt3iyEiYM:O |
File Size | 15M |
Additional Samples
During this investigation, Kroll identified other samples with indicators common to this loader. Several of these files notably have indications of Cobalt Strike and shellcode injection payloads. VirusTotal currently has the following list of hashes that have been identified with the yara rule listed below:
SHA-256 | VT Submissions |
---|---|
f63511dc1d46742a9afb09e51294bcefa6a950326688c6e67b13facbf8ecdcff | 1 |
0b77f2dc04fcb24034feb26ed8bb0721da93f55d74ea8347373946abdf245f37 | 1 |
e70aac286c3b320c7cf19a74904c3ff5ecd1795915c98c56c9ff3915875595da | 1 |
75a49cd2762810d0e9bd0187e8a29a0ad3e84281028e8aec44723249a5da2363 | 1 |
e8a08771552c29c573f55f6d444d9b9282f331e703fda76110deb124b801d730 | 1 |
f28f9a11926cfbd08896ee669607ea9ce10f69e217ce10f5ed74db688687cba5 | 1 |
b5ba48002f13975f23851a3ec80547aa71d6953ce7aad42af3ba4a87699c80dd | 1 |
05ecd6749aea5cade72b028994e719b3c3315103ef8ba6c46d4dba72575080e0 | 2 |
c9b36dbca2f3260c62c1180720be599886e56191be9d4b1822dacec4d8dd3e99 | 1 |
4741ddd031d4741e9ef92f606753ea4e95b9e161173a2a82c18ffd1f8206d852 | 1 |
fd557bc84742fa76efd394f0f5f648a889648bd01487c489aa395251b61a7d60 | 1 |
b5d46ffed1ec57b24867499bd15f5a0487443e1f0f4c1fa578d917e851560ba4 | 1 |
24c197844f1275df73f45803b1a740d4dae565f6de06bac388f2cd6df454469c | 1 |
fb728d019149bb3dd696c1b417ceea008b88a18baf61b2640bae224ed8148cbe | 1 |
0c3cb0a8314e668a65df60800c8075e34b95d1d18fe72fe269f938454543bca9 | 1 |
983e03a0f46cd40a861f7dc3e4efd1397b9b474168dc322a75a551bfb3fa8ded | 1 |
db42d41a59e3e5c9bb234479ce05cd1923ef9754911cc14e9b3e5d500e191511 | 1 |
94445af999055bf7d7cddc0d1d5183ab2776d85285f0522a28fac6c5a6101906 | 1 |
fdea8b01b2597ceafe6f08b5fd12cc603b1e3ce2037731c0b6defde6935b1ce0 | 1 |
25bfed3eb9ebc12604edee0aeb4c8bc2f2a37e9fd1c77ebda33b5756509a726d | 1 |
2df61720ffee7a6730c029da45bddba2ec9eace7359e1ee964b44560e9062bb9 | 1 |
12afe1b18b0e7dcc4903fff3a7dc2a2b6c3d111c2f836e7b4d13ed082b8dea89 | 1 |
73d1d42b76e1051c6ad0c832dc1c6bcd7158f4a0687f1f7d84c9c3c513b0e43e | 1 |
4ca0d50308013957a3da3fc60a62649c405fd9dbf7b184b18e73333ddf23e0bc | 1 |
Additionally, the below Yara rule may be used to search for indications of this loader:
import "pe"
rule leslieloader
{
meta:
author = "Marc Messer"
description = "Checks for the inline string “LeslieCheungKwok” with instructions."
truepositive = "ec45da0ca70a9b71652cc95d51665f7ad568294bd5652c395a119bccd613e9b4"
strings:
$a = {48 b9 4c 65 73 6c 69 65 43 68 48 89 08 48 b9 65 75 6e 67 4b 77 6f 6b}
condition:
pe.is_pe and $a
}
https://www.kroll.com/en/insights/publications/cyber/leslieloader-undocumented-loader-observed