ToddyCat — Umbrij .NET Backdoor & the Shadow Token via Remote Debug (STRD) Technique

Asia-nexus espionage actor stealing Gmail / Google Workspace mail by driving a headless browser's remote-debugging port to mint OAuth tokens · analysed by Kaspersky Securelist, July 2026
Threat
ToddyCat / Umbrij (STRD)
Severity
ACTIVE APT
Type
Nation-state backdoor / OAuth token theft
Access
Post-compromise (on-host tool)
Version
v0.2 · 2026-07-04
Author
HuntPack
Confidence
High (vendor-attributed)
01

Executive Summary

Umbrij is a .NET DLL backdoor (ConfuserEx-obfuscated) attributed by Kaspersky to ToddyCat, an Asia-nexus espionage actor known for targeting high-profile government and defence entities across Europe and Asia. Umbrij is purpose-built for one thing: surreptitiously reading a victim's Gmail / Google Workspace mailbox without ever needing the account password.

The novel tradecraft — which Kaspersky names Shadow Token via Remote Debug (STRD) — works by copying the victim's live browser profile, then launching Chrome/Edge in --headless mode with a --remote-debugging-port. Umbrij drives that debug port through PuppeteerSharp (the .NET Chrome DevTools Protocol library) to visit a Google OAuth URL for a legitimate Google Workspace migration client_id (GWMMO 279448736670, or GWSMO 1095133494869 with the -sync switch). Because the copied profile is still signed in, Google issues an authorization code with no password prompt; Umbrij exchanges it for an access token and reads mail via the Google API (scopes include https://mail.google.com/, gmail.insert, gmail.labels, drive, and admin.directory.user).

Umbrij is delivered by DLL side-loading: legitimate signed hosts (GoogleDesktop.exe, BDSubWiz.exe, VSTestVideoRecorder.exe) are dropped to user-writable staging paths (C:\Users\Public, C:\Windows\Vss, C:\Windows\Temp) alongside a malicious companion DLL (GoogleServices.DLL, log.dll, or the VideoRecorderEngine DLL). The launcher accepts switches such as -regex (find a target user by email substring), -browser, -debugport, -sync, and -deepsearch. Persistence is a scheduled task masquerading as KasperskyEndpointSecurityEDRAvp.

Defender priority: The highest-value, lowest-FP angles are a browser launched with both --remote-debugging-port and --headless (especially with --user-data-dir pointing at a BackupFiles copy), the three DLL-sideload host binaries running from Public/Vss/Temp, the Kaspersky-published Umbrij hashes, and the KasperskyEndpointSecurityEDRAvp scheduled task. Enforce Chrome policy DeveloperToolsAvailability=2 to break the remote-debug primitive outright.

02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry Fwd
1 · VendorKaspersky Securelist — "How the ToddyCat APT group gains access to Gmail accounts" (2026-07-02)Primary technical analysis: Umbrij .NET backdoor, STRD technique, PuppeteerSharp/CDP remote-debug flow, OAuth client_ids & scopes, DLL-sideload trios, MD5 hashes, scheduled-task persistence, Chrome-policy mitigationyes
2 · PressThe Hacker News — "ToddyCat-Linked Umbrij Malware Abuses OAuth to Access Gmail via Google API" (2026-07-02)Corroborates STRD, PuppeteerSharp usage, session-riding (no password needed), migration-tool client_id abusepartial
2 · PressGBHackers / CyberPress — ToddyCat "Shadow Token" & ConfuserEx toolingConfirm ConfuserEx obfuscation, headless remote-debug port, automated Gmail compromisepartial

Every atomic IOC below (MD5 hashes, host/DLL filenames, install paths, OAuth client_ids, scheduled-task name) traces to the Kaspersky Securelist indicator set. The OAuth client_ids and Google scopes are behavioural constants of the technique; the sideloaded filenames and staging paths are durable, while the debug-port number (e.g. 11111) is arbitrary and should be treated as illustrative, not a fixed indicator.

03

Hunt Brief & Attack Chain

