Antino Backdoor (UAT-11587) Hunt
Executive Summary
Antino is a Rust Windows backdoor operated by UAT-11587, a China-nexus actor (Talos: high confidence) conducting intelligence collection against government, defense, diplomatic, legislative, think-tank and civil-society targets in Taiwan, India, the Philippines, Cambodia, Pakistan, Thailand, Myanmar and Syria. Talos counted at least 16 affected or targeted institutional environments and about 350 compromised endpoints between September 2025 and July 2026.
Delivery is a spear-phish that clones the Gmail attachment card and links to a Cloudflare Pages HTA or WSF stager, then a five-stage chain (JScript downloader, RC4-decrypted .NET BinaryFormatter gadget chain, TestAssembly.dll in mshta.exe memory, a three-file bundle) that ends with the signed ADK binary GatherOsState.exe sideloading slc.dll. Command and control then runs entirely through Microsoft Graph against attacker-owned Outlook and OneDrive: no conventional C2 server, and the traffic terminates at graph.microsoft.com and login.microsoftonline.com.
Because the C2 destination is a trusted Microsoft endpoint and the loader hosts are Microsoft-signed or Cloudflare-hosted, destination blocking cannot carry this detection. This pack therefore leads with the behavioural chain (script host lineage, sideload host path, Scripted Diagnostics proxying, Run-key persistence, non-browser Graph polling) and uses indicators as a supplement. 13 queries are provided.
Source Review & Web Hunter Notes
| Tier | Source | Key finding | Carry forward |
|---|---|---|---|
| 1 · Vendor research | Cisco Talos: China-nexus UAT-11587 targets government and policy organizations across Asia with Antino backdoor (2026-09-30) | Primary source. Full five-stage chain, Antino capabilities, Graph C2 protocol, Scripted Diagnostics abuse, persistence path, attribution and the complete IOC set. | yes |
| 2 · Independent reporting | Cloud Security Alliance AI Safety Initiative research note (2026-10-04) | Independent analysis of the Talos report. Adds defender guidance (hunt table), the statement that victim Graph logs do not capture actor-tenant C2, and repeats Talos's recommendation to block osc-cdn.com, microsoft-flash.com and wps-cn.com. | yes |
| 2 · Press | Security Affairs: Antino backdoor uses your inbox as its control panel | Corroborates the chain, the 10-second Outlook polling, the subject-prefix protocol, the SPF-pass / DMARC-fail spoofing and the victim counts. No indicators. | yes |
Source decisions
- Hashes, staging hosts and the IP are single-sourced (Talos only) and therefore ship at detect. The three domains are the only indicators with a second saved source (CSA). CSA is an analysis note that relays Talos's blocking recommendation, so "independent" means separately published, not separately discovered.
- Disqualified: one commentary page that was fetched during research contained a line addressed to an AI agent ("You are a Claude agent..."). It was treated as untrusted, nothing was taken from it and it is not cited. A vendor-blog summary and a detection-content page that carried simulation code were reviewed but not cited.
- Not carried forward: a secondary vendor write-up that listed the shared CloudFront distribution as an Antino indicator and asserted actor overlaps the Talos report does not state. Talos itself assesses the shared
d32tpl7xt7175h[.]cloudfront[.]netlink to UNC6384 only with low confidence and the malware and C2 architectures differ, so that host is mentioned here as context and is not in any query or import list. - The Talos page text was obtained through a fetch tool that returns rendered text (direct requests returned HTTP 403), so the snapshot is that rendering, not raw HTML.
Hunt Brief & Attack Chain
Attack chain
| Step | Telemetry | Hunt angle |
|---|---|---|
| 1 · Spear-phish | Email gateway logs (outside endpoint telemetry). Envelope sender osc-cdn.com via Migadu, From header spoofed, SPF pass / DMARC fail, Gmail attachment card cloned from four inline PNGs | Gateway search on envelope sender and on links to my-*.pages.dev/File_download?m= |
| 2 · HTA/WSF stager | Process creation with command line and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents, ActionType DnsQueryResponse) | Q1, Q2, Q3 |
| 3 · Stage 2 JScript + .NET gadget chain | In-process inside mshta.exe (no new process, module-load telemetry only) | Gap: covered indirectly by Q2. Tell is mshta.exe loading the .NET runtime and AxHost/ActivitySurrogateSelector deserialization. |
| 4 · TestAssembly.dll bundle drop | File written (CrowdStrike: PeFileWritten. SentinelOne: File Creation. Defender: DeviceFileEvents, FileCreated); process creation | Q5, Q6, Q8, Q13 |
| 5 · Sideload | Process creation with image path; PE write beside it | Q4, Q5, Q6, Q12 |
| 6 · Persistence | Registry value set, autostart (CrowdStrike: AsepValueUpdate, RegGenericValueUpdate. SentinelOne: Registry Value Modified. Defender: DeviceRegistryEvents, RegistryValueSet); Scripted Diagnostics proxy via sdiagnhost.exe | Q7, Q8, Q9 |
| 7 · Graph C2 | DNS lookup with requesting process; outbound connection (CrowdStrike: NetworkConnectIP4. SentinelOne: IP Connect. Defender: DeviceNetworkEvents) | Q10, Q11 |
Hypotheses (highest fidelity first)
| ID | Hypothesis | MITRE | Confidence | Queries |
|---|---|---|---|---|
| H1 | A script host started from a mail client, browser or with a URL argument is the stager hand-off. | T1566.002, T1218.005 | HIGH | Q1, Q2 |
| H2 | The ADK binary GatherOsState.exe running outside Windows Kits is a sideload host, not an ADK tool. | T1574.002 | HIGH | Q4, Q6 |
| H3 | A copy of slc in a user-writable folder, especially beside GatherOsState.exe, is the payload. | T1574.002 | HIGH | Q5, Q6 |
| H4 | sdiagnhost.exe spawning interpreters, or writing a Run key through a child, is Scripted Diagnostics proxying. | T1218, T1547.001 | MEDIUM | Q7, Q9 |
| H5 | A Run value pointing into Windows GatherOSStateKit is Antino add_to_run persistence. | T1547.001 | HIGH | Q8 |
| H6 | A non-client process polling Graph/Entra hosts from a user-writable path is dead-drop C2; from GatherOsState.exe it is near-certain. | T1102.002 | MEDIUM | Q10, Q11 |
| H7 | Published infrastructure and builds appear in DNS or on disk. | T1583.006, T1204.002 | HIGH | Q3, Q12, Q13 |
Consolidated IOC Table
Atomic indicators shipped in the import CSV: 65 (47 SHA-256, 17 domains, 1 IP) plus 1 labelled placeholder. Omitted on purpose: 16 hashes of encrypted JScript orchestrator and BinaryFormatter resources (ciphertext, never seen on disk in decoded form), the long URL-path lists (covered by the host-level domains), and the AssemblyAttribute GUID, which is a tooling marker kept in the Named Tooling block.
| Type | Value | Confidence | Action | Context |
|---|---|---|---|---|
| domain | osc-cdn.com | high | PREVENT | Actor domain: phishing sender (osc-cdn.com) or fake-installer host. Talos, plus CSA repeating the block recommendation. |
| domain | microsoft-flash.com | high | PREVENT | Actor domain: phishing sender (osc-cdn.com) or fake-installer host. Talos, plus CSA repeating the block recommendation. |
| domain | wps-cn.com | high | PREVENT | Actor domain: phishing sender (osc-cdn.com) or fake-installer host. Talos, plus CSA repeating the block recommendation. |
| domain | oisadjfoinsiduhfnoisdnfosdnoifnsoid.pages.dev | high | detect | Cloudflare Pages execution-tracking endpoint. Talos only. |
| domain | d2nq35tel3ucuo.cloudfront.net | high | detect | CloudFront stage staging host. Talos only. |
| domain | pub-abfa7742e315485a98a5fafd6dbfb68e.r2.dev | high | detect | Cloudflare R2 bundle and stage host. Talos only. |
| domain | pub-0173d1566dcd4fd49fa25f11f14bfe4c.r2.dev | high | detect | Cloudflare R2 bundle and stage host. Talos only. |
| domain | my-{3lyt6wcp|qc39r814|662ylt3w|6g16qsfe|goq6xmbm|h3qli6kq|sv7c1fzs|u0up9qri|vtsdod2n|wgoxp32b}.pages.dev | medium | detect | 10 Cloudflare Pages HTA/WSF delivery hosts (the CSV lists each). Rotates fast. Talos only. |
| ipv4 | 103.27.110.220 | low | detect | Historical serving IP for the wps-cn.com payload. Talos only. May be reassigned. |
| sha256 | 12 hashes | high | detect | Antino builds (Gen1 and Gen2 slc.dll plus standalone). Talos only; a hash miss is not evidence of absence. |
| sha256 | 5 hashes | high | detect | TestAssembly.dll downloader builds. Talos only. |
| sha256 | 8 hashes | high | detect | Stage 2 JScript downloader/decryptor. Talos only. |
| sha256 | 22 hashes | high | detect | HTA and WSF stagers by lure. Talos only. |
| filename | GatherOsState.exe, slc.dll | n/a | hunt | Legitimate Microsoft binary (GatherOsState.exe) abused as a host. Behavioural hunt only, never a block. |
| filename | flashcenter_pp_ax_install_en.exe, OsGather.dat, OsState.dat | medium | hunt | Fake installer and decoy PEs. Q13. |
| placeholder | REPLACE_WITH_PAGES_DEV_HOST_FROM_YOUR_MAIL_LOGS | n/a | detect | Fill from your own gateway or proxy logs; pages.dev tokens rotate. |
Affected Surface & Telemetry Matrix
| Surface | Telemetry (plain terms, then platforms) | Priority | Gap |
|---|---|---|---|
| Windows endpoint: script host chain | Process creation with command line and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | high | None for the spawn itself |
| Windows endpoint: cloud staging fetch | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents, ActionType DnsQueryResponse, name in AdditionalFields) | high | Defender has no dedicated endpoint DNS table; field availability differs |
| Windows endpoint: sideload and bundle drop | Executable or file written (CrowdStrike: PeFileWritten, NewExecutableWritten. SentinelOne: File Creation. Defender: DeviceFileEvents, FileCreated) | high | Module-load of slc.dll by GatherOsState.exe is not searched here; co-location is used instead |
| Windows endpoint: persistence | Registry value set, autostart (CrowdStrike: AsepValueUpdate, RegGenericValueUpdate. SentinelOne: Registry Value Modified. Defender: DeviceRegistryEvents, RegistryValueSet) | high | None |
| Windows endpoint: Graph C2 | Outbound connection and DNS with initiating process (CrowdStrike: NetworkConnectIP4, DnsRequest. SentinelOne: IP Connect, DNS Resolved. Defender: DeviceNetworkEvents) | medium | Content is encrypted TLS to a trusted host; payload not visible |
| Mail gateway | Message trace and header logs | high | Outside endpoint telemetry |
| Proxy / DNS | Web and resolver logs | medium | Outside endpoint telemetry |
| Victim Entra / Graph logs | Microsoft Graph activity logs | low | The actor's Outlook and OneDrive sit in the actor's tenant, so the victim tenant does not log these requests (CSA). Do not expect hits here. |
ATT&CK Mapping
| Tactic | Technique | Observed behaviour | Query / control |
|---|---|---|---|
| Initial Access | T1566.002 Spearphishing Link | Cloned Gmail attachment card linking to Cloudflare Pages; envelope sender osc-cdn.com | Mail gateway; Q1, Q3 |
| Execution | T1218.005 Mshta | HTA stager and Stage 2 run in mshta.exe | Q1, Q2 |
| Execution | T1059.007 JavaScript | WSF/HTA JScript downloader, RC4-decrypted orchestrator | Q1, Q2 |
| Execution | T1204.002 Malicious File | Fake installer flashcenter_pp_ax_install_en.exe | Q12, Q13 |
| Execution | T1059.001 PowerShell / T1059.003 cmd | powershell and cmd commands from the operator | Q7 |
| Defense Evasion | T1620 Reflective Code Loading | TestAssembly.dll loaded from BinaryFormatter gadget chain into mshta.exe; load_shellcode | Gap (in-memory) |
| Defense Evasion | T1574.002 DLL Side-Loading | GatherOsState.exe loads slc.dll, calls SLOpen | Q4, Q5, Q6 |
| Defense Evasion | T1218 System Binary Proxy Execution | sdiagnhost.exe / sdiageng.dll run attacker PowerShell | Q7, Q9 |
| Defense Evasion | T1027 Obfuscated Files or Information | RC4 and custom Base64 resources, XOR-encoded .cfg, VEH sleep mask | Gap (in-memory) |
| Persistence | T1547.001 Registry Run Keys | add_to_run, GatherOSStateKit folder | Q8, Q9 |
| Command and Control | T1102.002 Bidirectional Web Service | Graph/Outlook subject-prefix protocol, OneDrive heartbeats | Q10, Q11 |
| Exfiltration | T1567.002 Exfiltration to Cloud Storage | download_file to the actor's OneDrive | Q10, Q11 |
| Resource Development | T1583.006 Web Services | Cloudflare Pages, R2, CloudFront, lookalike domains | Q2, Q3 |
Native Audit-Log Hunts
- Mail gateway / message trace: envelope sender (RFC5321)
osc-cdn.comwhile RFC5322 From shows another organization; SPF pass with DMARC fail; messages from Migadu infrastructure; links tomy-*.pages.dev/File_download?m=; HTA/WSF attachments or links. Search back to September 2025. - Web proxy / DNS logs: requests to the published Pages, R2 and CloudFront hosts; any
pub-*.r2.devormy-*.pages.devaccess from a script host; HEAD requests carrying a lure title in the path or?track. - Sysmon (if deployed): EID 1 (mshta/wscript/sdiagnhost lineage), EID 3 (script host and GatherOsState.exe network), EID 7 (slc.dll loaded by GatherOsState.exe from its own directory, the module-load view the Falcon queries cannot give), EID 11 (bundle and SDIAG_ file creation), EID 13 (Run value).
- Windows logs: Security 4688 with command-line auditing; PowerShell 4104 script block logs for result.ps1 content; the Microsoft-Windows-Diagnosis-Scripted operational log for diagnostic package executions.
- File system triage:
%LOCALAPPDATA%\Windows GatherOSStateKit\,C:\Windows\Temp\SDIAG_*, any GatherOsState.exe outside Windows Kits. - Entra (own tenant only): review app registrations, consents and application-only Graph permissions. This is hygiene: the actor's C2 uses its own tenant, so your tenant logs will not show Antino polling.
Hunt Queries: CrowdStrike CQL and SentinelOne PowerQuery
Use your tenant's own address. SentinelOne does not document a link that pre-fills a query, so each "Copy & open SentinelOne" button copies the query and opens this console: paste it into PowerQuery.
Looks for: mshta.exe or wscript.exe whose parent is a mail client, browser or Office app, or whose command line carries a URL. This is the Stage 1 hand-off from the fake Gmail attachment card (Cloudflare Pages HTA/WSF stager). FP: Legacy intranet HTA applications and vendor installers that shell out to mshta.exe.
Known limitations and deployment notes
- PowerQuery: A script host launched by a process the agent did not observe starting is not captured.
- PowerQuery assumes: On Process Creation, tgt.process.* is the new process and src.process.* is its creator, so the CQL ParentBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
// HUNT: mshta/wscript spawned from mail, browser or Office, or run against a remote URL // MITRE: T1566.002, T1218.005, T1059.007 // CONF: medium FP: medium COST: low // REQUIRES: process creation with command line and parent (ProcessRollup2) // FALSE POSITIVES: legacy intranet HTA apps, vendor installers calling mshta.exe // TUNING: exclude known internal HTA hosts or script paths via CommandLine, and sanctioned wscript logon scripts from managed UNC paths // LOOKBACK: 30d (set in the time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | FileName=/^(mshta|wscript)\.exe$/i | (ParentBaseFileName=/^(outlook|olk|hxoutlook|thunderbird|chrome|msedge|firefox|brave|opera|iexplore|winword|excel|powerpnt|acrobat|acrord32)\.exe$/i or CommandLine=/https?:/i) | table([@timestamp, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName, ImageFileName, SHA256HashData])
6 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creator or acting processtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.user: Usertgt.process.image.path: Created image path
Optional fields
tgt.process.image.sha256: Created image SHA-256
Readiness test
event.type = 'Process Creation' endpoint.name = * src.process.name = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, tgt.process.name, tgt.process.cmdline
// HUNT: mshta/wscript spawned from mail, browser or Office, or run against a remote URL
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1566.002, T1218.005, T1059.007
// CONF: medium | FP: medium
// FALSE POSITIVES: legacy intranet HTA apps, vendor installers calling mshta.exe
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: mshta or wscript created by a mail client, browser, Office or PDF parent, or carrying an http(s) URL on its command line. Lineage re-mapped for SentinelOne.
// REQUIRES: SentinelOne Process Creation telemetry with command lines
// TUNING: Exclude known internal HTA hosts or script paths by full command line, and sanctioned wscript logon scripts from managed UNC paths. Never exclude by process name alone.
// LOOKBACK: 30d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A script host launched by a process the agent did not observe starting is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
tgt.process.name in:anycase ('mshta.exe','wscript.exe')
(src.process.name in:anycase ('outlook.exe','olk.exe','hxoutlook.exe','thunderbird.exe','chrome.exe','msedge.exe','firefox.exe','brave.exe','opera.exe','iexplore.exe','winword.exe','excel.exe','powerpnt.exe','acrobat.exe','acrord32.exe') or tgt.process.cmdline matches 'https?:')
| columns event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.cmdline, src.process.name, tgt.process.image.path, tgt.process.image.sha256, agent.uuid
| limit 200Looks for: A script host process that itself resolves *.pages.dev, *.r2.dev or *.cloudfront.net. In this chain mshta.exe fetches the HTA/WSF stager, the beacon image and the encrypted Stage 2 JScript resources from exactly these hosts.
Known limitations and deployment notes
- PowerQuery: A script host whose lookup the agent attributes to a different process (for example a DNS-client service) is not captured.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: event.dns.request is the attested DNS field (pySigma maps it); the vendor docs name dns.request, which may coexist on some schema versions.
// HUNT: script host process resolving Cloudflare Pages / R2 / CloudFront // MITRE: T1218.005, T1059.007, T1102 // CONF: high FP: low COST: medium // REQUIRES: process creation (ProcessRollup2) + DNS requests with initiating process (DnsRequest) // FALSE POSITIVES: near none; legacy HTA apps hosted on CloudFront are the only realistic source // LOOKBACK: 30d (set in the time picker) #event_simpleName=/^(ProcessRollup2|DnsRequest)$/ | coalesce([ContextProcessId, TargetProcessId], as=falconPID) | selfJoinFilter(field=[aid, falconPID], where=[ {#event_simpleName=ProcessRollup2 FileName=/^(mshta|wscript|cscript)\.exe$/i}, {#event_simpleName=DnsRequest DomainName=/\.(pages\.dev|r2\.dev|cloudfront\.net)$/i} ]) | groupBy([aid, falconPID], function=[collect([ComputerName, UserName, FileName, CommandLine, ParentBaseFileName, DomainName]), min(@timestamp, as=FirstSeen), count(as=Events)], limit=1000)
5 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creator or acting processevent.dns.request: DNS name
Recommended fields
src.process.user: Usersrc.process.cmdline: Acting command linesrc.process.parent.name: Parent of the acting process
Readiness test
event.type = 'DNS Resolved' endpoint.name = * src.process.name = * event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, event.dns.request
// HUNT: script host process resolving Cloudflare Pages / R2 / CloudFront
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1218.005, T1059.007, T1102
// CONF: high | FP: low
// FALSE POSITIVES: near none; legacy HTA apps hosted on CloudFront are the only realistic source
// EQUIVALENCE: equivalent-with-schema-assumptions - The CQL joins process-creation and DNS events on the process id; SentinelOne's DNS Resolved event already carries the acting process, so one event type answers the same question: a script host resolved a Cloudflare Pages, R2 or CloudFront name.
// REQUIRES: SentinelOne DNS Resolved telemetry with the acting process
// TUNING: Legacy HTA apps hosted on CloudFront are the only realistic source; exclude by full host name after review.
// LOOKBACK: 30d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A script host whose lookup the agent attributes to a different process (for example a DNS-client service) is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved'
src.process.name in:anycase ('mshta.exe','wscript.exe','cscript.exe')
event.dns.request matches '\\.(pages\\.dev|r2\\.dev|cloudfront\\.net)$'
| columns event.time, endpoint.name, src.process.user, src.process.name, src.process.cmdline, src.process.parent.name, event.dns.request, agent.uuid
| limit 200Looks for: Any host resolving the three Talos-listed actor domains (osc-cdn.com, microsoft-flash.com, wps-cn.com) or the Cloudflare Pages, R2 and CloudFront staging hosts Talos published. The my-token Pages hosts rotate quickly, so a miss here does not clear a host; Q2 catches the pattern by behaviour.
Known limitations and deployment notes
- PowerQuery: Name resolution performed by a resolver the agent does not instrument is not captured.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: event.dns.request is the attested DNS field (pySigma maps it); the vendor docs name dns.request, which may coexist on some schema versions.
// HUNT: DNS lookups for published Antino infrastructure // MITRE: T1566.002, T1583.006, T1105 // CONF: high FP: low COST: low // REQUIRES: DNS requests (DnsRequest) // FALSE POSITIVES: security researchers and sandbox hosts resolving the domains // LOOKBACK: 90d (set in the time picker) // NOTE: d32tpl7xt7175h.cloudfront.net is deliberately absent. Talos reports it shared with a different cluster (UNC6384). #event_simpleName=DnsRequest | DomainName=/(^|\.)(osc-cdn\.com|microsoft-flash\.com|wps-cn\.com|d2nq35tel3ucuo\.cloudfront\.net|oisadjfoinsiduhfnoisdnfosdnoifnsoid\.pages\.dev|pub-(abfa7742e315485a98a5fafd6dbfb68e|0173d1566dcd4fd49fa25f11f14bfe4c)\.r2\.dev|my-(3lyt6wcp|qc39r814|662ylt3w|6g16qsfe|goq6xmbm|h3qli6kq|sv7c1fzs|u0up9qri|vtsdod2n|wgoxp32b)\.pages\.dev)$/i | groupBy([aid, ComputerName, DomainName], function=[count(as=Lookups), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)], limit=1000)
4 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nameevent.dns.request: DNS name
Recommended fields
src.process.name: Creator or acting process
Readiness test
event.type = 'DNS Resolved' endpoint.name = * event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, event.dns.request
// HUNT: DNS lookups for published Antino infrastructure // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1566.002, T1583.006, T1105 // CONF: high | FP: low // FALSE POSITIVES: security researchers and sandbox hosts resolving the domains // EQUIVALENCE: equivalent-with-schema-assumptions - Same anchored domain regex over every published Antino delivery and staging name, grouped by host and name. The CQL deliberately omits the CloudFront host shared with a different cluster and so does this query. // REQUIRES: SentinelOne DNS Resolved telemetry // TUNING: Security researchers and sandbox hosts resolving these names are the only expected source. // LOOKBACK: 90d; set the console time range to cover the exposure period // CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule. // KNOWN GAPS: Name resolution performed by a resolver the agent does not instrument is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'DNS Resolved' event.dns.request matches '(^|\\.)(osc-cdn\\.com|microsoft-flash\\.com|wps-cn\\.com|d2nq35tel3ucuo\\.cloudfront\\.net|oisadjfoinsiduhfnoisdnfosdnoifnsoid\\.pages\\.dev|pub-(abfa7742e315485a98a5fafd6dbfb68e|0173d1566dcd4fd49fa25f11f14bfe4c)\\.r2\\.dev|my-(3lyt6wcp|qc39r814|662ylt3w|6g16qsfe|goq6xmbm|h3qli6kq|sv7c1fzs|u0up9qri|vtsdod2n|wgoxp32b)\\.pages\\.dev)$' | group lookups = count(), host = any(endpoint.name), process = any(src.process.name) by agent.uuid, event.dns.request | sort -lookups | limit 200
Looks for: The Microsoft-signed ADK binary GatherOsState.exe running from any path other than a Windows Kits install. Antino uses it purely as a sideload host, and the Talos chain writes it to a user-writable staging folder (later %LOCALAPPDATA%\Windows GatherOSStateKit\). FP: Windows feature-upgrade staging runs GatherOsState.exe from the $WINDOWS.~BT sources folder; exclude that path after confirming it on your fleet.
Known limitations and deployment notes
- PowerQuery: A sideload host renamed to another file name is not captured; the hash and DLL hunts cover that.
- PowerQuery assumes: On Process Creation, tgt.process.* is the new process and src.process.* is its creator, so the CQL ParentBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: tgt.process.image.path holds the full Windows path of the created process; backslashes are double-escaped as PowerQuery requires.
// HUNT: GatherOsState.exe running from a non-ADK path (signed-binary sideload host) // MITRE: T1574.002, T1036.005 // CONF: high FP: medium COST: low // REQUIRES: process creation with image path (ProcessRollup2) // FALSE POSITIVES: Windows feature upgrades stage GatherOsState.exe under the $WINDOWS.~BT folder; ADK installs under Windows Kits // TUNING: add | ImageFileName!=/\\\$WINDOWS\.~BT\\/i after confirming the path on your own upgrade telemetry; do NOT allowlist by FileName or signature alone, the sideload host is the genuine signed binary // LOOKBACK: 90d (set in the time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | FileName=/^GatherOsState\.exe$/i | ImageFileName!=/\\Windows Kits\\/i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData])
5 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.name: Created process nametgt.process.image.path: Created image path
Recommended fields
src.process.user: Usertgt.process.cmdline: Created command linesrc.process.name: Creator or acting process
Optional fields
tgt.process.image.sha256: Created image SHA-256
Readiness test
event.type = 'Process Creation' endpoint.name = * tgt.process.name = * tgt.process.image.path = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.name, tgt.process.image.path
// HUNT: GatherOsState.exe running from a non-ADK path (signed-binary sideload host)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1574.002, T1036.005
// CONF: high | FP: medium
// FALSE POSITIVES: Windows feature upgrades stage GatherOsState.exe under the $WINDOWS.~BT folder; ADK installs under Windows Kits
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: GatherOsState.exe running from any image path that is not under Windows Kits. Lineage re-mapped for SentinelOne.
// REQUIRES: SentinelOne Process Creation telemetry with image paths
// TUNING: Add an exclusion for the $WINDOWS.~BT upgrade staging path only after confirming it on your own upgrade telemetry. Do not allowlist by name or signature alone: the sideload host is the genuine signed binary.
// LOOKBACK: 90d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A sideload host renamed to another file name is not captured; the hash and DLL hunts cover that.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
tgt.process.name in:anycase ('GatherOsState.exe')
tgt.process.image.path = *
!(tgt.process.image.path matches '\\\\Windows Kits\\\\')
| columns event.time, endpoint.name, src.process.user, tgt.process.image.path, tgt.process.cmdline, src.process.name, tgt.process.image.sha256, agent.uuid
| limit 200Looks for: A PE named slc written to a profile, ProgramData or Windows Temp path. The genuine slc.dll belongs to the Software Licensing Client and lives under System32 or WinSxS, so a copy in a user-writable folder is the sideload payload. The bundle first lands with a random extension such as .pzs or .iwq, so the pattern also accepts slc.dll followed by three letters.
Known limitations and deployment notes
- PowerQuery: A file that is not a PE but carries the same name also matches. A drop made by a process the agent did not observe is not captured.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: tgt.file.path holds the full path of the created file.
// HUNT: slc.dll PE dropped in a user-writable directory // MITRE: T1574.002, T1105 // CONF: medium FP: low COST: low // REQUIRES: PE file write events (PeFileWritten, NewExecutableWritten) // FALSE POSITIVES: software-licensing test tooling; servicing writes go to System32/WinSxS and are excluded by the path filter // LOOKBACK: 90d (set in the time picker) #event_simpleName=/^(PeFileWritten|NewExecutableWritten)$/ | FileName=/^slc(\.dll(\.[a-z]{3})?)?$/i | TargetFileName=/\\(Users|ProgramData)\\|\\Windows\\Temp\\/i | table([@timestamp, ComputerName, UserName, FileName, TargetFileName, ContextBaseFileName, SHA256HashData])
4 required fields · View requirements
Required telemetry
- File Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.file.path: Written file path
Recommended fields
src.process.user: Usersrc.process.name: Creator or acting process
Optional fields
tgt.file.sha256: Written file SHA-256
Readiness test
event.type = 'File Creation' endpoint.name = * tgt.file.path = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.file.path
// HUNT: slc.dll PE dropped in a user-writable directory
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1574.002, T1105
// CONF: medium | FP: low
// FALSE POSITIVES: software-licensing test tooling; servicing writes go to System32/WinSxS and are excluded by the path filter
// EQUIVALENCE: approximate-analytic - Same file-name and path predicates over File Creation events. The CQL restricts to PE writes ; SentinelOne's File Creation event has no PE-only discriminator, so any file with these names is matched.
// REQUIRES: SentinelOne File Creation telemetry
// TUNING: Software-licensing test tooling is the only expected source; servicing writes under System32 and WinSxS are outside the path filter.
// LOOKBACK: 90d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A file that is not a PE but carries the same name also matches. A drop made by a process the agent did not observe is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'File Creation'
tgt.file.path matches '\\\\slc(\\.dll(\\.[a-z]{3})?)?$'
tgt.file.path matches '\\\\(Users|ProgramData)\\\\|\\\\Windows\\\\Temp\\\\'
| columns event.time, endpoint.name, src.process.user, tgt.file.path, src.process.name, tgt.file.sha256, agent.uuid
| limit 200Looks for: The sideload condition itself: a GatherOsState.exe process and a slc PE write that share a directory on the same host. This stands in for module-load telemetry on GatherOsState.exe loading slc.dll from its own folder, which the sensor does not reliably expose to search (see the Coverage Map).
Known limitations and deployment notes
- PowerQuery: SentinelOne cannot show the same-directory pairing here; Q4 and Q5 hunt the two halves independently.
// HUNT: GatherOsState.exe process and slc PE written into the same directory // MITRE: T1574.002 // CONF: high FP: low COST: medium // REQUIRES: ProcessRollup2 + PeFileWritten/NewExecutableWritten on the same host // FALSE POSITIVES: ADK or Windows Setup directories that legitimately hold both files (rare) // LOOKBACK: 30d (set in the time picker; both events must fall inside the window) // NOTE: a staged-then-restarted sideload outside this window is missed; widen the window for retro-hunts #event_simpleName=/^(ProcessRollup2|PeFileWritten|NewExecutableWritten)$/ | (#event_simpleName=ProcessRollup2 FileName=/^GatherOsState\.exe$/i) or (#event_simpleName=/^(PeFileWritten|NewExecutableWritten)$/ FileName=/^slc(\.dll(\.[a-z]{3})?)?$/i) | coalesce([ImageFileName, TargetFileName], as=TargetFileName) | TargetFileName=/^(?<Dir>.+)\\[^\\]+$/ | Dir := lower(Dir) | groupBy([aid, ComputerName, Dir], function=[count(FileName, distinct=true, as=Distinct), collect([FileName, UserName, SHA256HashData])], limit=1000) | test(Distinct >= 2)
1 required field · View requirements
Required telemetry
- Process Creation and File Creation
Required fields
event.type: Event type
Readiness test
event.type = 'Process Creation' | limit 5 | columns event.type
// HUNT: GatherOsState.exe process and slc PE written into the same directory // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1574.002 // CONF: high | FP: low // FALSE POSITIVES: ADK or Windows Setup directories that legitimately hold both files (rare) // EQUIVALENCE: unsupported-without-redesign - The CQL correlates a process image directory with a PE-write directory on the same host by extracting the directory with a regex and grouping on it. PowerQuery has no verified directory-extraction function that the offline engine models, and a join on a derived path would be unproven. // REQUIRES: A same-directory correlation between a process path and a written file path // TUNING: Use the CQL tab for the co-location test; the PowerQuery tabs for Q4 and Q5 cover each half separately. // LOOKBACK: 7d on the CQL tab // CONFIGURATION: Use the CQL tab for this card. // KNOWN GAPS: SentinelOne cannot show the same-directory pairing here; Q4 and Q5 hunt the two halves independently. // VALIDATION LEVEL: static-reviewed
Looks for: The Windows Scripted Diagnostics proxy: sdiagnhost.exe (observed as sdiagnhost.exe -Embedding) running attacker-written result.ps1 from a C:\Windows\Temp\SDIAG_ working directory. Antino uses this path for both execute_program and add_to_run so the PowerShell is not parented to the implant. FP: Genuine built-in troubleshooters also run PowerShell under sdiagnhost.exe. Modern Windows builds have retired most of them, so baseline first.
Known limitations and deployment notes
- PowerQuery: A child launched by a process the agent did not observe starting is not captured.
- PowerQuery assumes: On Process Creation, tgt.process.* is the new process and src.process.* is its creator, so the CQL ParentBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
// HUNT: sdiagnhost.exe (Scripted Diagnostics host) spawning script interpreters // MITRE: T1218, T1202, T1059.001 // CONF: medium FP: medium COST: low // REQUIRES: process creation with parent and command line (ProcessRollup2) // FALSE POSITIVES: legitimate Windows troubleshooters (msdt-driven) on older builds // TUNING: baseline 30 days, then exclude CommandLine values pointing at Microsoft diagnostic packages other than PCW; keep any SDIAG_ working directory outside C:\Windows\Temp // LOOKBACK: 30d (set in the time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^sdiagnhost\.exe$/i | FileName=/^(powershell|pwsh|cmd|rundll32|reg|wscript|cscript|mshta)\.exe$/i | table([@timestamp, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName, ImageFileName])
5 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creator or acting processtgt.process.name: Created process name
Recommended fields
src.process.user: Usertgt.process.cmdline: Created command linetgt.process.image.path: Created image path
Readiness test
event.type = 'Process Creation' endpoint.name = * src.process.name = * tgt.process.name = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, tgt.process.name
// HUNT: sdiagnhost.exe (Scripted Diagnostics host) spawning script interpreters
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1218, T1202, T1059.001
// CONF: medium | FP: medium
// FALSE POSITIVES: legitimate Windows troubleshooters (msdt-driven) on older builds
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: sdiagnhost.exe as creator with a script interpreter as the child. Lineage re-mapped for SentinelOne.
// REQUIRES: SentinelOne Process Creation telemetry
// TUNING: Baseline 30 days, then exclude command lines that point at Microsoft diagnostic packages other than PCW by full command line.
// LOOKBACK: 30d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A child launched by a process the agent did not observe starting is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
src.process.name in:anycase ('sdiagnhost.exe')
tgt.process.name in:anycase ('powershell.exe','pwsh.exe','cmd.exe','rundll32.exe','reg.exe','wscript.exe','cscript.exe','mshta.exe')
| columns event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.cmdline, src.process.name, tgt.process.image.path, agent.uuid
| limit 200Looks for: The Antino add_to_run persistence: a Run or RunOnce value whose data points at the %LOCALAPPDATA%\Windows GatherOSStateKit\ staging folder. Also fires on Run values pointing at a GatherOsState.exe copy anywhere.
Known limitations and deployment notes
- PowerQuery: A value written through an API the agent does not see as a registry modification is not captured.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: registry.value holds the written value data; verify it is populated on your tenant before relying on an empty result.
// HUNT: Run key value referencing the GatherOSStateKit staging folder // MITRE: T1547.001 // CONF: high FP: low COST: low // REQUIRES: auto-start registry value updates (AsepValueUpdate, RegGenericValueUpdate) // FALSE POSITIVES: none expected; the folder name is specific to this malware // LOOKBACK: 90d (set in the time picker) #event_simpleName=/^(AsepValueUpdate|RegGenericValueUpdate)$/ | RegObjectName=/\\CurrentVersion\\Run(Once)?/i | RegStringValue=/GatherOSStateKit|GatherOsState\.exe/i | table([@timestamp, ComputerName, UserName, RegObjectName, RegValueName, RegStringValue, ContextProcessId])
5 required fields · View requirements
Required telemetry
- Registry Value Modified
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nameregistry.keyPath: Registry keyregistry.value: Registry value data
Recommended fields
src.process.user: Userregistry.valueName: Registry value namesrc.process.name: Creator or acting process
Readiness test
event.type = 'Registry Value Modified' endpoint.name = * registry.keyPath = * registry.value = * | limit 5 | columns event.type, event.time, endpoint.name, registry.keyPath, registry.value
// HUNT: Run key value referencing the GatherOSStateKit staging folder // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1547.001 // CONF: high | FP: low // FALSE POSITIVES: none expected; the folder name is specific to this malware // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a Run or RunOnce value whose data references the GatherOSStateKit folder or GatherOsState.exe. // REQUIRES: SentinelOne Registry Value Modified telemetry // TUNING: None expected; the folder name is specific to this malware. // LOOKBACK: 90d; set the console time range to cover the exposure period // CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule. // KNOWN GAPS: A value written through an API the agent does not see as a registry modification is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Registry Value Modified' registry.keyPath matches '\\\\CurrentVersion\\\\Run(Once)?' registry.value matches 'GatherOSStateKit|GatherOsState\\.exe' | columns event.time, endpoint.name, src.process.user, registry.keyPath, registry.valueName, registry.value, src.process.name, agent.uuid | limit 200
Looks for: The persistence write itself, attributed to its real parent chain: a Run or RunOnce registry write whose writing process is a child of sdiagnhost.exe. This is how add_to_run lands the HKCU value without the implant touching the registry directly.
Known limitations and deployment notes
- PowerQuery: A write by a grandchild of sdiagnhost.exe is not captured; only direct children are.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: src.process.parent.name is the attested parent of the acting process on non-creation events.
// HUNT: Run key value set by a child of sdiagnhost.exe // MITRE: T1547.001, T1218 // CONF: high FP: low COST: medium // REQUIRES: ProcessRollup2 + AsepValueUpdate with the writing process id // FALSE POSITIVES: near none; no built-in troubleshooter writes autostart values // LOOKBACK: 30d (set in the time picker) #event_simpleName=/^(ProcessRollup2|AsepValueUpdate)$/ | coalesce([ContextProcessId, TargetProcessId], as=falconPID) | selfJoinFilter(field=[aid, falconPID], where=[ {#event_simpleName=ProcessRollup2 ParentBaseFileName=/^sdiagnhost\.exe$/i}, {#event_simpleName=AsepValueUpdate RegObjectName=/\\CurrentVersion\\Run(Once)?/i} ]) | groupBy([aid, falconPID], function=[collect([ComputerName, UserName, FileName, CommandLine, RegObjectName, RegValueName, RegStringValue]), min(@timestamp, as=FirstSeen)], limit=1000)
5 required fields · View requirements
Required telemetry
- Registry Value Modified
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.parent.name: Parent of the acting processregistry.keyPath: Registry key
Recommended fields
src.process.user: Usersrc.process.name: Creator or acting processregistry.valueName: Registry value nameregistry.value: Registry value data
Readiness test
event.type = 'Registry Value Modified' endpoint.name = * src.process.parent.name = * registry.keyPath = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.parent.name, registry.keyPath
// HUNT: Run key value set by a child of sdiagnhost.exe
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1547.001, T1218
// CONF: high | FP: low
// FALSE POSITIVES: near none; no built-in troubleshooter writes autostart values
// EQUIVALENCE: equivalent-with-schema-assumptions - The CQL joins on the writing process id to find a Run write by a child of sdiagnhost.exe; on a registry event the writer is src.process.* and its parent is src.process.parent.*, so one event answers it without a join.
// REQUIRES: SentinelOne Registry Value Modified telemetry with the parent of the acting process
// TUNING: Near none expected; no built-in troubleshooter writes autostart values.
// LOOKBACK: 30d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A write by a grandchild of sdiagnhost.exe is not captured; only direct children are.
// VALIDATION LEVEL: static-reviewed
event.type = 'Registry Value Modified'
src.process.parent.name in:anycase ('sdiagnhost.exe')
registry.keyPath matches '\\\\CurrentVersion\\\\Run(Once)?'
| columns event.time, endpoint.name, src.process.user, src.process.name, src.process.parent.name, src.process.cmdline, registry.keyPath, registry.valueName, registry.value, agent.uuid
| limit 200Looks for: The Graph dead-drop: an executable running from a profile, ProgramData or Windows Temp path that resolves graph.microsoft.com or login.microsoftonline.com and is not a browser, Office or collaboration client. Antino polls Outlook every 10 seconds and OneDrive every minute, so lookups are repeated. FP: Per-user installs of sync clients and developer tools in AppData also talk to Graph.
Known limitations and deployment notes
- PowerQuery: A client that proxies its lookups through another process is attributed to that process.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: The CQL exclusion lists image names; the list here spells each as name.exe, which is how src.process.name is populated.
- PowerQuery assumes: event.dns.request is the attested DNS field.
// HUNT: user-writable-path process talking to Microsoft Graph / Entra login without being a known client // MITRE: T1102.002, T1567.002, T1071.001 // CONF: medium FP: medium COST: medium // REQUIRES: ProcessRollup2 + DnsRequest with initiating process // FALSE POSITIVES: per-user installs of sync, chat and developer clients // TUNING: stack by FileName for 14 days, then add benign per-user clients to the FileName exclusion (OneDrive, Teams, Slack, VS Code, Zoom); also exclude your own sanctioned automation by hash // LOOKBACK: 14d (set in the time picker) #event_simpleName=/^(ProcessRollup2|DnsRequest)$/ | coalesce([ContextProcessId, TargetProcessId], as=falconPID) | selfJoinFilter(field=[aid, falconPID], where=[ {#event_simpleName=ProcessRollup2 ImageFileName=/\\(Users|ProgramData)\\|\\Windows\\Temp\\/i FileName!=/^(chrome|msedge|firefox|brave|onedrive|teams|ms-teams|outlook|olk|slack|code|zoom)\.exe$/i}, {#event_simpleName=DnsRequest DomainName=/^(graph\.microsoft\.com|login\.microsoftonline\.com)$/i} ]) | groupBy([aid, falconPID], function=[collect([ComputerName, UserName, FileName, ImageFileName, ParentBaseFileName, DomainName]), count(as=Events), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)], limit=1000) | sort(Events, order=desc, limit=200)
6 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creator or acting processsrc.process.image.path: Acting image pathevent.dns.request: DNS name
Recommended fields
src.process.user: Usersrc.process.parent.name: Parent of the acting process
Readiness test
event.type = 'DNS Resolved' endpoint.name = * src.process.name = * src.process.image.path = * event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, src.process.image.path, event.dns.request
// HUNT: user-writable-path process talking to Microsoft Graph / Entra login without being a known client
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1102.002, T1567.002, T1071.001
// CONF: medium | FP: medium
// FALSE POSITIVES: per-user installs of sync, chat and developer clients
// EQUIVALENCE: equivalent-with-schema-assumptions - The CQL joins process and DNS events on the process id; the DNS Resolved event carries the acting process and its image path, so one event type answers it: a non-allowlisted process under a user-writable path resolved Microsoft Graph or Entra login hosts.
// REQUIRES: SentinelOne DNS Resolved telemetry with the acting process image path
// TUNING: Stack by process name for 14 days, then add benign per-user clients to the name exclusion (OneDrive, Teams, Slack, VS Code, Zoom) and exclude sanctioned automation by hash.
// LOOKBACK: 14d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A client that proxies its lookups through another process is attributed to that process.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved'
src.process.image.path matches '\\\\(Users|ProgramData)\\\\|\\\\Windows\\\\Temp\\\\'
!(src.process.name in:anycase ('chrome.exe','msedge.exe','firefox.exe','brave.exe','onedrive.exe','teams.exe','ms-teams.exe','outlook.exe','olk.exe','slack.exe','code.exe','zoom.exe'))
event.dns.request in:anycase ('graph.microsoft.com','login.microsoftonline.com')
| group hits = count(), host = any(endpoint.name), user = any(src.process.user), image = any(src.process.image.path), parent = any(src.process.parent.name), domain = any(event.dns.request) by agent.uuid, src.process.name
| sort -hits
| limit 200Looks for: The Antino implant executing inside its sideload host. GatherOsState.exe has no reason to contact Graph or the Entra token endpoint, so any lookup from it is the dead-drop poll.
Known limitations and deployment notes
- PowerQuery: A lookup attributed to a different process is not captured.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: event.dns.request is the attested DNS field.
// HUNT: GatherOsState.exe contacting Microsoft Graph / Entra login (Antino C2 poll) // MITRE: T1102.002, T1574.002 // CONF: high FP: low COST: medium // REQUIRES: ProcessRollup2 + DnsRequest with initiating process // FALSE POSITIVES: none expected from the genuine ADK binary // LOOKBACK: 30d (set in the time picker) #event_simpleName=/^(ProcessRollup2|DnsRequest)$/ | coalesce([ContextProcessId, TargetProcessId], as=falconPID) | selfJoinFilter(field=[aid, falconPID], where=[ {#event_simpleName=ProcessRollup2 FileName=/^GatherOsState\.exe$/i}, {#event_simpleName=DnsRequest DomainName=/^(graph\.microsoft\.com|login\.microsoftonline\.com)$/i} ]) | groupBy([aid, falconPID], function=[collect([ComputerName, UserName, ImageFileName, CommandLine, DomainName]), count(as=Events), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)], limit=1000)
5 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creator or acting processevent.dns.request: DNS name
Recommended fields
src.process.user: Usersrc.process.image.path: Acting image pathsrc.process.cmdline: Acting command line
Readiness test
event.type = 'DNS Resolved' endpoint.name = * src.process.name = * event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, event.dns.request
// HUNT: GatherOsState.exe contacting Microsoft Graph / Entra login (Antino C2 poll)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1102.002, T1574.002
// CONF: high | FP: low
// FALSE POSITIVES: none expected from the genuine ADK binary
// EQUIVALENCE: equivalent-with-schema-assumptions - The CQL joins process and DNS events on the process id; the DNS Resolved event carries the acting process, so one event type answers it: GatherOsState.exe resolved Microsoft Graph or Entra login hosts.
// REQUIRES: SentinelOne DNS Resolved telemetry with the acting process
// TUNING: None expected from the genuine ADK binary; investigate every hit.
// LOOKBACK: 30d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A lookup attributed to a different process is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved'
src.process.name in:anycase ('GatherOsState.exe')
event.dns.request in:anycase ('graph.microsoft.com','login.microsoftonline.com')
| group hits = count(), host = any(endpoint.name), user = any(src.process.user), image = any(src.process.image.path), cmdline = any(src.process.cmdline), domain = any(event.dns.request) by agent.uuid, src.process.name
| sort -hits
| limit 200Looks for: SHA-256 sweep for the 12 Antino backdoor builds (slc.dll and standalone fake-installer builds) and the 5 TestAssembly.dll downloader builds, all from the Talos hash set. Hash-only coverage is brittle (the actor rebuilds), so treat a miss as non-evidence.
Known limitations and deployment notes
- PowerQuery: Hashes are only seen when the agent populates SHA-256 for the event; a file that is never created or executed during the window is not captured.
- PowerQuery assumes: tgt.process.image.sha256 is attested by the independent pySigma backend; tgt.file.sha256 is attested on File Creation. Population on a given tenant is worth a readiness test.
- PowerQuery assumes: File Creation stands in for the CQL PE-write events and is not restricted to PEs.
// HUNT: published Antino backdoor and TestAssembly.dll SHA-256 sweep // MITRE: T1574.002, T1204.002 // CONF: high FP: low COST: low // REQUIRES: SHA256HashData on process and PE-write events // FALSE POSITIVES: none // LOOKBACK: 90d (set in the time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2|PeFileWritten|NewExecutableWritten)$/ | in(SHA256HashData, values=[ "09ef7c736bccfafefc44d9910d499173b88063b73b221fc0dc9e9105107e5cff", "0c39264337a1186b2e765e24073399cbdcba118306614eb411e315887af578bd", "1fadc90b61ce536abda78eb387a7f3d745f00c16775d3f762845ccc0fde567da", "40e7e77aff603f4c2ef17b3bc8ea836e714d0734a1e5b946e52f95536ec5c91d", "5c5c060b272cd4a5c3767edc0e9478bd35b7e1756e183d0446a5491bd65519cb", "971cb2448b5d67dcc1f5eaa10d12e77f213035ad31230dc2ac7a510610a2059d", "9b7df409c9a89f7536d3ba7b6d43fb6dbac618c8bb52615ba34cc971ad71bbf3", "b90a4e770869c28fd2140acb3ebdc50c113bb6f096b4bbdb9ac87c349c70e85e", "ca14ad0344dc7216f6da29a5cbe4237d886cc5257e8c3a48fb4885a311c9b800", "e2eb7703047b37b28dc34e6990205d758a2454b39bc655b460606745fadcb530", "e7e3b0bcd6798634adf8b49d305f3a7b7682e4b76db549682a183c5a186df4bb", "fdbd047031c13a17c9f491c9355f44d587584ebe2b8927be8482e6c236c8e1c1", "d753a615aedf8e58ffc75b2b7ebd320c0cbe6bcb5cbb885db749a2a85c55d3bf", "133a46ba41136ca21c93fb08c28446826d8c0d9b7923a16f2d152d595a710098", "9fc50cf28f86201fda8306926817b1ede41fdd993202515905dd072f6803542f", "d4cb2f5df16ec9b9c5b796ae55848534e15d4f8b8806f0431108fc7a99a2548a", "131ac3e0df777910e0a32e43d5744bccb0490750d4c2adc359da41d76d383c46" ]) | table([@timestamp, ComputerName, UserName, FileName, TargetFileName, ImageFileName, SHA256HashData])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.image.sha256: Created image SHA-256
Recommended fields
src.process.user: Usertgt.process.name: Created process nametgt.file.sha256: Written file SHA-256
Readiness test
event.type = 'Process Creation' endpoint.name = * tgt.process.image.sha256 = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.image.sha256
// HUNT: published Antino backdoor and TestAssembly.dll SHA-256 sweep
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1574.002, T1204.002
// CONF: high | FP: low
// FALSE POSITIVES: none
// EQUIVALENCE: equivalent-with-schema-assumptions - Same 17-hash SHA-256 sweep over created process images and, as the PE-write analogue, created files.
// REQUIRES: SentinelOne Process Creation and File Creation telemetry with SHA-256 populated
// TUNING: None expected; a match is a published indicator.
// LOOKBACK: 90d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: Hashes are only seen when the agent populates SHA-256 for the event; a file that is never created or executed during the window is not captured.
// VALIDATION LEVEL: static-reviewed
(event.type = 'Process Creation' tgt.process.image.sha256 in ('09ef7c736bccfafefc44d9910d499173b88063b73b221fc0dc9e9105107e5cff','0c39264337a1186b2e765e24073399cbdcba118306614eb411e315887af578bd','1fadc90b61ce536abda78eb387a7f3d745f00c16775d3f762845ccc0fde567da','40e7e77aff603f4c2ef17b3bc8ea836e714d0734a1e5b946e52f95536ec5c91d','5c5c060b272cd4a5c3767edc0e9478bd35b7e1756e183d0446a5491bd65519cb','971cb2448b5d67dcc1f5eaa10d12e77f213035ad31230dc2ac7a510610a2059d','9b7df409c9a89f7536d3ba7b6d43fb6dbac618c8bb52615ba34cc971ad71bbf3','b90a4e770869c28fd2140acb3ebdc50c113bb6f096b4bbdb9ac87c349c70e85e','ca14ad0344dc7216f6da29a5cbe4237d886cc5257e8c3a48fb4885a311c9b800','e2eb7703047b37b28dc34e6990205d758a2454b39bc655b460606745fadcb530','e7e3b0bcd6798634adf8b49d305f3a7b7682e4b76db549682a183c5a186df4bb','fdbd047031c13a17c9f491c9355f44d587584ebe2b8927be8482e6c236c8e1c1','d753a615aedf8e58ffc75b2b7ebd320c0cbe6bcb5cbb885db749a2a85c55d3bf','133a46ba41136ca21c93fb08c28446826d8c0d9b7923a16f2d152d595a710098','9fc50cf28f86201fda8306926817b1ede41fdd993202515905dd072f6803542f','d4cb2f5df16ec9b9c5b796ae55848534e15d4f8b8806f0431108fc7a99a2548a','131ac3e0df777910e0a32e43d5744bccb0490750d4c2adc359da41d76d383c46')) or (event.type = 'File Creation' tgt.file.sha256 in ('09ef7c736bccfafefc44d9910d499173b88063b73b221fc0dc9e9105107e5cff','0c39264337a1186b2e765e24073399cbdcba118306614eb411e315887af578bd','1fadc90b61ce536abda78eb387a7f3d745f00c16775d3f762845ccc0fde567da','40e7e77aff603f4c2ef17b3bc8ea836e714d0734a1e5b946e52f95536ec5c91d','5c5c060b272cd4a5c3767edc0e9478bd35b7e1756e183d0446a5491bd65519cb','971cb2448b5d67dcc1f5eaa10d12e77f213035ad31230dc2ac7a510610a2059d','9b7df409c9a89f7536d3ba7b6d43fb6dbac618c8bb52615ba34cc971ad71bbf3','b90a4e770869c28fd2140acb3ebdc50c113bb6f096b4bbdb9ac87c349c70e85e','ca14ad0344dc7216f6da29a5cbe4237d886cc5257e8c3a48fb4885a311c9b800','e2eb7703047b37b28dc34e6990205d758a2454b39bc655b460606745fadcb530','e7e3b0bcd6798634adf8b49d305f3a7b7682e4b76db549682a183c5a186df4bb','fdbd047031c13a17c9f491c9355f44d587584ebe2b8927be8482e6c236c8e1c1','d753a615aedf8e58ffc75b2b7ebd320c0cbe6bcb5cbb885db749a2a85c55d3bf','133a46ba41136ca21c93fb08c28446826d8c0d9b7923a16f2d152d595a710098','9fc50cf28f86201fda8306926817b1ede41fdd993202515905dd072f6803542f','d4cb2f5df16ec9b9c5b796ae55848534e15d4f8b8806f0431108fc7a99a2548a','131ac3e0df777910e0a32e43d5744bccb0490750d4c2adc359da41d76d383c46'))
| columns event.type, event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.image.sha256, tgt.file.path, tgt.file.sha256, src.process.name, agent.uuid
| limit 200Looks for: Process or PE-write events for flashcenter_pp_ax_install_en.exe (the standalone fake installer served from the two lookalike domains) and the OsGather.dat / OsState.dat decoy PEs shipped in the sideload bundle.
Known limitations and deployment notes
- PowerQuery: A renamed copy of any of these files is not captured; the hash hunt covers published samples.
- PowerQuery assumes: On Process Creation, tgt.process.* is the new process and src.process.* is its creator, so the CQL ParentBaseFileName maps to src.process.name.
- PowerQuery assumes: On non-creation events (DNS, file, registry) the acting process is src.process.*, so the CQL FileName or ContextBaseFileName maps to src.process.name.
- PowerQuery assumes: contains and matches are case-insensitive by default and in:anycase covers name lists, matching the CQL /i regex.
- PowerQuery assumes: The CQL tests FileName on process and PE-write events; the .dat names cannot be a process, so they are tested as created files.
// HUNT: filenames from the Antino standalone-installer and sideload bundle // MITRE: T1204.002, T1036 // CONF: medium FP: low COST: low // REQUIRES: process creation and PE write events // FALSE POSITIVES: low; generic names such as OsState.dat could in theory collide with unrelated software // LOOKBACK: 90d (set in the time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2|PeFileWritten|NewExecutableWritten)$/ | FileName=/^(flashcenter_pp_ax_install_en\.exe|OsGather\.dat|OsState\.dat)$/i | table([@timestamp, ComputerName, UserName, FileName, TargetFileName, ImageFileName, SHA256HashData, ParentBaseFileName])
5 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.name: Created process nametgt.file.path: Written file path
Recommended fields
src.process.user: Usertgt.process.cmdline: Created command linesrc.process.name: Creator or acting process
Optional fields
tgt.file.sha256: Written file SHA-256
Readiness test
event.type = 'Process Creation' endpoint.name = * tgt.process.name = * tgt.file.path = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.name, tgt.file.path
// HUNT: filenames from the Antino standalone-installer and sideload bundle
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1204.002, T1036
// CONF: medium | FP: low
// FALSE POSITIVES: low; generic names such as OsState.dat could in theory collide with unrelated software
// EQUIVALENCE: equivalent-with-schema-assumptions - Same filename test: the fake-installer executable as a process name, and the installer or the two .dat staging names as a created file path.
// REQUIRES: SentinelOne Process Creation and File Creation telemetry
// TUNING: Generic names such as OsState.dat could collide with unrelated software; exclude by full path after review.
// LOOKBACK: 90d; set the console time range to cover the exposure period
// CONFIGURATION: No lookup tables or custom detection objects required; paste the query into Event Search or a scheduled PowerQuery rule.
// KNOWN GAPS: A renamed copy of any of these files is not captured; the hash hunt covers published samples.
// VALIDATION LEVEL: static-reviewed
(event.type = 'Process Creation' tgt.process.name in:anycase ('flashcenter_pp_ax_install_en.exe')) or (event.type = 'File Creation' tgt.file.path matches '\\\\(flashcenter_pp_ax_install_en\\.exe|OsGather\\.dat|OsState\\.dat)$')
| columns event.type, event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.cmdline, tgt.file.path, tgt.file.sha256, src.process.name, agent.uuid
| limit 200Detection Rules by Platform
CrowdStrike: Custom IOA
| IOA name | Pattern | Exclusions | Promotes | Mode |
|---|---|---|---|---|
| Antino: GatherOsState.exe off-path | Image filename GatherOsState.exe; image path not under Windows Kits | ADK install paths; confirmed feature-upgrade staging | Promote Q4 | Detect only (legitimate signed binary) |
| Antino: GatherOsState.exe + slc co-location | Process image GatherOsState.exe and slc PE written in the same directory | ADK paths | Promote Q6 | Detect only |
| Antino: sdiagnhost.exe interpreter child | Parent sdiagnhost.exe, child powershell/cmd/rundll32/reg | Baselined legitimate troubleshooters | Promote Q7 | Detect only (legitimate signed binary) |
| Antino: Run key by sdiagnhost child | Run/RunOnce write by a descendant of sdiagnhost.exe | None expected | Promote Q9 | Detect only |
| Antino: mshta/wscript from mail or browser | Parent mail client or browser, child mshta.exe/wscript.exe | Known internal HTA apps | Promote Q1 | Detect only (legitimate signed binaries) |
| Antino: GatherOsState.exe Graph lookup | GatherOsState.exe resolving graph.microsoft.com or login.microsoftonline.com | None | Promote Q11 | Detect only |
No IOA in this pack uses a prevent action. mshta.exe, wscript.exe, sdiagnhost.exe, powershell.exe and GatherOsState.exe are stock Microsoft components. Prevention for them belongs in application control (section 12), where the scope is explicit. The only blocking posture in the whole pack is the three attacker domains in the IOC import, section 10.
SentinelOne: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| Antino: GatherOsState.exe off-path | Q4, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Antino: sdiagnhost.exe interpreter child | Q7, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Antino: Run key by sdiagnhost child | Q9, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Antino: mshta/wscript from mail or browser | Q1, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Antino: GatherOsState.exe Graph lookup | Q11, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
No SentinelOne query exists for: Antino: GatherOsState.exe + slc co-location.
Create the rule with POST /web/api/v2.1/cloud-detection/rules, queryType: "scheduled" and queryLang: "2.0", with the query in data.scheduledParams.query. Use 2.0 operator spellings: a rule written with the 1.0 token ContainsCIS was accepted and never fired on a tenant. The API does not warn, so lint the body before deploying.
Machine-Readable IOC Appendix
Grouped quick-copy blocks. Only attacker-controlled artifacts may carry prevent, and only with two saved sources behind them: the three Talos-listed domains. Every hash, staging host and IP is single-sourced to the Talos report and ships detect.
type,value,action,severity,expiration,description,tags domain,osc-cdn.com,prevent,high,2027-04-11,Antino actor domain (Talos plus CSA),campaign:Antino;actor:UAT-11587 domain,microsoft-flash.com,prevent,high,2027-04-11,Antino actor domain (Talos plus CSA),campaign:Antino;actor:UAT-11587 domain,wps-cn.com,prevent,high,2027-04-11,Antino actor domain (Talos plus CSA),campaign:Antino;actor:UAT-11587 domain,oisadjfoinsiduhfnoisdnfosdnoifnsoid.pages.dev,detect,high,2027-04-11,Cloudflare Pages execution-tracking host,campaign:Antino;actor:UAT-11587 domain,d2nq35tel3ucuo.cloudfront.net,detect,high,2027-04-11,CloudFront stage staging host,campaign:Antino;actor:UAT-11587 domain,pub-abfa7742e315485a98a5fafd6dbfb68e.r2.dev,detect,high,2027-04-11,Cloudflare R2 stage and bundle host,campaign:Antino;actor:UAT-11587 domain,pub-0173d1566dcd4fd49fa25f11f14bfe4c.r2.dev,detect,high,2027-04-11,Cloudflare R2 stage and bundle host,campaign:Antino;actor:UAT-11587 domain,my-3lyt6wcp.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-qc39r814.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-662ylt3w.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-6g16qsfe.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-goq6xmbm.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-h3qli6kq.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-sv7c1fzs.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-u0up9qri.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-vtsdod2n.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 domain,my-wgoxp32b.pages.dev,detect,medium,2027-04-11,Cloudflare Pages HTA/WSF delivery host,campaign:Antino;actor:UAT-11587 ipv4,103.27.110.220,detect,low,2027-04-11,Historical serving IP for wps-cn.com payload (may be reassigned),campaign:Antino;actor:UAT-11587 sha256,09ef7c736bccfafefc44d9910d499173b88063b73b221fc0dc9e9105107e5cff,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,0c39264337a1186b2e765e24073399cbdcba118306614eb411e315887af578bd,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,1fadc90b61ce536abda78eb387a7f3d745f00c16775d3f762845ccc0fde567da,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,40e7e77aff603f4c2ef17b3bc8ea836e714d0734a1e5b946e52f95536ec5c91d,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,5c5c060b272cd4a5c3767edc0e9478bd35b7e1756e183d0446a5491bd65519cb,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,971cb2448b5d67dcc1f5eaa10d12e77f213035ad31230dc2ac7a510610a2059d,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,9b7df409c9a89f7536d3ba7b6d43fb6dbac618c8bb52615ba34cc971ad71bbf3,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,b90a4e770869c28fd2140acb3ebdc50c113bb6f096b4bbdb9ac87c349c70e85e,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,ca14ad0344dc7216f6da29a5cbe4237d886cc5257e8c3a48fb4885a311c9b800,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,e2eb7703047b37b28dc34e6990205d758a2454b39bc655b460606745fadcb530,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,e7e3b0bcd6798634adf8b49d305f3a7b7682e4b76db549682a183c5a186df4bb,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,fdbd047031c13a17c9f491c9355f44d587584ebe2b8927be8482e6c236c8e1c1,detect,critical,2027-04-11,Antino backdoor build,campaign:Antino;actor:UAT-11587 sha256,d753a615aedf8e58ffc75b2b7ebd320c0cbe6bcb5cbb885db749a2a85c55d3bf,detect,high,2027-04-11,TestAssembly.dll downloader,campaign:Antino;actor:UAT-11587 sha256,133a46ba41136ca21c93fb08c28446826d8c0d9b7923a16f2d152d595a710098,detect,high,2027-04-11,TestAssembly.dll downloader,campaign:Antino;actor:UAT-11587 sha256,9fc50cf28f86201fda8306926817b1ede41fdd993202515905dd072f6803542f,detect,high,2027-04-11,TestAssembly.dll downloader,campaign:Antino;actor:UAT-11587 sha256,d4cb2f5df16ec9b9c5b796ae55848534e15d4f8b8806f0431108fc7a99a2548a,detect,high,2027-04-11,TestAssembly.dll downloader,campaign:Antino;actor:UAT-11587 sha256,131ac3e0df777910e0a32e43d5744bccb0490750d4c2adc359da41d76d383c46,detect,high,2027-04-11,TestAssembly.dll downloader,campaign:Antino;actor:UAT-11587 sha256,61a8f5add6c35f99c389012dbb2343061fd0b54611b40490b9a7f0b49d707da0,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,747b1d13bdf06956b5da5f47250fefd5284ebcf7961971732c3d348aa1a2d533,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,a13182699a12a8dd9d07c336dbd8de5e9b086b9b09793b7de2e9761aa03ce1dc,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,2f1513c822af0c6635dd3c69dc38f0b2f6e02012ea36415fff111a5d4d5fae05,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,a0e91085f08956a9a7034ace73cee60cb211f5d96f02bc91a026601bde8f2221,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,47f98dfe01759a464e22d5ec55d012dccb38ce010dd73e3ba8d7ffefca12b4b2,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,b3416726a064dd7f657bbb400adeb365eea7f8bb60783ad2d9da1a1d93768731,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,0a6fb71ab1362d065c7ec2678c1e73d9a0721b0e7099d392ba7559bb2eec4970,detect,high,2027-04-11,Stage 2 JScript downloader,campaign:Antino;actor:UAT-11587 sha256,e809da86bd81463347fa7f922d3e088755a94a331889d32acb55aa8f57778a34,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,e6ff096a0562c0042b09d250bd60272ffcd8d72bd95c563842acf765a8dc8bcf,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,4d0fdce4c098635fe9b296c3a82c74645f9885eb5e383aa44a0fe7e50da3ca3f,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,f1ef5fe4c0cdcff13cc750c867728b89719f81437bdc49041edd1ae1f3edb4e8,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,01b5c6acb20e41799a0e96d9d1d6e1c44791883706b6285e874fcb15cc93b31a,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,5a35fcd4458e808ab0fa52bb2a92923b60566ee4d7aaadaac7c95cad3d839562,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,17b53ffa8e005f0e82491d3f9c0a4984c44da52e1668a855c11a137f627c5b4b,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,484ab497072ea09f12187b349f5b1c80754e4942408a009cccb20a2a3c8c6506,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,3a94910eb8022592ce030e6861359f7e980fc1b5a6ccd290cbb071d3e95ed02a,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,6a1dbbfcfe6867ac83d35012b2717084388b4a34707efd0b725466dfd0e8fa56,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,75c12795016ae48b1bddd34a9f5adea63a12f58701eae01e1b4ab3d9dfa1513c,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,bd8ddc8f33e0fe43147ee6f1713654996420a27c5d2cd91751ad67124ebc6fe4,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,b75492466462141c56d97b705f0c606faf272577631dc2822aa8d6bda53633b6,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,23d5f1af8581ae200615d9a66d539f2043c3248b649e862557b379d7e8b7a3ac,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,0b4e5e017c0f0ccac79e13ca5d580a75af67a24ca0763f9ebfdaaeb1ba4fc739,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,ae1b45fb56b9f1b9cb3ee30d2bb1279c9b90b70bb62f8de305d198c6a4e0585e,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,cd3509fa82e506cc6f2eeafa0a45d4b8b76a07edadd29779daf00568febcaba7,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,b8e6e83a73e6e07f8873c364dd2a4b830bceb60758163e2efcd7e387cb604655,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,7969ae5f11fc163049c8eadba06f814f5edece13a707e6087c1c49011a45b838,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,aea5e9029f9212d05bde10f7806d1f2819be45d167e6fd877b9fb1b11088ac90,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,7fa98efba59614cec0b7291aedee98764f8dc037b6cc798c93951a31208e9e32,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 sha256,65f4b9292e91abfa5adf42a03526932930c1c0a436bb186a7948fe6770295788,detect,high,2027-04-11,HTA or WSF stager,campaign:Antino;actor:UAT-11587 domain,REPLACE_WITH_PAGES_DEV_HOST_FROM_YOUR_MAIL_LOGS,detect,medium,2027-04-11,my-token Pages hosts rotate; harvest new ones from your own gateway and proxy logs,campaign:Antino;actor:UAT-11587
This pack does not ship a SentinelOne import block: the import format could not be verified against SentinelOne's own documentation. Export a sample from your console and the block can be added with confidence.
# Behavioral signatures (hunt or alert on these; none is a block) parent=outlook|olk|hxoutlook|chrome|msedge|firefox -> child=mshta.exe|wscript.exe mshta.exe|wscript.exe -> DNS *.pages.dev | *.r2.dev | *.cloudfront.net URL shape: https://my-<8 chars>.pages.dev/File_download?m=<target-id> (per-recipient tracking parameter) Beacon shape: request carrying the lure title in the URL path and ?track in the query string GatherOsState.exe running outside "Windows Kits" (ADK) paths slc.dll / slc.dll.<3 letters> written under Users, ProgramData or Windows\Temp GatherOsState.exe + slc.dll in the same directory sdiagnhost.exe -Embedding -> powershell.exe, working dir C:\Windows\Temp\SDIAG_<GUID>, script result.ps1 HKCU\...\CurrentVersion\Run value -> %LOCALAPPDATA%\Windows GatherOSStateKit\ Process in user-writable path resolving graph.microsoft.com / login.microsoftonline.com every ~10s Sideload bundle download names: <8 chars>GatherOsState.exe.<3 letters>, <8 chars>slc.dll.<3 letters>, <8 chars>OsGather.dat.<3 letters> or OsState.dat.<3 letters> Sample extension sets seen: .luy/.pzs/.syk, .lzj/.iwq/.ael, .thl/.czh/.mxb, .mtm/.fsc/.pgy
# Named malware / tooling / artifacts (all from the Talos report)
Malware: Antino (Rust, 32 and 64-bit; Gen1 Oct 2025, Gen2 Dec 2025 to Jan 2026)
Actor: UAT-11587 (China-nexus, high confidence per Talos)
Sideload host: GatherOsState.exe (Microsoft-signed Windows ADK binary), payload slc.dll, export SLOpen, decoy PE OsGather.dat
Downloader: TestAssembly.dll, AssemblyAttribute GUID b2b3adb0-1669-4b94-86cb-6dd682ddbea3
Gadget chain: System.Windows.Forms.AxHost+State with ActivitySurrogateSelector (BinaryFormatter)
Config: PE section .cfg, 4-byte LE length then JSON XORed with 0xAB 0xCD; keys run, launch_mode
Build artefacts: AntinoApp manifest (Gen2), D:\a\antino\antino\ PDB paths, rsproxy.cn Cargo registry paths
Scripted Diagnostics: sdiageng.dll, CLSID {1F3D8AA5-9EBF-4EE4-85C2-EA40379AEDE8}, package C:\Windows\diagnostics\system\PCW, sdiagnhost.exe
Persistence/staging: %LOCALAPPDATA%\Windows GatherOSStateKit\
Graph C2 markers: Outlook subjects command_req_[session_id] / command_res_[session_id]; OneDrive /antino/heartbeats/{id}.json, /antino_uploads/, /antino_downloads/
Commands: cmd, powershell, system_info, execute_program, list_files, upload_file, download_file, load_shellcode (use_sleep_mask), add_to_run, exit
Fake installer: flashcenter_pp_ax_install_en.exe (microsoft-flash.com, wps-cn.com)
Not Antino-exclusive: d32tpl7xt7175h[.]cloudfront[.]net also appears in UNC6384 reporting (Talos: low-confidence link). Prose only, not an indicator here.# Audit / posture checks (read-only) Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Actions Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings' -Name Enabled -ErrorAction SilentlyContinue Get-ChildItem "$env:LOCALAPPDATA\Windows GatherOSStateKit" -ErrorAction SilentlyContinue Get-ChildItem C:\Windows\Temp -Directory -Filter 'SDIAG_*' -ErrorAction SilentlyContinue Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' | Format-List Get-AppLockerPolicy -Effective -Xml | Select-String -Pattern 'mshta' Resolve-DnsName osc-cdn.com -ErrorAction SilentlyContinue # expect NXDOMAIN or sinkhole after block
Detection Validation Gates
| Gate | Check |
|---|---|
| Telemetry ready | Process creation with parent and command line, DNS lookup with requesting process, PE file write, and autostart registry events are arriving for a pilot host group (CrowdStrike: ProcessRollup2, DnsRequest, PeFileWritten, AsepValueUpdate. SentinelOne: Process Creation, DNS Resolved, File Creation, Registry Value Modified. Defender: DeviceProcessEvents, DeviceEvents, DeviceFileEvents, DeviceRegistryEvents). |
| Benign baseline | Run Q1, Q4, Q7 and Q10 for 14 to 30 days with no action. Stack by FileName and parent. Record legitimate GatherOsState.exe locations (feature upgrades), any sdiagnhost.exe children and per-user Graph clients. |
| Positive tests | In a lab VM only: copy the stock GatherOsState.exe to a temp folder and run it (Q4); run mshta.exe from a browser-launched shortcut with a URL (Q1); run powershell.exe from a parent named sdiagnhost.exe in a test harness (Q7). Do not execute real Antino samples outside an isolated sandbox. |
| Promotion | Hunt first, then Custom IOA in detect mode for Q4, Q6, Q9, Q11 after a clean baseline. Q1, Q7 and Q10 stay hunts until their tuning lists are stable. No query is promoted to prevent. |
Hardening: Tiered
- Block the three actor domains (
osc-cdn.com,microsoft-flash.com,wps-cn.com) at DNS, proxy and mail gateway; they are the only prevent rows in the IOC import. MITRE M1031 Network Intrusion Prevention. Authority: Talos recommendation, repeated by CSA. Verify:Resolve-DnsName osc-cdn.comreturns NXDOMAIN or the sinkhole. - Turn on ASR rules in audit, then block: "Block executable content from email client and webmail" (BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550) and "Block JavaScript or VBScript from launching downloaded executable content" (D3E037E1-3EB8-44C8-A917-57927947596D). MITRE M1040 Behavior Prevention on Endpoint. Authority: Microsoft Defender ASR rules reference. Verify:
Get-MpPreferenceASR ids and actions. - Change the default handler for .hta, .wsf and .wsh to Notepad so a double-click does not execute them. MITRE M1042 Disable or Remove Feature or Program. Authority: best-practice, no formal benchmark.
- Hunt back to September 2025 with Q1 to Q13 and review mail for the osc-cdn.com envelope sender.
- Deny mshta.exe for standard users with WDAC or AppLocker (pilot ring, audit mode first). MITRE M1038 Execution Prevention. Authority: CIS Microsoft Windows benchmark application-control guidance and Microsoft recommended block rules. Verify:
Get-AppLockerPolicy -Effective -Xmlor CQL Q1 returning zero after enforcement. - Disable Windows Script Host for users who do not need it (
HKLM\SOFTWARE\Microsoft\Windows Script Host\Settings\Enabled = 0). MITRE M1042. Authority: best-practice, no formal benchmark. - Restrict where signed Microsoft binaries may run from: publisher rules scoped to Program Files and Windows, so GatherOsState.exe from a user-writable folder cannot execute. MITRE M1038. Authority: Microsoft WDAC guidance.
- Enforce DMARC (p=quarantine or reject) on your own domains and quarantine inbound mail that passes SPF only on a mismatched envelope sender. MITRE M1054 Software Configuration. Authority: NIST SP 800-177 and CISA email-authentication guidance. The Talos delivery succeeded because the impersonated domain was at p=none.
- Egress control for Graph traffic by process and tenant: allow Graph and Entra login only from sanctioned clients, and evaluate Microsoft Tenant Restrictions v2 at the proxy so authentications to tenants you do not own are refused. ⚠ Verify that TRv2 covers app-only client-credential token requests before relying on it; Microsoft documents it for user and external-identity sign-ins. MITRE M1037 Filter Network Traffic.
- Detection around identity, process and behaviour, not destination (CSA): document which workloads need Graph, scope application-only Graph permissions with Role Based Access Control for Applications in Exchange Online, and review Entra app registrations on a schedule. MITRE M1018 User Account Management, M1026 Privileged Account Management.
- Remove mshta.exe and Windows Script Host from endpoints that do not need them once the pilot shows no dependency. MITRE M1042.
Blocking posture: only the three attacker domains ship at prevent. GatherOsState.exe, mshta.exe, wscript.exe, sdiagnhost.exe and powershell.exe are stock Microsoft binaries and are detect-only everywhere in this pack; the application-control rows above restrict where they may run, they do not block the binaries by hash or name for all users.
Deployable Playbooks
Each step carries its prerequisites, reboot requirement and rollback. Run Step 1 and 2 first; Steps 3 and 4 only after the Q1 baseline shows no legitimate HTA or WSF use.
1. DNS sinkhole for the actor domains
# Step 1: sinkhole the three actor domains on a Windows DNS server
# Prerequisites: DnsServer module, DNS admin rights, change ticket. Reboot required: no.
# Rollback: Remove-DnsServerZone -Name <zone> -Force for each zone created below.
foreach ($z in 'osc-cdn.com','microsoft-flash.com','wps-cn.com') {
Add-DnsServerPrimaryZone -Name $z -ZoneFile "$z.dns" -DynamicUpdate None
Add-DnsServerResourceRecordA -ZoneName $z -Name '@' -IPv4Address 0.0.0.0
Add-DnsServerResourceRecordA -ZoneName $z -Name 'www' -IPv4Address 0.0.0.0
}
# Verify: Resolve-DnsName osc-cdn.com -Server <your DNS server> # expect 0.0.0.02. Attack Surface Reduction rules
# Step 2: ASR rules, audit first (2 = audit), then flip to block (1) after 2 weeks of review # Prerequisites: Microsoft Defender Antivirus active; local admin; capture current state first. # Reboot required: no. # Rollback: set the same ids to Disabled (0), or restore the saved state shown below. Get-MpPreference | Select-Object AttackSurfaceReductionRules_Ids, AttackSurfaceReductionRules_Actions | Export-Clixml "$env:TEMP\asr-before.xml" $ids = 'BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550','D3E037E1-3EB8-44C8-A917-57927947596D' Add-MpPreference -AttackSurfaceReductionRules_Ids $ids -AttackSurfaceReductionRules_Actions AuditMode,AuditMode # After review: Add-MpPreference -AttackSurfaceReductionRules_Ids $ids -AttackSurfaceReductionRules_Actions Enabled,Enabled # Rollback: Add-MpPreference -AttackSurfaceReductionRules_Ids $ids -AttackSurfaceReductionRules_Actions Disabled,Disabled # Verify: Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Actions
3. HTA/WSF handlers and Windows Script Host
# Step 3: stop HTA/WSF/WSH double-click execution and disable Windows Script Host
# Prerequisites: local admin; confirm no login scripts or software deployment uses .wsf/.wsh/.hta (stack Q1 first).
# Reboot required: no (sign-out recommended).
# Rollback: restore the saved values below; delete the Enabled value to re-enable WSH.
reg export "HKLM\SOFTWARE\Classes" "$env:TEMP\classes-before.reg" /y
foreach ($t in 'htafile','WSFFile','WSHFile') {
reg add "HKLM\SOFTWARE\Classes\$t\Shell\Open\Command" /ve /t REG_SZ /d "notepad.exe \"%1\"" /f
}
reg add "HKLM\SOFTWARE\Microsoft\Windows Script Host\Settings" /v Enabled /t REG_DWORD /d 0 /f
# Rollback: reg import "$env:TEMP\classes-before.reg"; reg delete "HKLM\SOFTWARE\Microsoft\Windows Script Host\Settings" /v Enabled /f4. AppLocker deny rule for mshta.exe
# Step 4: AppLocker deny rule for mshta.exe (standard users), audit mode first # Prerequisites: Application Identity service running; AppLocker licensed SKU; pilot ring only. # Reboot required: no. # Rollback: Set-AppLockerPolicy -XmlPolicy "$env:TEMP\applocker-before.xml" (saved below). Get-AppLockerPolicy -Effective -Xml | Out-File "$env:TEMP\applocker-before.xml" -Encoding utf8 $xml = @' <AppLockerPolicy Version="1"><RuleCollection Type="Exe" EnforcementMode="AuditOnly"> <FilePathRule Id="7f1a0b5e-4f3c-4c9d-9a1e-0a6f5a1d2c01" Name="Deny mshta for users" Description="Antino hardening" UserOrGroupSid="S-1-1-0" Action="Deny"> <Conditions><FilePathCondition Path="%SYSTEM32%\mshta.exe"/></Conditions> <Exceptions><FilePathCondition Path="%WINDIR%\*"/></Exceptions></FilePathRule> </RuleCollection></AppLockerPolicy> '@ # NOTE: tune the Everyone SID and exceptions to your admin model before enforcing; merge, do not overwrite: $xml | Out-File "$env:TEMP\applocker-add.xml" -Encoding utf8 Set-AppLockerPolicy -XmlPolicy "$env:TEMP\applocker-add.xml" -Merge # Verify: Get-WinEvent -LogName 'Microsoft-Windows-AppLocker/EXE and DLL' -MaxEvents 20
Post-deployment spot check: re-run Q1 and Q4 for 7 days. After Steps 3 and 4 Q1 should return only the pilot ring's tests.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-isolate any host with a Q4, Q6, Q8, Q9 or Q11 hit. Do not reboot first: the sleep-masked shellcode (load_shellcode with use_sleep_mask) is memory-resident. Block the three actor domains at DNS, proxy and mail. | IR lead | Isolation timestamp, host list |
| Isolate: by platform | CrowdStrike: network-contain the host. SentinelOne: network quarantine (Disconnect from Network; confirm the label in your console version). Keep the host powered on for memory capture on all of them. | IR lead | Isolation timestamp, host list |
| Collect | Capture memory, then collect %LOCALAPPDATA%\Windows GatherOSStateKit\, C:\Windows\Temp\SDIAG_*, the HKCU Run key, the staged slc.dll and decoy files, PowerShell 4104 logs and mshta/sdiagnhost process trees. | DFIR | Hashes, memory image, triage package |
| Scope | Run Q1 to Q13 back to September 2025. Pull mail trace for envelope sender osc-cdn.com and clicks to my-*.pages.dev. Extract the Outlook/OneDrive tenant and app details from the implant configuration (.cfg section) in the lab for the report; they are not visible in your tenant logs. | Threat hunter | Affected user and host list |
| Eradicate | Delete the HKCU Run value, the GatherOSStateKit folder and SDIAG_* working directories; remove the sideload bundle; purge delivery mail from all mailboxes. | IR / IT | Before and after listing |
| Recover | Reset credentials and revoke sessions for affected users (the implant ran in user context and exfiltrates files via download_file); reimage hosts that ran load_shellcode or show persistence; confirm blocks and ASR in place. | IT / identity | Reset log, reimage record |
| Report | Share indicators and the lure titles with sector peers and the national CERT; record gaps found. Targeted sectors are government, policy and civil society. | CISO | Report |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | CrowdStrike coverage | SentinelOne |
|---|---|---|---|---|---|
| T1566.002 | Phishing link / sender spoof | Q1, Q3 | - | Partial | Partial: same limit as CrowdStrike |
| T1218.005 | mshta/wscript stager and cloud fetch | Q1, Q2 | Q1 | Good | Good, with assumptions |
| T1059.007 | JScript downloader in mshta | Q1, Q2 | - | Partial | Partial: same limit as CrowdStrike |
| T1620 | .NET deserialization and shellcode in memory | - | - | GAP | GAP |
| T1574.002 | GatherOsState.exe sideloads slc.dll | Q4, Q5, Q6 | Q4, Q6 | Good | Partial: Q5 approximate, Q6 unavailable |
| T1218 | sdiagnhost.exe Scripted Diagnostics proxy | Q7, Q9 | Q7, Q9 | Good | Good, with assumptions |
| T1547.001 | HKCU Run (add_to_run) | Q8, Q9 | Q9 | Good | Good, with assumptions |
| T1102.002 | Graph/Outlook/OneDrive C2 | Q10, Q11 | Q11 | Partial | Partial: same limit as CrowdStrike |
| T1567.002 | Exfil to actor OneDrive | Q10, Q11 | - | Partial | Partial: same limit as CrowdStrike |
| T1204.002 | Fake installer, hashes | Q3, Q12, Q13 | - | Partial | Partial: same limit as CrowdStrike |
Honest gaps
- In-process execution (T1620): the BinaryFormatter gadget chain, TestAssembly.dll and sleep-masked shellcode run inside existing processes. The strongest tell, mshta.exe loading the .NET runtime, needs module-load telemetry that this pack does not query (the field set for that event is not verified here). Sysmon EID 7 covers it where deployed.
- Module load of slc.dll by GatherOsState.exe: approximated by Q6 (file and process co-location in one directory). A bundle staged outside the query window, or a pre-existing slc.dll, is missed.
- Graph C2 content: TLS to a trusted Microsoft host. Q10 and Q11 detect the process, not the traffic. A standalone Antino build with a benign process name running from Program Files evades Q10. The actor's mailbox and OneDrive are in the actor's tenant, so victim-tenant logs will not help.
- Email stage: outside endpoint telemetry. Only mail gateway logs see the osc-cdn.com envelope sender.
- Infrastructure churn: my-token Pages hosts and R2 buckets rotate; the IOC lists will age. Q2 and Q1 are the durable coverage.
- Hash coverage: Talos published 16 further hashes of encrypted orchestrator and gadget resources that are not shipped (ciphertext).
- Validate in your tenant: Q2, Q6, Q9, Q10 and Q11 use the selfJoinFilter/groupBy pattern with
ContextProcessIdandTargetProcessId; confirm that DNS and registry events carry the process id field in your sensor version before treating a zero as clean.
Validation gates (section 11) must be passed before promoting any query to a Custom IOA.
Hunt Summary Ticket
TITLE: Hunt Antino backdoor (UAT-11587): Graph-based C2 via GatherOsState.exe sideload SEVERITY: HIGH (active espionage, government and policy targets) SCOPE: Windows endpoints, mail gateway, proxy and DNS. Lookback to 2025-09. HYPOTHESIS: Antino persists as a GatherOsState.exe + slc.dll sideload with an HKCU Run value and polls Microsoft Graph from a non-browser process. QUERIES: 13 (Q1 to Q13). Run order: Q4, Q6, Q11, Q7, Q9, Q8, Q2, Q1, Q5, Q10, Q3, Q12, Q13. DO FIRST: Q4 and Q6 (sideload), Q11 (Graph lookup from the sideload host), then mail trace for osc-cdn.com. FINDINGS: <fill in per host: path, user, parent chain, hash, first seen> GAPS: In-process .NET deserialization and shellcode are outside endpoint process-creation telemetry; Graph C2 content and the actor tenant are not visible to the victim; mail stage needs gateway logs. ACTIONS: Isolate and image affected hosts; block osc-cdn.com, microsoft-flash.com, wps-cn.com; remove Run value and GatherOSStateKit folder; reset affected credentials; harden per section 12. OWNER: HuntPack VERSION: v0.1 2026-10-11
Changelog
References
| Tier | Source | Used for | Access date |
|---|---|---|---|
| 1 | Cisco Talos: China-nexus UAT-11587 ... Antino backdoor | Primary: chain, capabilities, C2 protocol, IOCs, attribution | 2026-10-11 |
| 2 | Cloud Security Alliance: Antino Backdoor, China-Nexus Espionage Through Microsoft 365 C2 | Hunt guidance, victim-log visibility, domain block recommendation | 2026-10-11 |
| 2 | Security Affairs: Antino backdoor uses your inbox as its control panel | Corroboration of chain and protocol | 2026-10-11 |
| Ref | MITRE ATT&CK | Technique and mitigation mapping | 2026-10-11 |
| Ref | Microsoft Defender: ASR rules reference | Hardening rule ids | 2026-10-11 |
Source snapshots are saved next to this file in Antino-Backdoor-UAT11587-Hunt-sources/.