VoidStealer — Debugger-Based Chrome ABE Bypass
Executive Summary
VoidStealer ("The Void") is a Malware-as-a-Service infostealer sold via Telegram/underground forums and run across multiple simultaneous campaigns in 2026. Its v2.0 variant (first seen 2026-03-13) is the first malware observed in the wild to weaponize a debugger-based technique against Chrome's Application-Bound Encryption (ABE): instead of injecting into the browser or escalating to SYSTEM, it launches the browser hidden/suspended, attaches as a debugger, sets a hardware breakpoint on the ABE decrypt routine, and reads the v20_master_key straight from a CPU register — defeating ABE with neither code injection nor privilege escalation.
Mechanically: it calls CreateProcessW with CREATE_SUSPENDED + SW_HIDE, DebugActiveProcess to attach, sets DR0/DR7 (hardware breakpoint) on LEA RCX, OSCrypt.AppBoundProvider.Decrypt.ResultCode (string found in the browser's .rdata), then on the breakpoint reads v20_master_key from R14 (Edge) / R15 (Chrome) via ReadProcessMemory. It evades EDR with direct/Zw-prefixed ntdll syscalls resolved at runtime, dynamic API resolution (no import table), XOR-encrypted config, and a mutex-based sandbox check. C2 uses a Steam profile as a dead-drop resolver (server address embedded in the display name) fronted by an intermediate portal. It follows a grab-and-go model — collect, exfil, exit — leaving minimal persistence.
Defender priority: The technique's tell is loud even though the syscalls are quiet — a non-browser process launching chrome.exe/msedge.exe hidden off-screen (--window-position=-32000,-32000, --no-sandbox, --disable-extensions) and then debugging it / reading its memory. Hunt for that lineage plus reads of Local State / Login Data by non-browser code. Because ABE is bypassed at user level, treat any hit as cookie + credential theft: invalidate sessions and rotate, don't just reset passwords.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry Fwd |
|---|---|---|---|
| 1 | Gen Digital Research — "VoidStealer: Debugging Chrome to Steal Its Secrets" | Full debugger-bypass chain (DebugActiveProcess, DR0/DR7 hardware breakpoint, v20_master_key from R14/R15), target paths, SHA-256, v2.0 date | yes |
| 1 | SOCRadar — "Void Stealer: The Infostealer Quietly Targeting Organizations in 2026" | MaaS model, Zw-syscall EDR bypass, Steam dead-drop (SteamID), intermediate C2 (citrusshop.icu), browser launch flags, data targeted | yes |
| 2 | Kaspersky / BlackFog | Corroborate ABE bypass, 20+ browser targeting, grab-and-go architecture | partial |
Web-hunter note: One v2.0 sample SHA-256 was published (Gen Digital); SOCRadar references additional MD5s in a gated whitepaper not reproduced here. The hunts therefore lead with behavior (hidden-browser-launch + debug + memory-read), which survives repacking, and pin the published hash/domain/SteamID as exact IOCs.
Hunt Brief & Attack Chain
Hunt hypotheses (ordered by fidelity)
- H1 (high): A non-browser process launches
chrome.exe/msedge.exewith off-screen +--no-sandbox+--disable-extensionsflags. → Q1 - H2 (high): A browser process is spawned by an anomalous parent (not explorer/user shell/launcher) then immediately debugged. → Q2
- H3 (high): A non-browser process reads Chrome/Edge
Local StateorLogin Data(key + cred extraction). → Q3 - H4 (high): Endpoint connects to the known C2 domain or the Steam dead-drop resolver from a non-gaming process. → Q4
- H5 (high): Execution of the known VoidStealer v2.0 SHA-256. → Q5
- H6 (medium): A process reads crypto-wallet / Telegram / Discord token files in a single short burst (grab-and-go). → Q6
- H7 (medium): steamcommunity.com contacted by a process that never renders a UI / from a server endpoint. → Q4, Q7
Attack chain
| Step | Behavior | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 · Delivery | MaaS payload via phishing / fake software / loader | ProcessRollup2, PeFileWritten | Q5, generic loader hunts |
| 2 · Evasion | Mutex sandbox check; Zw-syscall + dynamic API resolution | Limited (userland-hook bypass) | Behavioral only — gap |
| 3 · Hidden browser | CreateProcessW suspended+hidden, off-screen flags | ProcessRollup2 (CommandLine, lineage) | Q1, Q2 |
| 4 · Debug + breakpoint | DebugActiveProcess; DR0/DR7 HW breakpoint on ABE decrypt | Process access / debug events | Q2, s7 |
| 5 · Key + secret theft | Read v20_master_key from register; decrypt Login Data; cookies, wallets, tokens | FileOpenInfo (Local State / Login Data) | Q3, Q6 |
| 6 · C2 resolution | Steam profile dead-drop → intermediate portal | DnsRequest, NetworkConnectIP4 | Q4, Q7 |
| 7 · Exfil + exit | JSON upload to low-rep domain; Telegram notify; terminate | NetworkConnectIP4, EndOfProcess | Q4 |
Consolidated IOC Table
Values are source-attributed (Gen Digital / SOCRadar). Behavior-first: the launch-flags + debug + memory-read chain is the durable signal; the hash/domain/SteamID are exact but perishable.
| Type | Value | Conf | Action | Context |
|---|---|---|---|---|
| sha256 | f783fde5cf7930e4b3054393efadd3675b505cbef8e9d7ae58aa35b435adeea4 | high | detect | VoidStealer v2.0 sample (Gen Digital) |
| domain | citrusshop.icu | high | detect | Active intermediate C2 portal |
| steam | SteamID 76561199877608270 | high | hunt | Dead-drop resolver (C2 address in display name) |
| behavior | chrome/msedge launched with --window-position=-32000,-32000 --no-sandbox --disable-extensions | high | detect | Hidden off-screen browser for ABE bypass |
| behavior | DebugActiveProcess + DR0/DR7 HW breakpoint on browser | high | hunt | Debugger-based key extraction |
| string | OSCrypt.AppBoundProvider.Decrypt.ResultCode | medium | pivot | .rdata target string located by the stealer |
| file path | %LOCALAPPDATA%\Google\Chrome\User Data\...\Login Data, ...\Local State | medium | hunt | Credential + ABE key source files |
| net | steamcommunity.com from non-gaming/non-browser process | medium | hunt | Dead-drop fetch |
| technique | Zw-prefixed ntdll direct syscalls; dynamic API resolution; XOR config; mutex sandbox check | medium | enrich | EDR/sandbox evasion stack |
Affected Surface & Telemetry Matrix
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Windows endpoints (Chromium + Gecko browsers) | ProcessRollup2 (CommandLine, lineage), FileOpenInfo | Critical | Low — core telemetry; the launch-flags signal is strong |
| Process-debug / memory-access layer | Process-access / debug-event telemetry | High | Direct-syscall reads may evade userland hooks — rely on lineage+flags |
| Network egress | DnsRequest, NetworkConnectIP4 | High | Steam/Telegram blend with legit traffic |
| Identity / SaaS sessions | SSO/IdP sign-in logs, impossible-travel | High | Stolen cookies replay elsewhere — endpoint won't see it |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Credential Access | T1555.003 — Credentials from Web Browsers | ABE bypass → decrypt Login Data | Q1, Q3 |
| Credential Access | T1539 — Steal Web Session Cookie | Cookie theft post-ABE-bypass | Q3 |
| Credential Access | T1552.001 — Credentials in Files | Crypto wallets / seed phrases, FTP creds | Q6 |
| Defense Evasion | T1106 — Native API | Direct Zw-prefixed ntdll syscalls | Behavioral (gap) |
| Defense Evasion | T1027.007 — Dynamic API Resolution | Functions resolved at runtime, no import table | Behavioral (gap) |
| Defense Evasion | T1622 — Debugger Evasion / debug abuse | DebugActiveProcess + HW breakpoint on browser | Q2, s7 |
| Defense Evasion | T1497.001 — Sandbox Evasion (mutex check) | Exit if mutex marker exists | Behavioral |
| Command & Control | T1102.001 — Dead Drop Resolver | Steam profile display name holds C2 address | Q4, Q7 |
| Exfiltration | T1567 — Exfil Over Web Service | JSON to low-rep domain; Telegram notify | Q4 |
Native Audit-Log Hunts (non-CQL)
- Sysmon Event ID 10 (ProcessAccess): Hunt for a non-browser
SourceImageopeningchrome.exe/msedge.exewithGrantedAccessincludingPROCESS_VM_READ(0x10) / debug rights — the strongest local tell of the memory-read step that direct syscalls can hide from EDR hooks. - Sysmon Event ID 1: Browser launched with the off-screen +
--no-sandboxflag combo by an unexpected parent. - IdP / SSO sign-in logs: After any endpoint hit, hunt for session-cookie replay — sign-ins from new ASN/geo reusing an existing session token (impossible travel, no MFA prompt).
- Proxy / DNS logs: Connections to
citrusshop.icuandsteamcommunity.comfrom server or non-gaming endpoints; JSON POSTs to newly-registered domains.
CrowdStrike LogScale CQL Hunt Queries
Looks for: chrome.exe/msedge.exe started with the off-screen window position plus --no-sandbox/--disable-extensions — the VoidStealer hidden-browser step. Very low FP: legitimate use rarely combines off-screen positioning with --no-sandbox.
// HUNT: hidden off-screen browser launch for ABE bypass // MITRE: T1555.003 CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ImageFileName=/\\(chrome|msedge)\.exe$/i | CommandLine=/window-position=-3200?0,-3200?0/i | CommandLine=/--no-sandbox|--disable-extensions|--headless/i | table([ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine], limit=200)
Looks for: chrome/msedge launched by a parent that isn't a normal shell/launcher/updater — the stealer spawning the browser to debug it. FP: Automation (Selenium/Puppeteer), RMM, and some apps launch browsers — exclude your known automation/launcher parents and correlate with Q1/Q3.
// HUNT: browser child of an unexpected parent process // MITRE: T1622 CONF: medium FP: medium COST: low | REQUIRES: ProcessRollup2 // TUNING: exclude known launchers/automation #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ImageFileName=/\\(chrome|msedge)\.exe$/i | ParentBaseFileName!=/^(explorer|chrome|msedge|firefox|userinit|svchost|GoogleUpdate|MicrosoftEdgeUpdate|cmd|powershell|StartMenuExperienceHost|SearchApp)\.exe$/i | table([ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine], limit=200)
Looks for: a process other than the browser opening Chrome/Edge Local State (holds the ABE key blob) or Login Data. FP: Backup/sync/password-manager agents read these — exclude approved tools and the browsers themselves.
// HUNT: non-browser process reads browser key/cred stores // MITRE: T1555.003, T1539 CONF: high FP: medium COST: low | REQUIRES: FileOpenInfo // TUNING: exclude approved backup/password agents #event_simpleName=/FileOpenInfo/ | TargetFileName=/\\User Data\\.*(Local State|Login Data)$/i | ImageFileName!=/\\(chrome|msedge|firefox|brave|opera)\.exe$/i | table([ComputerName, UserName, ImageFileName, TargetFileName], limit=200)
Looks for: DNS for the known intermediate C2 and for steamcommunity.com (dead-drop resolver). FP: steamcommunity.com is benign on gaming hosts — the named citrusshop.icu is high-fidelity; treat the Steam arm as hunt-only, scoped to servers / non-gaming endpoints.
// HUNT: VoidStealer C2 + Steam dead-drop DNS // MITRE: T1102.001, T1567 CONF: high FP: medium COST: low | REQUIRES: DnsRequest // TUNING: citrusshop.icu = confirmed; steamcommunity.com = hunt on non-gaming hosts #event_simpleName=DnsRequest | DomainName=/citrusshop\.icu|steamcommunity\.com/i | table([ComputerName, ContextBaseFileName, DomainName, aid], limit=200)
Looks for: execution of the published VoidStealer v2.0 SHA-256. Exact match — promote straight to a Custom IOC block.
// HUNT: known VoidStealer v2.0 SHA-256 // CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | SHA256HashData=/^f783fde5cf7930e4b3054393efadd3675b505cbef8e9d7ae58aa35b435adeea4$/i | table([ComputerName, UserName, ImageFileName, CommandLine, SHA256HashData], limit=200)
Looks for: one process reading crypto-wallet, Telegram, and Discord artifacts in a short window (grab-and-go collection). FP: High — backup/AV tooling touches these. Stack-rank by a single process hitting multiple distinct categories and correlate with Q1/Q3.
// HUNT: single process sweeping wallet + messaging secrets // MITRE: T1552.001 CONF: medium FP: high COST: medium | REQUIRES: FileOpenInfo // TUNING: require >= 2 distinct categories per process; exclude backup/AV agents #event_simpleName=/FileOpenInfo/ | TargetFileName=/wallet\.dat|\\Exodus\\|\\Electrum\\|\\Telegram Desktop\\tdata|\\discord\\.*\\Local Storage/i | groupBy([ComputerName, ImageFileName], function=count(as=hits)) | hits >= 2 | table([ComputerName, ImageFileName, hits], limit=200)
Looks for: a process that is not a browser or the Steam client contacting steamcommunity.com — the dead-drop fetch. FP: Some launchers/overlays use Steam — exclude the Steam client and known game launchers; strongest on servers.
// HUNT: Steam dead-drop fetch by non-browser/non-Steam process // MITRE: T1102.001 CONF: medium FP: medium COST: low | REQUIRES: DnsRequest // TUNING: exclude steam.exe + known game launchers; prioritize servers #event_simpleName=DnsRequest | DomainName=/steamcommunity\.com$/i | ContextBaseFileName!=/^(chrome|msedge|firefox|brave|opera|steam|steamwebhelper)\.exe$/i | table([ComputerName, ContextBaseFileName, DomainName, aid], limit=200)
CrowdStrike Custom IOA Recommendations
| IOA Name | Pattern | Exclusions | Deployment |
|---|---|---|---|
| STEALER — Hidden off-screen browser | chrome/msedge with off-screen pos + --no-sandbox | Known automation parents | Promote Q1 → Custom IOA (Detect/Prevent, High) |
| STEALER — Non-browser key-store read | Non-browser reads Local State / Login Data | Approved backup/PW agents | Promote Q3 → Custom IOA (Detect, High) after baseline |
| STEALER — VoidStealer hash | SHA-256 = f783fde5…eea4 | None | Q5 → Custom IOC (Prevent, Critical) |
Pair the IOAs with a Sysmon EID 10 (ProcessAccess) rule for non-browser PROCESS_VM_READ on browsers — it catches the memory-read even when direct syscalls evade Falcon's userland hooks.
Machine-Readable IOC Appendix
type,value,action,severity,expiration,description,tags sha256,f783fde5cf7930e4b3054393efadd3675b505cbef8e9d7ae58aa35b435adeea4,prevent,critical,2026-12-22,VoidStealer v2.0,campaign:VoidStealer domain,citrusshop.icu,detect,high,2026-09-22,VoidStealer intermediate C2,campaign:VoidStealer
# Hidden browser launch (ABE bypass) chrome.exe / msedge.exe with: --window-position=-32000,-32000 --no-sandbox --disable-extensions spawned by a non-shell parent, then debugged # Debugger key extraction CreateProcessW(CREATE_SUSPENDED|SW_HIDE) -> DebugActiveProcess -> DR0/DR7 HW breakpoint on LEA RCX, OSCrypt.AppBoundProvider.Decrypt.ResultCode -> read v20_master_key from R14 (Edge) / R15 (Chrome) via ReadProcessMemory # Sysmon EID 10: non-browser SourceImage opens chrome/msedge w/ PROCESS_VM_READ (0x10) # Evasion Zw-prefixed direct ntdll syscalls; dynamic API resolution (no IAT); XOR-encrypted config; mutex sandbox check (exit if marker present) # Files read %LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data %LOCALAPPDATA%\Google\Chrome\User Data\Local State
# Intermediate C2 citrusshop.icu # Dead-drop resolver (C2 address embedded in display name) steamcommunity.com -> SteamID 76561199877608270 # Hunt: JSON POST to newly-registered / low-reputation domains # Hunt: steamcommunity.com or Telegram API from server / non-gaming endpoints
# Assume cookies + creds stolen on any hit (ABE bypassed at user level) 1. Invalidate all browser/SSO sessions for the user (force re-auth) 2. Rotate saved browser passwords + any MFA seeds stored in browser 3. Review IdP sign-ins for cookie replay (new ASN/geo, no MFA challenge) 4. Rotate crypto wallet seed phrases / move funds if wallet artifacts read 5. Reset Telegram/Discord/FTP tokens flagged in Q6
Detection Validation Gates
- Telemetry ready: Confirm ProcessRollup2 CommandLine capture is enabled and FileOpenInfo flows; deploy Sysmon EID 10 to cover the memory-read step that direct syscalls can hide.
- Benign baseline: Run Q2/Q3/Q6/Q7 for 7 days; catalog legitimate browser automation, backup/password agents, and Steam usage; build exclusions.
- Positive tests: Launch
chrome.exe --window-position=-32000,-32000 --no-sandboxfrom a script to confirm Q1; readLocal Statewith a non-browser test tool to confirm Q3. - Promotion: Q1 and Q5 → Custom IOA/IOC first; Q3 → Detect after baselining approved key-store readers.
Hardening — Tiered & Deployable
- Block known IOCs (M1031): add
citrusshop.icuto DNS/proxy denylist and the SHA-256 to Falcon prevent. - Treat hits as session theft (M1027): run the post-theft identity audit (s10) — invalidate sessions and rotate, since ABE was bypassed at user level.
- Sysmon ProcessAccess rule (M1040): deploy EID 10 logging for non-browser
PROCESS_VM_READon chrome/msedge.
- Disable browser password storage (M1042): enforce
PasswordManagerEnabled=0via Chrome/Edge policy so there are no saved creds to decrypt; steer users to a managed vault. - Phishing-resistant MFA (M1032): FIDO2/passkeys blunt stolen-cookie replay; shorten session lifetimes and bind sessions to device where possible.
- Restrict debug rights (M1026): audit/limit
SeDebugPrivilegeassignment; alert on non-admin processes acquiring it.
- Token binding / continuous access eval (M1015): adopt device-bound sessions / CAE so a cookie lifted off one endpoint can't be replayed elsewhere.
- App control (M1038): WDAC/AppLocker allowlisting to block unsigned MaaS payloads at execution.
- Browser ABE roadmap (⚠ best-practice): track Chrome/Edge ABE hardening updates and deploy promptly; report this debugger bypass to the browser vendor channel.
Deployable Playbooks
1 · Disable browser password manager (Chrome/Edge GPO registry)
# HKLM policies - removes saved creds VoidStealer would decrypt reg add "HKLM\SOFTWARE\Policies\Google\Chrome" /v PasswordManagerEnabled /t REG_DWORD /d 0 /f reg add "HKLM\SOFTWARE\Policies\Microsoft\Edge" /v PasswordManagerEnabled /t REG_DWORD /d 0 /f
2 · Sysmon ProcessAccess rule for browser memory reads
<Sysmon schemaversion="4.90">
<EventFiltering>
<RuleGroup groupRelation="or">
<ProcessAccess onmatch="include">
<TargetImage condition="end with">chrome.exe</TargetImage>
<TargetImage condition="end with">msedge.exe</TargetImage>
</ProcessAccess>
</RuleGroup>
</EventFiltering>
</Sysmon>
<!-- Then alert where SourceImage is NOT a browser and GrantedAccess includes 0x10 (PROCESS_VM_READ) -->
3 · Block C2 at the proxy (Squid example)
# /etc/squid/voidstealer.acl acl void_c2 dstdomain citrusshop.icu http_access deny void_c2
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain any host matching Q1/Q3/Q5; capture volatile memory before reboot (grab-and-go leaves little on disk) | SOC / IR | Falcon detections, memory image |
| Eradicate | Kill + remove the stealer binary; confirm grab-and-go left no persistence (it usually doesn't) but check for the dropper/loader | IR | Removed artifacts |
| Invalidate sessions | Force-expire all browser/SSO sessions for the user; rotate saved passwords, wallet seeds, Telegram/Discord/FTP tokens (s10 audit) | IR / IAM | Session revocation logs, rotation tickets |
| Hunt replay | Review IdP sign-ins for stolen-cookie replay (new ASN/geo, no MFA); contain affected SaaS accounts | IR / IAM | Sign-in logs |
| Recover | Rebuild if loader chain uncertain; re-enable browser policy hardening; user awareness on delivery vector | Endpoint | Rebuild records |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1555.003 | Hidden-browser ABE bypass | Q1, Q3 | Q1, Q3 | Good |
| T1622 | Debugger attach to browser | Q2, s7 (Sysmon EID 10) | — | Partial |
| T1539 | Cookie/session theft | Q3 | Q3 | Partial |
| T1552.001 | Wallet / token grab | Q6 | — | Partial |
| T1102.001 / T1567 | Steam dead-drop + exfil | Q4, Q7 | Q4 (domain) | Good |
| (known sample) | VoidStealer v2.0 hash | Q5 | Q5 | Good |
| T1106 / T1027.007 | Direct syscalls / dynamic API resolution | — | — | GAP |
Validation: The behavioral chain (hidden browser → key-store read → C2) is well covered and promotable. The residual gap is the userland-hook-evading syscall layer — close it with Sysmon EID 10 (memory-read visibility) and IdP-side cookie-replay hunting (s7) rather than relying on EDR API hooks alone.
Hunt Summary Ticket
TITLE: VoidStealer v2.0 - debugger-based Chrome ABE bypass (MaaS infostealer)
SEVERITY: High - user-level cookie + credential + wallet theft, defeats ABE
SCOPE: Windows endpoints with Chromium/Gecko browsers; IdP/SaaS sessions
HYPOTHESIS: Stealer launches browser hidden off-screen, debugs it, reads v20_master_key
from a register via HW breakpoint, decrypts Login Data + cookies, exfils via
Steam dead-drop / citrusshop.icu, then exits
QUERIES: Q1 hidden browser | Q2 anomalous parent | Q3 key-store read | Q4 C2 DNS |
Q5 known hash | Q6 wallet/token sweep | Q7 Steam dead-drop
DO FIRST: Run Q1 + Q5; deploy Sysmon EID 10 for browser PROCESS_VM_READ
FINDINGS: <fill on triage>
GAPS: direct-syscall/dynamic-API layer (cover via Sysmon EID 10 + IdP replay hunt)
ACTIONS: Block IOCs, invalidate sessions + rotate (assume theft), disable browser PW mgr
OWNER: <analyst>
VERSION: v0.1 · 2026-06-22
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used For | Access Date |
|---|---|---|---|
| 1 | Gen Digital — VoidStealer: Debugging Chrome to Steal Its Secrets | Debugger-bypass chain, APIs, SHA-256, target paths | 2026-06-22 |
| 1 | SOCRadar — Void Stealer: The Infostealer Quietly Targeting Organizations in 2026 | MaaS model, syscall evasion, Steam dead-drop, C2 domain, launch flags | 2026-06-22 |
| 2 | Kaspersky — Chrome ABE bypass (VoidStealer) | ABE-bypass corroboration | 2026-06-22 |
| Ref | MITRE ATT&CK T1555.003 | Technique mapping | 2026-06-22 |