Hunt hypotheses (fidelity-ordered)

  1. H1 (high): A browser was launched with both --remote-debugging-port and --headless — the core STRD primitive. Covers T1550.001 / T1528.
  2. H2 (high): A headless remote-debug browser used --user-data-dir pointing at a copied profile (BackupFiles). STRD profile-clone tell.
  3. H3 (high): One of the three DLL-sideload host binaries executed from C:\Users\Public, C:\Windows\Vss, or C:\Windows\Temp. Covers T1574.001.
  4. H4 (high): A file matching a Kaspersky-published Umbrij / sideloaded-DLL hash executed or was written. Atomic.
  5. H5 (high): A scheduled task named KasperskyEndpointSecurityEDRAvp was registered. Covers T1053.005 masquerade.
  6. H6 (high): An Umbrij launcher ran with STRD switches (-regex + -deepsearch / -debugport / -browser). Command-line tell.
  7. H7 (medium): A non-browser parent spawned a headless remote-debug browser. Catches renamed/unknown host binaries.
  8. H8 (medium): A sideload host binary or headless browser resolved accounts.google.com for the OAuth code exchange. Covers T1114 / T1071.001.

Attack chain

StepBehaviorTelemetryHunt Angle
1 · DeliveryDLL side-load: signed host (GoogleDesktop/BDSubWiz/VSTestVideoRecorder) + malicious DLL dropped to Public/Vss/TempProcessRollup2, PeFileWrittenQ3, Q4
2 · ExecutionUmbrij launcher runs with -regex / -browser / -debugport / -deepsearch to pick a target userProcessRollup2Q6
3 · Profile cloneCopies live Chrome/Edge profile (Login Data, Local State, Web Data) into a BackupFiles dirFileCreateInfo / PeFileWrittenQ2 (via user-data-dir), native hunts
4 · STRDLaunches browser --headless --remote-debugging-port; PuppeteerSharp drives CDP to Google OAuth URLProcessRollup2Q1, Q2, Q7
5 · Token mintRides signed-in session → authorization code for GWMMO/GWSMO client_id → access tokenDnsRequest, NetworkConnectIP4Q8
6 · CollectionReads mailbox via Google API (mail.google.com, gmail.insert, drive scopes)NetworkConnectIP4 (API egress)Q8, native hunts
7 · PersistenceScheduled task masquerading as KasperskyEndpointSecurityEDRAvpScheduledTaskRegisteredQ5
04

Consolidated IOC Table

All values published by Kaspersky Securelist. Hashes and sideloaded filenames are durable; the debug-port number is arbitrary (illustrative 11111). Validate against your own retention window before bulk-blocking, and note the host binaries are legitimate signed files abused only when they run from user-writable staging paths.

TypeValueConfActionContext
md51AB58838E5790EFB22F2D35AB98C0B7DhighdetectUmbrij (ver. a)
md5A7D7D6C4C3F227F7117261C63B9E23A9highdetectUmbrij (ver. a)
md53D3A621F852C42D97FD7260681E42508highdetectUmbrij (ver. a)
md53432DD9AC0DF80EF86EB80BD080F839BhighdetectUmbrij (ver. a)
md522AAEB4946BA6D2F2E27FEB7DBB295DEhighdetectUmbrij (ver. b)
md5F61FBFB7AA1CD5DC8F70B055B51563E2highdetectUmbrij (ver. b)
md5F169D6D172DFB775895A5E2B1540C854highdetectUmbrij (ver. c)
md59F5F2F0FB0A7F5AA9F16B9A7B6DAD89FhighdetectGoogleServices.DLL (sideloaded)
md528CB7B261F4EB97E8A4B3B0D32F8DEF1highdetectlog.dll (sideloaded)
md5BAE82A15D1DBFB024617B9B56A8E5F66highdetectVideoRecorderEngine.dll (sideloaded)
filenameGoogleDesktop.exe / BDSubWiz.exe / VSTestVideoRecorder.exe (from Public/Vss/Temp)highhuntDLL-sideload host binaries
pathC:\Users\Public\ , C:\Windows\Vss\ , C:\Windows\Temp\highhuntstaging / execution paths
taskKasperskyEndpointSecurityEDRAvphighhuntscheduled-task persistence (masquerade)
oauthclient_id 279448736670 (GWMMO) / 1095133494869 (GWSMO)highhuntWorkspace migration app abused for token mint
behaviorbrowser --headless --remote-debugging-port (STRD)highdetectcore technique primitive
05

Affected Surface & Telemetry Matrix

SurfaceRequired TelemetryPriorityGap Risk
Windows endpoints (Chrome/Edge + .NET present)ProcessRollup2 / SyntheticProcessRollup2CriticalLow — default Falcon coverage
File writes (profile clone / sideloaded DLL)PeFileWritten / FileCreateInfoHighLow
Scheduled tasksScheduledTaskRegisteredHighLow
DNS / egress (OAuth code exchange, Google API)DnsRequest, NetworkConnectIP4MedHigh — accounts.google.com is ubiquitous; only useful scoped to a suspicious parent
Google Workspace (identity side)Workspace Admin login/token audit logsMedHigh — not in Falcon EDR; needs Workspace telemetry (§7)
06

ATT&CK Mapping

TacticTechniqueObserved BehaviorCoverage
Defense EvasionT1574.001 DLL Side-LoadingSigned host (GoogleDesktop/BDSubWiz/VSTestVideoRecorder) loads malicious companion DLLQ3, Q4
Defense EvasionT1036.005 Masquerading: Match Legitimate NameScheduled task named KasperskyEndpointSecurityEDRAvp; migration-app client_id reuseQ5
Credential AccessT1528 Steal Application Access TokenOAuth authorization code minted from a signed-in sessionQ1, Q2, Q7
Defense Evasion / LateralT1550.001 Use Alternate Auth Material: App Access TokenRides existing Gmail session; no password neededQ1, Q8
Privilege EscalationT1134.003 Make and Impersonate TokenRuns browser in a targeted user's context (-user / -regex)Q6
PersistenceT1053.005 Scheduled TaskKasperskyEndpointSecurityEDRAvp taskQ5
CollectionT1114 Email CollectionReads mailbox via Google API (mail.google.com / gmail scopes)Q8, native hunts
Command & ControlT1071.001 Web ProtocolsOAuth code exchange + Google API over HTTPSQ8
07

Native Audit-Log Hunts (non-CQL)

  • Google Workspace Admin — Token audit: In the Admin console, review OAuth token grants and app activity for the migration apps Google Workspace Migration for Microsoft Outlook (client_id 279448736670) and Google Workspace Sync for Microsoft Outlook (1095133494869). Legitimate use is rare and admin-driven; unexpected grants tied to a workstation IP are the identity-side tell.
  • Google Workspace — Login audit: Hunt for API access to Gmail from a localhost redirect flow or new device/session immediately after an endpoint alert; users can self-audit at myaccount.google.com/connections.
  • Chrome/Edge policy state: Confirm DeveloperToolsAvailability is enforced (value 2 = disabled) via GPO/MDM reporting; any host where it is unset is exposed to STRD.
  • Scheduled task inventory: Sweep for a task literally named KasperskyEndpointSecurityEDRAvp on hosts that do not run Kaspersky (the name is a masquerade).
  • File-system sweep: Look for a BackupFiles directory under %LOCALAPPDATA%\Google\Chrome or %LOCALAPPDATA%\Microsoft\Edge — Umbrij's copied-profile staging folder.
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
Q1 · Browser headless + remote-debugging port (STRD core)
CONF HIGHFP LOWCOST LOW

Looks for: a Chromium-based browser launched with both --remote-debugging-port and --headless — the STRD primitive Umbrij needs to drive the DevTools protocol. Very rare on user workstations.

// HUNT: Headless browser with a remote-debugging port (STRD)
// MITRE: T1528, T1550.001
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
// FALSE POSITIVES: rare — some automated testing/CI harnesses; scope out known runners
// TUNING: exclude sanctioned QA/automation hosts and puppeteer-based CI agents
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(chrome|msedge|brave|chromium)\.exe$/i
| CommandLine=/--remote-debugging-port/i
| CommandLine=/--headless/i
| table([@timestamp, aid, ComputerName, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Q2 · Remote-debug browser pointed at a cloned profile (BackupFiles)
CONF HIGHFP LOWCOST LOW

Looks for: a remote-debug browser whose --user-data-dir points at a copied-profile BackupFiles folder — Umbrij clones the live profile so the debug session inherits the signed-in Google cookies. Near-zero FP.

// HUNT: STRD browser using a cloned profile (BackupFiles user-data-dir)
// MITRE: T1528, T1550.001, T1539
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(chrome|msedge|brave|chromium)\.exe$/i
| CommandLine=/--remote-debugging-port/i
| CommandLine=/--user-data-dir=.{0,120}BackupFiles/i
| table([@timestamp, aid, ComputerName, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Q3 · DLL-sideload host binaries from user-writable staging paths
CONF HIGHFP LOWCOST LOW

Looks for: the three signed host binaries Umbrij abuses running from C:\Users\Public, C:\Windows\Vss, or C:\Windows\Temp — legitimate files in illegitimate locations.

// HUNT: Umbrij DLL-sideload host binaries from staging paths
// MITRE: T1574.001
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
// FALSE POSITIVES: none expected — these binaries do not normally live in Public/Vss/Temp
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(GoogleDesktop|BDSubWiz|VSTestVideoRecorder|bds)\.exe$/i
| FilePath=/\\(Users\\Public|Windows\\Vss|Windows\\Temp)\\/i
| table([@timestamp, aid, ComputerName, UserName, FileName, FilePath, CommandLine, ParentBaseFileName], limit=200)
Q4 · Kaspersky-published Umbrij / sideloaded-DLL hashes
CONF HIGHFP LOWCOST LOW

Looks for: execution or write of any Kaspersky-listed Umbrij or sideloaded-DLL MD5. Atomic — promote straight to a Custom IOC block (see §10).

// HUNT: Umbrij / sideloaded-DLL known-bad MD5 hashes (Kaspersky)
// MITRE: T1574.001, T1528
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2 / PeFileWritten
#event_simpleName=/ProcessRollup2|PeFileWritten|NewExecutableWritten/
| in(MD5HashData, values=["1AB58838E5790EFB22F2D35AB98C0B7D", "A7D7D6C4C3F227F7117261C63B9E23A9", "3D3A621F852C42D97FD7260681E42508", "3432DD9AC0DF80EF86EB80BD080F839B", "22AAEB4946BA6D2F2E27FEB7DBB295DE", "F61FBFB7AA1CD5DC8F70B055B51563E2", "F169D6D172DFB775895A5E2B1540C854", "9F5F2F0FB0A7F5AA9F16B9A7B6DAD89F", "28CB7B261F4EB97E8A4B3B0D32F8DEF1", "BAE82A15D1DBFB024617B9B56A8E5F66"])
| table([@timestamp, aid, ComputerName, UserName, FileName, FilePath, MD5HashData], limit=max)
Q5 · Scheduled task masquerading as KasperskyEndpointSecurityEDRAvp
CONF HIGHFP LOWCOST LOW

Looks for: registration of a scheduled task named KasperskyEndpointSecurityEDRAvp — Umbrij's persistence masquerade. On any host without a genuine Kaspersky install this is a strong signal.

// HUNT: Umbrij scheduled-task persistence (Kaspersky EDR masquerade)
// MITRE: T1053.005, T1036.005
// CONF: high  FP: low  COST: low | REQUIRES: ScheduledTaskRegistered
// TUNING: on genuine Kaspersky fleets, confirm the task's backing executable path is legitimate
#event_simpleName=/ScheduledTaskRegistered/
| TaskName=/KasperskyEndpointSecurityEDRAvp/i
| table([@timestamp, aid, ComputerName, UserName, TaskName, TaskExecutable], limit=200)
Q6 · Umbrij launcher command-line switches
CONF HIGHFP MEDCOST LOW

Looks for: a process invoked with the distinctive Umbrij switch pairing — a -regex user selector alongside -deepsearch, -debugport, or -browser. FP: generic -regex exists in other tools; the pairing with browser/debug switches is what makes this specific.

// HUNT: Umbrij launcher switches (-regex + -deepsearch/-debugport/-browser)
// MITRE: T1134.003, T1528
// CONF: high  FP: medium  COST: low | REQUIRES: ProcessRollup2
// FALSE POSITIVES: unrelated CLI tools that accept a -regex flag
// TUNING: require the -regex + browser/debug pairing (below); exclude sanctioned admin scripts
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| CommandLine=/\s-regex\s/i
| CommandLine=/\s-(deepsearch|debugport|browser|sync)\b/i
| table([@timestamp, aid, ComputerName, UserName, FileName, FilePath, CommandLine, ParentBaseFileName], limit=200)
Q7 · Non-browser parent spawns a headless remote-debug browser
CONF MEDFP MEDCOST LOW

Looks for: a headless remote-debug browser whose parent is not a normal browser/updater — catches Umbrij even under a renamed host binary. FP: automation frameworks (node.exe, python.exe) legitimately launch headless Chrome — exclude sanctioned CI/QA parents.

// HUNT: Headless remote-debug browser launched by a non-browser parent
// MITRE: T1528, T1574.001
// CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2
// FALSE POSITIVES: node/python automation harnesses driving Puppeteer/Playwright
// TUNING: exclude approved automation parents and CI runner hosts
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(chrome|msedge|brave|chromium)\.exe$/i
| CommandLine=/--remote-debugging-port/i
| ParentBaseFileName!=/^(chrome|msedge|brave|chromium|explorer|GoogleUpdate|MicrosoftEdgeUpdate|services)\.exe$/i
| table([@timestamp, aid, ComputerName, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Q8 · OAuth code-exchange DNS from a sideload host / headless browser
CONF MEDFP MEDCOST MED

Looks for: DNS to accounts.google.com / oauth2.googleapis.com initiated by one of the sideload host binaries (not the real browser) — the token-mint egress. FP: these domains are ubiquitous, so this query is scoped by ContextBaseFileName to the abused hosts; broaden only during active IR.

// HUNT: OAuth token-mint DNS from an Umbrij sideload host binary
// MITRE: T1114, T1071.001, T1550.001
// CONF: medium  FP: medium  COST: medium | REQUIRES: DnsRequest
// FALSE POSITIVES: accounts.google.com is common — scoping to the host binaries keeps it tight
// TUNING: during IR, drop the ContextBaseFileName filter to see all OAuth egress on a suspect host
#event_simpleName=DnsRequest
| DomainName=/^(accounts\.google\.com|oauth2\.googleapis\.com)$/i
| ContextBaseFileName=/^(GoogleDesktop|BDSubWiz|VSTestVideoRecorder|bds)\.exe$/i
| table([@timestamp, aid, ComputerName, DomainName, ContextBaseFileName], limit=200)
Q9 · Chromium browser executing from a staging path
CONF HIGHFP LOWCOST LOW

Looks for: a Chrome/Edge binary running from Public/Vss/Temp rather than Program Files — a portable browser Umbrij can drop to guarantee a debuggable instance. Distinctive path → very low FP.

// HUNT: Chromium browser running from a user-writable staging path
// MITRE: T1528, T1574.001
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(chrome|msedge|brave|chromium)\.exe$/i
| FilePath=/\\(Users\\Public|Windows\\Vss|Windows\\Temp)\\/i
| table([@timestamp, aid, ComputerName, UserName, FileName, FilePath, CommandLine], limit=200)
09

CrowdStrike Custom IOA Recommendations

IOA NamePatternActionExclusions
STRD — Headless Remote-Debug BrowserChromium image with --remote-debugging-port + --headless (Q1)Detect (high)Sanctioned QA/CI automation hosts
Umbrij — Sideload Host in Staging PathGoogleDesktop/BDSubWiz/VSTestVideoRecorder from Public/Vss/Temp (Q3)Detect → Block (after baseline)None expected — abnormal location
Umbrij — EDR-Masquerade TaskScheduledTaskRegistered TaskName KasperskyEndpointSecurityEDRAvp (Q5)Detect (high)Genuine Kaspersky fleets — verify backing path
Umbrij — Launcher Switches-regex + -deepsearch/-debugport/-browser (Q6)Detect (medium)Sanctioned admin scripts using -regex

Promotion path: validate the high-CONF/low-FP queries (Q1, Q3, Q5) against 7–14 days of baseline, confirm zero benign hits, then promote to Custom IOAs in detect mode; escalate Q3 to block once clean. Q4 hashes → Custom IOC Management (block).

10

Machine-Readable IOC Appendix

One-click blocks for SOC tooling. Hashes are Kaspersky-published; swap expirations to fit your policy. Note the host EXEs are legitimate signed binaries — hunt on location/behaviour, do not blanket-block by name.

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
md5,1AB58838E5790EFB22F2D35AB98C0B7D,prevent,critical,2026-12-31,Umbrij ver.a,actor:ToddyCat;tool:Umbrij
md5,A7D7D6C4C3F227F7117261C63B9E23A9,prevent,critical,2026-12-31,Umbrij ver.a,actor:ToddyCat;tool:Umbrij
md5,3D3A621F852C42D97FD7260681E42508,prevent,critical,2026-12-31,Umbrij ver.a,actor:ToddyCat;tool:Umbrij
md5,3432DD9AC0DF80EF86EB80BD080F839B,prevent,critical,2026-12-31,Umbrij ver.a,actor:ToddyCat;tool:Umbrij
md5,22AAEB4946BA6D2F2E27FEB7DBB295DE,prevent,critical,2026-12-31,Umbrij ver.b,actor:ToddyCat;tool:Umbrij
md5,F61FBFB7AA1CD5DC8F70B055B51563E2,prevent,critical,2026-12-31,Umbrij ver.b,actor:ToddyCat;tool:Umbrij
md5,F169D6D172DFB775895A5E2B1540C854,prevent,critical,2026-12-31,Umbrij ver.c,actor:ToddyCat;tool:Umbrij
md5,9F5F2F0FB0A7F5AA9F16B9A7B6DAD89F,prevent,critical,2026-12-31,GoogleServices.DLL sideload,actor:ToddyCat;tool:Umbrij
md5,28CB7B261F4EB97E8A4B3B0D32F8DEF1,prevent,critical,2026-12-31,log.dll sideload,actor:ToddyCat;tool:Umbrij
md5,BAE82A15D1DBFB024617B9B56A8E5F66,prevent,critical,2026-12-31,VideoRecorderEngine.dll sideload,actor:ToddyCat;tool:Umbrij
Behavioral Signatureshunt logic
[ Umbrij / STRD behaviors ]
- Browser launched with --headless AND --remote-debugging-port
- --user-data-dir pointing at a *\BackupFiles\* cloned profile
- GoogleDesktop.exe / BDSubWiz.exe / VSTestVideoRecorder.exe / bds.exe
  running from C:\Users\Public, C:\Windows\Vss, or C:\Windows\Temp
- Sideloaded DLL: GoogleServices.DLL / log.dll / VideoRecorderEngine.dll
- Launcher switches: -regex + -deepsearch / -debugport / -browser / -sync
- Scheduled task named KasperskyEndpointSecurityEDRAvp
- OAuth code exchange for client_id 279448736670 or 1095133494869
- Non-browser parent spawning a headless remote-debug Chrome/Edge
Named Malware / Toolingattribution
Actor:   ToddyCat (Asia-nexus espionage APT)
Implant: Umbrij (.NET DLL, ConfuserEx-obfuscated)
         Verdicts: HEUR:Trojan-PSW.MSIL.Umbrij.gen
                   HEUR:Trojan.MSIL.Agent.gen
Technique: STRD - Shadow Token via Remote Debug
Library:  PuppeteerSharp (Chrome DevTools Protocol)
OAuth:    GWMMO client_id 279448736670
          GWSMO client_id 1095133494869 (-sync)
Scopes:   mail.google.com, gmail.insert, gmail.labels,
          drive, admin.directory.user
Workspace / Policy Auditprevent checklist
[ ] Chrome/Edge policy DeveloperToolsAvailability = 2 (disabled) enforced
[ ] Workspace: restrict/deny GWMMO (279448736670) & GWSMO (1095133494869)
[ ] Workspace: review OAuth token grants + localhost-redirect API access
[ ] Scheduled-task sweep for KasperskyEndpointSecurityEDRAvp
[ ] WDAC/AppLocker blocks EXEs under C:\Users\Public, \Windows\Vss, \Windows\Temp
[ ] ASR: block credential stealing / LSASS + audit DLL side-loading hosts
[ ] Users audit third-party access at myaccount.google.com/connections
11

Detection Validation Gates

  • Telemetry ready: Confirm ProcessRollup2, ScheduledTaskRegistered, PeFileWritten, and DnsRequest are flowing from in-scope Windows hosts running Chrome/Edge.
  • Benign baseline: Run Q1 and Q7 (headless remote-debug) over 7–14 days; record any sanctioned Puppeteer/Playwright CI or QA hosts, and exclude those parents before alerting.
  • Positive test: In a lab, launch chrome.exe --headless --remote-debugging-port=9222 --user-data-dir=C:\Temp\BackupFiles and confirm Q1 and Q2 fire; register a task named KasperskyEndpointSecurityEDRAvp and confirm Q5 fires.
  • Promotion: Only promote Q1/Q3/Q5 to detect/block after zero benign hits across the baseline window.
12

Hardening — Tiered & Deployable

Immediate (this week — low risk)
  • Enforce Chrome/Edge DeveloperToolsAvailability = 2 via GPO/MDM — disables DevTools and the remote-debugging primitive STRD depends on. (MITRE M1042 Disable or Remove Feature.)
  • Restrict the Workspace migration apps (GWMMO 279448736670, GWSMO 1095133494869) to trusted admins in Google Admin console API controls, or block them outright if unused. (M1018 User Account Management.)
  • Sweep + alert on the KasperskyEndpointSecurityEDRAvp task across the fleet. (M1047 Audit.)
Near term (1–4 weeks — pilot first)
  • WDAC/AppLocker: block execution of binaries under C:\Users\Public, C:\Windows\Vss, and C:\Windows\Temp (deny-by-path). (M1038 Execution Prevention.)
  • Audit DLL side-loading hosts: alert when GoogleDesktop/BDSubWiz/VSTestVideoRecorder load a DLL from a non-standard directory. (M1052 User Account Control / M1038.)
  • Enforce phishing-resistant MFA and re-auth for OAuth grants in Google Workspace so a stolen cookie alone cannot mint high-scope tokens. (M1032 Multi-factor Authentication.)
Strategic (1–3 months — architectural)
  • Context-aware access / device trust in Workspace so API sessions from unmanaged or anomalous device contexts are denied. (M1035 Limit Access to Resource Over Network.)
  • Application allow-listing for OAuth apps (block unverified/unneeded third-party and migration apps org-wide). (M1018.)
  • Least-privilege on admin scopes — restrict admin.directory.user and Drive-wide scopes to a minimal, monitored admin set. (M1026 Privileged Account Management.)
13

Deployable Playbooks

P1 · Enforce Chrome DeveloperToolsAvailability = 2 (disable DevTools / remote debug)

# HKLM policy (applies to all users; Edge uses ...\Policies\Microsoft\Edge)
New-Item -Path 'HKLM:\SOFTWARE\Policies\Google\Chrome' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Google\Chrome' `
  -Name 'DeveloperToolsAvailability' -Type DWord -Value 2
New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' `
  -Name 'DeveloperToolsAvailability' -Type DWord -Value 2
# Verify:
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Google\Chrome' -Name DeveloperToolsAvailability

P2 · Hunt the KasperskyEndpointSecurityEDRAvp scheduled task

$t = Get-ScheduledTask -TaskName 'KasperskyEndpointSecurityEDRAvp' -ErrorAction SilentlyContinue
if ($t) {
  $a = $t.Actions | Select-Object Execute, Arguments
  [pscustomobject]@{ Host=$env:COMPUTERNAME; Found=$true; Exec=$a.Execute; Args=$a.Arguments }
} else {
  [pscustomobject]@{ Host=$env:COMPUTERNAME; Found=$false }
}

P3 · Flag Chromium binaries / EXEs running from staging paths

$dirs = 'C:\Users\Public','C:\Windows\Vss','C:\Windows\Temp'
foreach ($d in $dirs) {
  if (Test-Path $d) {
    Get-ChildItem -Path $d -Filter *.exe -Recurse -ErrorAction SilentlyContinue |
      Where-Object { $_.Name -match '^(chrome|msedge|brave|chromium|GoogleDesktop|BDSubWiz|VSTestVideoRecorder|bds)\.exe$' } |
      Select-Object FullName, Length, LastWriteTime
  }
}

P4 · Locate cloned-profile BackupFiles staging folders

$roots = @(
  "$env:LOCALAPPDATA\Google\Chrome",
  "$env:LOCALAPPDATA\Microsoft\Edge"
)
foreach ($r in $roots) {
  if (Test-Path $r) {
    Get-ChildItem -Path $r -Directory -Filter 'BackupFiles' -ErrorAction SilentlyContinue |
      Select-Object FullName, CreationTime
  }
}
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain the host in Falcon; preserve memory, the BackupFiles profile copy, and the staging directories; do NOT reboot (lose volatile token/CDP state).SOCRTR capture, process tree, netconns
EradicateRemove the KasperskyEndpointSecurityEDRAvp task; delete sideloaded host+DLL pairs and the cloned profile; block Umbrij hashes (Q4).IRTask diff, deleted-file hashes
Identity recoveryIn Google Workspace: revoke the user's OAuth tokens/sessions, force password reset + re-MFA, and revoke the GWMMO/GWSMO grants; review Gmail rules/labels for tampering (gmail.insert scope).IR + IdPWorkspace token-revocation log
Hunt-backSweep the fleet with Q1–Q9; pivot on the sideloaded-DLL hashes and any host with a BackupFiles clone or the masquerade task; review Workspace audit for other abused mailboxes.Threat HuntFleet query results, Workspace audit
15

Detection Coverage Map

TechniqueBehaviorCQLIOACoverage
T1528 / T1550.001Headless remote-debug browser (STRD)Q1, Q2YesGood
T1574.001DLL-sideload host in staging pathQ3, Q9YesGood
Atomic hashesKnown-bad Umbrij / DLL filesQ4IOCGood
T1053.005EDR-masquerade scheduled taskQ5YesGood
T1134.003Umbrij launcher switchesQ6YesPartial (FP-tuned)
T1528 (evasion)Non-browser parent → headless browserQ7Partial
T1114 / T1071.001OAuth token-mint egressQ8Partial (scoped)
Profile cloneLive browser-profile copyQ2 (via user-data-dir)Partial — full file-copy detection needs FileCreateInfo hunt (§7)
Identity sideWorkspace token grant / API readGap — out of EDR scope; covered by Workspace audit (§7)

Detection is strongest at the STRD primitive (headless + remote-debug), DLL-sideload location, atomic hashes, and the masquerade task — all low-FP. The launcher-switch and non-browser-parent hunts need environment tuning for automation frameworks. The mailbox-read itself happens in Google's cloud and is a gap best covered upstream via Workspace token/login audit (§7).

16

Hunt Summary Ticket

TITLE:      ToddyCat Umbrij / STRD OAuth-token backdoor hunt
SEVERITY:   Critical - active nation-state espionage (mailbox theft)
SCOPE:      Windows endpoints (Chrome/Edge + .NET); DNS/egress;
            Google Workspace identity audit
HYPOTHESIS: ToddyCat ran Umbrij to clone a signed-in browser profile,
            drive a headless --remote-debugging-port session via
            PuppeteerSharp, and mint a Google OAuth token to read mail.
QUERIES:    Q1 headless+debug | Q2 BackupFiles profile | Q3 sideload
            hosts | Q4 hashes | Q5 EDR-masq task | Q6 launcher switches
            Q7 non-browser parent | Q8 OAuth egress | Q9 browser in staging
DO FIRST:   Q1, Q3, Q5 (lowest FP, structural) then Q4, Q2.
FINDINGS:   <record hosts / hashes / tasks / Workspace grants here>
GAPS:       Mailbox read in Google cloud; profile file-copy (use §7).
ACTIONS:    Enforce DeveloperToolsAvailability=2; restrict GWMMO/GWSMO;
            block Q4 hashes; revoke tokens + re-MFA; isolate + IR
            confirmed hosts.
OWNER:      HuntPack
VERSION:    v0.2 · 2026-07-04
17

Changelog

v0.22026-07-24CQL correctness pass. All 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.
v0.12026-07-04Initial HuntPack from Kaspersky Securelist ToddyCat / Umbrij analysis — 9 CQL queries, 4 Custom IOA recs, IOC appendix (7 Umbrij + 3 sideloaded-DLL MD5s, OAuth client_ids, masquerade task), tiered hardening, playbooks, containment runbook.
18

References

TierSourceUsed ForAccess Date
1 · VendorKaspersky Securelist — How the ToddyCat APT group gains access to Gmail accountsUmbrij analysis, STRD technique, IOCs, hashes, OAuth client_ids, scheduled-task persistence, Chrome-policy mitigation2026-07-04
2 · PressThe Hacker News — ToddyCat-Linked Umbrij Malware Abuses OAuth to Access GmailTechnique corroboration, PuppeteerSharp/CDP, session-riding, migration-app abuse2026-07-04
2 · PressGBHackers — ToddyCat Uses Shadow Token via Remote DebugSTRD naming, ConfuserEx, headless remote-debug detail2026-07-04
RefMITRE ATT&CK — ToddyCat (G1022)Technique mapping, mitigations2026-07-04