QuartzLine (CLOUDHAZE): A Working PDF Viewer with the zenith Backdoor
Executive Summary
Attacker objective. QuartzLine is a Windows PDF viewer that works, and that is the point: nobody uninstalls it. Hidden inside is a backdoor module called zenith that gives the operator remote command execution, browser-profile tampering and a way to install more malware. Mandiant tracks it as CLOUDHAZE. [#1] [#2] Expel confirmed 38 incidents at 32 customers by 20 October 2026. [#1] MCNC describes an eCrime campaign with a focus on education. [#4]
How it arrives. A Google ad on an unrelated third-party site redirects through beatramiro[.]com and softwareslizards[.]com to a download from an AWS S3 bucket. Victims were often searching for a consent form or a wallpaper, not a PDF reader. [#1] [#2] [#3] The installer is signed with an EV certificate issued to Guangzhou Guoying Communication Technology Co., Ltd., which Sectigo has revoked with the reason Privilege Withdrawn. [#2]
What it does next. Within seconds of the first check-in the server orders a hidden cmd /C install: copy to %LOCALAPPDATA%\QuartzLine, register the task QuartzlineUpdateCheck, verify with findstr, kill and relaunch Chrome. Days later it pulls a Chrome history uploader, then a self-update, then weeks later the Caira RAT with a second task, CairaServiceCheck. IronBark follows and also spreads through its own ads. [#1] [#2]
Why this pack. Blocking C2 does not clean the host: the tasks keep launching the implant every hour. [#1] [#2] [#3] This pack hunts the persistence, the install folders, the shell chain, the Chrome kill-and-relaunch, the DNS footprint and the follow-on stages, and gives a removal order that does not trigger the task loop. [#4] It ships only QuartzLine-family indicators. Twelve hashes and twenty-six domains are included, 16 as prevent where two independent snapshots agree and 22 as detect.
Defender priority: alert on Q1 and Q3 (the tasks), Q7 (viewer spawning shells) and Q5 (C2 and redirect DNS). For every network block that fired, find the device: it is still infected. Remove the scheduled tasks first, then the processes, then the folders, and reset credentials and sessions for the user.
Source Review & Web Hunter Notes
| # | Tier | Source | Key finding | Snapshot | Carry forward |
|---|---|---|---|---|---|
| #1 | T1 | Expel: QuartzLine: A working PDF viewer with a backdoor inside (2026-10-15, updated 2026-10-21) | Primary vendor casework: 38 incidents at 32 customers by 2026-10-20, Google Ads delivery, timeline, scheduled tasks, IronBark ad funnel and certificate, full IOC list. | 01-expel.txt | yes |
| #2 | T1 | Rogue Authority: A signed PDF viewer that quietly takes orders: the QuartzLine zenith backdoor (2026-10-09, updated 2026-10-25) | Independent reverse engineering: zenith module, terrain.dat, /quarry/ protocol, no User-Agent, certificate revocation, LeafDesk/Canvex build, install order and IOC table. | 02-rogueauthority.txt | yes |
| #3 | T1 | ReliaQuest Threat Research post on X (QuartzLine PDF viewer) | Independent confirmation of the redirect chain through two domains, the S3 installer, both scheduled tasks, two C2 domains, and the warning that quarantining the installer does not remediate. | 03-reliaquest.txt | yes |
| #4 | T2 | MCNC: QuartzLine Infostealer Campaign (PDF linked from the MCNC news page) | Regional operator view: education-sector focus, 6-step cleanup order, URL block list, extra hash and folder names. The HTML page returned HTTP 403, so the linked PDF was snapshotted. | 04-mcnc.txt | yes |
Decisions and conflicts
- Snapshots. Every indicator in this pack was copied from the saved snapshot text in
QuartzLine-CLOUDHAZE-PDFViewer-Hunt-sources/, not from search summaries. Section 10 values were resolved from those files by script and any value not found would have stopped the build. - Prevent needs two sources. Rogue Authority, Expel and ReliaQuest are independent observers. MCNC repeats much of the Expel list, so it does not count as an independent second source. Indicators named only by Expel, only by Rogue Authority or only by MCNC ship as detect.
- Role conflicts. MCNC labels three hashes as initial droppers. Expel names two of them as
hosthealth.exeandupdater-helper.exe, and Rogue Authority and Expel name the third as the QuartzLine update (fielddesk.exe/quartzline.exe). This pack uses the Expel and Rogue Authority roles. - Excluded. The Cloudflare edge addresses MCNC lists for the C2 domains are shared infrastructure and are not shipped. A PDFMaestro domain that only MCNC lists is not shipped because no other snapshot explains it. A search-result summary linking this activity to a differently named actor appears in no saved source and is not used: no actor attribution is made.
- Delivery wording. Expel confirmed Google Ads clicks in two cases and could not see the path in others. MCNC says search-engine malvertising. The pack says Google Ads malvertising as reported by Expel, Rogue Authority and ReliaQuest.
- Named in the sources and used here: QuartzLine, zenith, CLOUDHAZE, Caira, LeafDesk, Canvex, IronBark, Paperline. No other name is used.
- Hostile content. None found in any fetched page.
Hunt Brief & Attack Chain
Hunt hypotheses
| # | Hypothesis | MITRE | Telemetry (plain terms) | Expected FP | Confidence | Queries |
|---|---|---|---|---|---|---|
| H1 | A QuartzLine-family scheduled task exists and relaunches the implant hourly. | T1053.005 | Scheduled task creation (CrowdStrike: ScheduledTaskRegistered. SentinelOne: Task Register. Defender: DeviceEvents ScheduledTaskCreated); process creation with command line (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | None expected | high | Q1, Q3 |
| H2 | Executables run from, or are written to, the per-user install folders. | T1036.005, T1204.002 | Process creation with image path; executable file written (CrowdStrike: PeFileWritten, NewExecutableWritten. SentinelOne: File Creation. Defender: DeviceFileEvents) | Sanctioned product with a folder named Quartz or Canvex | high | Q2, Q11 |
| H3 | The viewer or implant starts shells and admin tools. | T1059.003, T1059.001 | Process creation with parent name | None expected | high | Q7 |
| H4 | Chrome is force-closed and relaunched with the restore bubble hidden, then search settings change. | T1176, T1539 | Process creation with command line and parent | Browser management tools | high | Q8, Q9 |
| H5 | The host resolves campaign domains for C2, ad redirect or search hijack. | T1071.001, T1583.008 | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: no endpoint DNS table, use proxy or DNS logs) | None expected | high | Q5, Q6, Q12 |
| H6 | A Chrome history uploader runs with a pre-signed upload link. | T1567.002 | Process creation with command line and parent | Backup tools run from PowerShell | medium | Q10, Q13 |
| H7 | A known family hash executes or is written. | T1204.002, T1105 | Process creation and executable write with SHA-256 | None expected | high | Q4 |
| H8 | The implant sends check-ins with no User-Agent to /quarry/ paths. | T1071.001 | Web proxy or network sensor logs (outside endpoint telemetry) | Rare custom clients | medium | Native N1 |
Attack chain
| Step | Behavior | Telemetry (plain terms) | Hunt angle |
|---|---|---|---|
| 1 Lure | Google ad on an unrelated site, redirect via beatramiro[.]com and softwareslizards[.]com, download from an S3 bucket. | DNS lookup with requesting process; proxy logs | Q5, Q6, N1, N8 |
| 2 Install | Versioned QuartzLine_1.<n>.exe runs, copies itself to %LOCALAPPDATA%\QuartzLine\quartzline.exe. | Executable written; process creation with image path | Q2, Q11, Q4 |
| 3 Identity and check-in | Writes terrain.dat with a zenith= line, POSTs to /quarry/vein on three Cloudflare-fronted domains with no User-Agent header. | DNS lookup; outbound connection; proxy logs | Q5, Q12, N1, N5 |
| 4 Install orders | Hidden cmd /C copies the binary, writes a task file, checks it with findstr, registers QuartzlineUpdateCheck, deletes the file. | Process creation with parent name | Q7, Q1, Q3 |
| 5 Browser step | taskkill /F on Chrome, relaunch with --hide-crash-restore-bubble --restore-last-session, open thankyou[.]molehawks[.]com, change default search and new-tab page. | Process creation with command line; DNS lookup | Q8, Q9, Q5, N7 |
| 6 History theft | Days later chrome-history-summarizer-v0.0.1.exe is downloaded, run by PowerShell with backup <pre-signed link>, then deleted. | Process creation; executable written; DNS to the history bucket | Q10, Q13, Q6, Q11 |
| 7 Self-update | PowerShell stages quartzline_new.exe, adds --uid= to the task, swaps with up to ten retries (replaceInPlace.ps1). | Process creation with command line | Q10, Q2 |
| 8 Caira RAT | Weeks later deployApp.ps1 runs whoami /groups, installs %LOCALAPPDATA%\Caira\caira.exe and the task CairaServiceCheck. | Process creation; scheduled task creation; DNS | Q1, Q3, Q5, Q7, Q10 |
| 9 IronBark | Third stage, via Caira or its own ad funnel; IronbarkUpdateCheck; separate certificate; same Chrome relaunch. | Scheduled task creation; DNS; process creation | Q1, Q3, Q5, Q8 |
Known gaps: the cause of the first click (the ad), the contents of encrypted C2 traffic, and which Chrome profile files were read or written are not visible in endpoint process telemetry. [#2]
Consolidated IOC Table
38 atomic indicators: 12 SHA-256 hashes and 26 domains. 16 prevent, 22 detect. Prevent rows are named in at least two independent snapshots. Everything else ships as detect. No legitimate vendor binary (Chrome, PowerShell, schtasks, findstr, taskkill) is an indicator in this pack.
| Type | Value | Confidence | Action | Context | Named by |
|---|---|---|---|---|---|
| sha256 | 7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3 | high | prevent | QuartzLine installer original build (paperline.exe) | Expel, Rogue Authority, MCNC |
| sha256 | 25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653 | high | prevent | quartzline.exe / fielddesk.exe newer build pushed as update | Expel, Rogue Authority, MCNC |
| sha256 | 069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527 | high | prevent | chrome-history-summarizer-v0.0.1.exe (Chrome history uploader) | Expel, Rogue Authority |
| sha256 | 74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124 | high | prevent | caira.exe second-stage RAT (also pagestone.exe) | Expel, Rogue Authority, MCNC |
| sha256 | d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b | medium | detect | quartzline_takeover_carrier.exe self-deleting carrier | Expel |
| sha256 | 4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811 | medium | detect | deployApp.ps1 Caira deployment script | Expel |
| sha256 | 3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d | medium | detect | hosthealth.exe short-lived stager | Expel, MCNC |
| sha256 | 0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77 | medium | detect | updater-helper.exe downloads IronBark | Expel, MCNC |
| sha256 | f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8 | medium | detect | IronBark standalone installer | Expel |
| sha256 | 835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca | medium | detect | ironbark.exe third stage | Expel |
| sha256 | 8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86 | medium | detect | leafdesk.exe LeafDesk/Canvex build of the same kit | Rogue Authority |
| sha256 | 90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97 | low | detect | Unnamed dropper listed by one source only | MCNC |
| domain | westbeavers[.]com | high | prevent | QuartzLine C2 (Cloudflare fronted) | Expel, Rogue Authority, ReliaQuest, MCNC |
| domain | motherotters[.]com | high | prevent | QuartzLine C2 (Cloudflare fronted) | Expel, Rogue Authority, ReliaQuest, MCNC |
| domain | healskills[.]com | high | prevent | QuartzLine C2 (Cloudflare fronted) | Expel, Rogue Authority, MCNC |
| domain | topsmagnificentgrade[.]com | high | prevent | Caira C2 | Expel, Rogue Authority, ReliaQuest, MCNC |
| domain | tabbyottercub[.]com | high | prevent | Caira C2 | Expel, Rogue Authority, MCNC |
| domain | flawlessgradecheered[.]com | high | prevent | Caira C2 | Expel, Rogue Authority |
| domain | beatramiro[.]com | high | prevent | Google Ads redirect domain | Expel, Rogue Authority, ReliaQuest, MCNC |
| domain | softwareslizards[.]com | high | prevent | Google Ads redirect domain | Expel, Rogue Authority, ReliaQuest, MCNC |
| domain | thankyou[.]molehawks[.]com | high | prevent | Page opened after Chrome relaunch | Expel, Rogue Authority, MCNC |
| domain | duskhollow.s3.us-east-2.amazonaws.com | high | prevent | Installer and update bucket (exact host only) | Expel, Rogue Authority, MCNC |
| domain | chrome-history-backup.s3.us-east-2.amazonaws.com | high | prevent | History tool download and upload bucket (exact host only) | Expel, Rogue Authority, MCNC |
| domain | alberfine.s3.us-east-2.amazonaws.com | high | prevent | Caira delivery bucket (exact host only) | Expel, Rogue Authority, MCNC |
| domain | foxsilk[.]com | medium | detect | LeafDesk C2 (observed down 2026-10-24) | Rogue Authority |
| domain | runnerfrogs[.]com | medium | detect | LeafDesk C2 | Rogue Authority |
| domain | fasterhedgehogs[.]com | medium | detect | LeafDesk C2 | Rogue Authority |
| domain | leolin15.s3.us-east-2.amazonaws.com | medium | detect | hosthealth.exe delivery bucket (exact host only) | Expel, MCNC |
| domain | tidefern.s3.us-east-2.amazonaws.com | medium | detect | IronBark installer bucket (exact host only) | Expel |
| domain | purplepandagroup[.]com | medium | detect | Ad redirect before IronBark installer | Expel |
| domain | royalproductive[.]com | medium | detect | Ad redirect before IronBark installer | Expel |
| domain | biggerworldclassstandard[.]com | medium | detect | IronBark payload delivery | Expel, MCNC |
| domain | guessgooseberries[.]com | medium | detect | IronBark install reporting | Expel, MCNC |
| domain | commonhedgehogs[.]com | medium | detect | IronBark C2 | Expel, MCNC |
| domain | thankyou[.]charlottedetector[.]com | medium | detect | Page IronBark opens after install | Expel |
| domain | pinkexploratorysearch[.]com | medium | detect | Chrome default search and new-tab hijack | Expel |
| domain | smallerbestsearch[.]com | medium | detect | Chrome default search and new-tab hijack | Expel |
| domain | searchedvictoryresults[.]com | medium | detect | Chrome default search and new-tab hijack | Expel |
Non-atomic indicators
| Kind | Value | Notes |
|---|---|---|
| Scheduled tasks | QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck, HostHealthCacheCheck-<32 hex>, HostHealthCacheCleanup-<32 hex> | Task commands may carry --uid=. Match on task name and path. |
| Folders | %LOCALAPPDATA%\QuartzLine, \Quartz, \Caira, \IronBark, \HostHealthCache, \DevicePerfCache, \PaperLine, \Canvex | Caira holds deployment-<guid> subfolders. |
| Identity files | %LOCALAPPDATA%\QuartzLine\terrain.dat (last line zenith=<id>); %LOCALAPPDATA%\Canvex\topology.dat (pinnacle=<id>) | Settings-style files carrying a per-host ID. |
| URI paths | /quarry/vein, /quarry/deposit, /quarry/sinter, /quarry/geode, /quarry/talc; Caira /piglet/flange, /piglet/trestle, /piglet/corbet; LeafDesk /timber/bracket, /timber/fiber | Geology and carpentry words. Check-ins carry no User-Agent header. |
| Mutexes | Local\pustBacktraceMutex00000000 (Caira), Local\austBacktraceMutex00000000 (LeafDesk) | Single-source (Rogue Authority). |
| Certificates | Guangzhou Guoying Communication Technology Co., Ltd. via Sectigo Public Code Signing CA EV R36, serial 1b56cb4e99fb9444645a1ce7ffc0a46b, revoked 2026-10-09 (Privilege Withdrawn). ZEPHYR LAWN CARE, LLC three-day Microsoft Trusted Signing certificate on LeafDesk. A separate certificate issued to Amir Dow signs the IronBark installer, since revoked. | Falcon does not expose signer or serial as a queryable field. Use native check N6. |
| Campaign identifiers | Build QNPVXZGJYUSLTREHK, tag QZRT07, implant version 6.1.3; LeafDesk build KRMFDXZLQBHGJWPTVN | Appear in decrypted check-in JSON only. |
| Signer mismatch | Signer Guangzhou Guoying, file details Paperline Document Viewer from Summit Works, window title QuartzLine | Three names that do not match is the tell. |
Affected Surface & Telemetry Matrix
| Surface | Telemetry (plain terms) | Priority | Gap |
|---|---|---|---|
| Windows endpoints | Process creation with command line, image path and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); executable written (CrowdStrike: PeFileWritten. SentinelOne: File Creation. Defender: DeviceFileEvents) | High | Settings-style files such as terrain.dat are not executables, so executable-write telemetry does not see them. Use native N5. |
| Scheduled tasks | Scheduled task creation (CrowdStrike: ScheduledTaskRegistered. SentinelOne: Task Register. Defender: DeviceEvents ScheduledTaskCreated) | High | Task Scheduler operational log must be enabled for the native view (N3). |
| DNS and network | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: no endpoint DNS table); outbound connection (CrowdStrike: NetworkConnectIP4. SentinelOne: IP Connect. Defender: DeviceNetworkEvents) | High | C2 is HTTPS behind Cloudflare with an inner scrambling layer: content is outside endpoint telemetry. Missing User-Agent needs proxy logs (N1). |
| Web proxy and DNS filter | Proxy and resolver logs | High | Expel found a case where the only signal was a network block on a host with no EDR agent. Unmanaged devices are outside endpoint telemetry. |
| Chrome profile | Chrome policy state and profile files | Medium | Profile file reads and writes are not visible in process logs. Use N7 and enterprise policy. |
| Code signing | Authenticode signer and serial | Medium | Signer and serial are outside endpoint telemetry. Use N6. |
| Identity provider | Sign-in and session logs for users of an infected device | Medium | Browser-stored passwords, cookies and tokens are treated as exposed. Session theft is outside endpoint telemetry. |
ATT&CK Mapping
| Tactic | Technique | Observed behavior | Query or control |
|---|---|---|---|
| Resource Development | T1583.008 Malvertising | Google Ads on unrelated sites, redirect domains | Q5, N8; DNS filtering |
| Initial Access | T1189 Drive-by Compromise | Ad click to S3 download (user then runs the installer) | Q6, Q11 |
| Execution | T1204.002 Malicious File | Working signed viewer | Q2, Q4 |
| Defense Evasion | T1553.002 Code Signing | EV certificate, later Trusted Signing certificate | N6; WDAC publisher rules |
| Defense Evasion | T1036.005 Match Legitimate Name or Location | Signer, file details and window title all differ | Q2, Q11 |
| Execution | T1059.003 Windows Command Shell | Hidden cmd /C from the implant | Q7 |
| Execution | T1059.001 PowerShell | Staging, in-place swap, history tool and Caira deployment | Q10, Q13 |
| Persistence | T1053.005 Scheduled Task | QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck | Q1, Q3, N3 |
| Command and Control | T1071.001 Web Protocols | HTTPS POST to /quarry/ paths, no User-Agent | Q5, Q12, N1 |
| Defense Evasion | T1027 Obfuscated Files or Information | Inner gzip, XOR, rotate, shuffle, base64 layer | N1 (content not inspectable) |
| Command and Control | T1105 Ingress Tool Transfer | Update, history tool, Caira and IronBark downloads from S3 | Q4, Q6, Q11 |
| Credential Access | T1539 Steal Web Session Cookie | Chrome profile tampering; treat stored cookies as exposed | Q8, N7 |
| Discovery | T1217 Browser Information Discovery | Chrome History database collected | Q10, Q13 |
| Exfiltration | T1567.002 Exfiltration to Cloud Storage | History archive uploaded to a pre-signed S3 link | Q13, Q6 |
| Discovery | T1033 System Owner/User Discovery | whoami /groups in deployApp.ps1 | Q7 |
| Defense Evasion | T1070.004 File Deletion | Task file, history tool and carrier deleted after use | Q10, Q11 |
| Persistence | T1176 Browser Extensions (closest fit) | Search engine and new-tab page changed; extensions not confirmed in the sources | Q8, N7 |
Native Audit-Log Hunts
Non-CQL checks. Replace each placeholder value with your own log source.
| # | Check | Where | What to look for |
|---|---|---|---|
| N1 | Check-ins with no User-Agent | Web proxy, secure web gateway, network sensor | POST requests to paths matching /quarry/(vein|deposit|sinter|geode|talc|stratum|gravel|bedrock|sandstone|seam), /piglet/(flange|trestle|corbet) or /timber/(bracket|fiber), especially from desktop software and with an empty User-Agent. POST /quarry/sinter with application/json is the unencrypted status report. [#2] [#1] |
| N2 | Resolver view | DNS server or DNS filter logs | Lookups for the Section 10 domains. Map each source address to a host; start with unmanaged devices and anything without EDR. [#1] |
| N3 | Task creation and launch | Security 4698, 4699, 4702; Microsoft-Windows-TaskScheduler/Operational 106, 141, 200 | Task names QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck, HostHealthCache*. Enable the operational log first (Playbook 4). [#1] [#4] |
| N4 | Sysmon | Sysmon operational log | Event 1 for the Q7 shell chain, event 11 for terrain.dat and topology.dat, event 22 for the C2 domains. |
| N5 | Filesystem sweep | Each endpoint, admin shell | terrain.dat with a zenith= last line, topology.dat with pinnacle=, and the Section 4 folders under every profile (Playbook 1, step 1.1). [#2] |
| N6 | Signer check | Each endpoint, admin shell | Get-AuthenticodeSignature on binaries under AppData\Local: signer Guangzhou Guoying, serial in the Section 10 certificate block, ZEPHYR LAWN CARE, or any signer whose name does not match the product. [#2] |
| N7 | Chrome state | chrome://policy, chrome://settings/searchEngines, chrome://extensions | Default search engine or new-tab page set to pinkexploratorysearch[.]com, smallerbestsearch[.]com or searchedvictoryresults[.]com. Unknown extensions. [#1] |
| N8 | Browser history and referrers | Proxy logs or managed-browser history export | Visits to beatramiro[.]com or softwareslizards[.]com followed by a download from a campaign S3 bucket on the same host within minutes. [#3] |
| N9 | Identity provider | Sign-in and session logs | For users of an infected device: sign-ins from new locations or devices, session reuse, MFA method changes after the infection date. Revoke sessions regardless. [#1] [#4] |
Hunt Queries: CrowdStrike CQL, SentinelOne PowerQuery and Defender XDR KQL
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.
Pick your portal. Microsoft documents a Share link in advanced hunting but not its URL format, so each "Copy & open Defender" button copies the query and opens Advanced hunting: paste it into the editor.
Thirteen queries on Windows sensor telemetry. Set the time window with the Falcon time picker; each query records its intended lookback in a comment. The campaign has been active since at least September 2026, so run Q1 to Q5 over 30 days and Q4 over 90.
Looks for: creation of QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck or a HostHealthCache task. Deleting the file does not remove the task, so this finds hosts that are still being relaunched every hour.
Known limitations and deployment notes
- PowerQuery: A task registered through a path that does not write the cache key under the monitored hive is not seen.
- PowerQuery: The CQL's task executable field has no equivalent here; read the action from the host after a hit.
- PowerQuery assumes: The Task Scheduler cache key path ends in or contains the task name, so a plain substring pattern after TaskCache\Tree finds the registration.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: Tasks created before the sensor onboarded, or on hosts that do not report this action type, are not captured.
- KQL – Defender XDR assumes: ScheduledTaskCreated is attested in Microsoft-owned hunting repositories rather than on the Learn table page.
- KQL – Defender XDR assumes: AdditionalFields is a JSON string that carries a TaskName key for this action type.
// HUNT: QuartzLine family scheduled tasks registered // MITRE: T1053.005 // CONF: high FP: low COST: low // REQUIRES: Windows sensor with scheduled task registration telemetry // FALSE POSITIVES: None expected. The task names are specific to this campaign. // LOOKBACK: 30d #event_simpleName=ScheduledTaskRegistered | TaskName=/(quartzlineupdatecheck|cairaservicecheck|ironbarkupdatecheck|hosthealthcache(check|cleanup)-[0-9a-f]{32})/i | table([@timestamp, ComputerName, UserName, TaskName, TaskExecutable]) | sort(@timestamp, order=desc, limit=200)
4 required fields · View requirements
Required telemetry
- Registry Value Modified
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nameregistry.keyPath: Registry key path
Recommended fields
src.process.name: Registering processsrc.process.user: User
Readiness test
event.type = 'Registry Value Modified' registry.keyPath = * | limit 5 | columns event.type, event.time, endpoint.name, registry.keyPath
// HUNT: QuartzLine family scheduled tasks registered
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1053.005
// CONF: high | FP: low
// FALSE POSITIVES: None expected. The task names are specific to this campaign.
// EQUIVALENCE: approximate-analytic - SentinelOne has no attested scheduled-task registration event, so the hunt watches the Task Scheduler registry cache instead: a value written under TaskCache\Tree for one of the campaign task names. That fires for any registration method, but it keys on the registry write rather than the task-registration event.
// REQUIRES: SentinelOne Registry Value Modified telemetry for the Task Scheduler cache keys
// TUNING: None needed; the task names are specific to this campaign. Pivot on src.process.name to see what registered the task.
// LOOKBACK: 30d; set the console time range or the query window 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 task registered through a path that does not write the cache key under the monitored hive is not seen. The CQL's task executable field has no equivalent here; read the action from the host after a hit.
// VALIDATION LEVEL: static-reviewed
event.type = 'Registry Value Modified'
registry.keyPath matches '\\\\TaskCache\\\\Tree\\\\.*(quartzlineupdatecheck|cairaservicecheck|ironbarkupdatecheck|hosthealthcache(check|cleanup)-[0-9a-f]{32})'
| columns event.time, endpoint.name, src.process.user, registry.keyPath, registry.valueName, registry.value, src.process.name, agent.uuid
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeAdditionalFields: Action details
Recommended fields
InitiatingProcessFileName: Registering process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "ScheduledTaskCreated" | project Timestamp, ActionType, AdditionalFields | take 5
// HUNT: QuartzLine family scheduled tasks registered
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1053.005
// CONF: high | FP: low
// FALSE POSITIVES: None expected. The task names are specific to this campaign.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a scheduled task creation whose task name matches the campaign pattern. The task name is read from the action's additional fields. matches regex with the (?i) prefix reproduces the CQL /i flag.
// REQUIRES: Defender for Endpoint scheduled-task telemetry (DeviceEvents, ScheduledTaskCreated)
// TUNING: None needed; the task names are specific to this campaign.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Tasks created before the sensor onboarded, or on hosts that do not report this action type, are not captured.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType == "ScheduledTaskCreated"
| extend TaskName = tostring(parse_json(AdditionalFields)["TaskName"])
| where TaskName matches regex @"(?i)(quartzlineupdatecheck|cairaservicecheck|ironbarkupdatecheck|hosthealthcache(check|cleanup)-[0-9a-f]{32})"
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, TaskName, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: any program started from %LOCALAPPDATA% under QuartzLine, Quartz, Caira, IronBark, HostHealthCache, DevicePerfCache, PaperLine or Canvex. Install is per-user, so admin lockdown does not stop it. FP: a sanctioned product that uses one of the folder names. Confirm by hash and signer, then exclude that name.
Known limitations and deployment notes
- PowerQuery: A process the agent did not observe starting is not captured.
- PowerQuery assumes: tgt.process.image.path holds the full path of the created process.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- PowerQuery assumes: Synthetic process records that the CQL also reads have no separate event type here; the Process Creation event covers real starts only.
- KQL – Defender XDR: A process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: FolderPath holds the full image path of the created process, including the file name.
// HUNT: Executables running from the per-user install folders // MITRE: T1036.005, T1204.002 // CONF: high FP: medium COST: low // REQUIRES: Windows process creation telemetry with image path // FALSE POSITIVES: A legitimate product that installs into a folder named Quartz, Canvex or PaperLine. // TUNING: If a folder name belongs to a sanctioned product, drop that name from the group and confirm by SHA256HashData and signer before excluding. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ImageFileName=/\\AppData\\Local\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\[^\\]+\.exe$/i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData]) | sort(@timestamp, order=desc, limit=200)
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.image.path: Created process path
Recommended fields
tgt.process.cmdline: Created command linesrc.process.name: Creating process
Optional fields
tgt.process.image.sha256: Hash. Population varies by tenant; verify with the readiness test.
Readiness test
event.type = 'Process Creation' tgt.process.image.path = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.image.path
// HUNT: Executables running from the per-user install folders // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1036.005, T1204.002 // CONF: high | FP: medium // FALSE POSITIVES: A legitimate product that installs into a folder named Quartz, Canvex or PaperLine. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose image sits directly in one of the per-user install folders under AppData Local and ends in .exe. On a Process Creation event the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the image path // TUNING: If a folder name belongs to a sanctioned product, drop that name from the group and confirm by hash and signer before excluding. // LOOKBACK: 30d; set the console time range or the query window 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 process the agent did not observe starting is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.image.path matches '\\\\AppData\\\\Local\\\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\\\[^\\\\]+\\.exe$' | 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 200
Automated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFolderPath: Created process path
Recommended fields
ProcessCommandLine: Created command lineInitiatingProcessFileName: Initiating process
Optional fields
SHA1: Hash. SHA256 is often unpopulated in this table; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FolderPath, ProcessCommandLine | take 5
// HUNT: Executables running from the per-user install folders // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1036.005, T1204.002 // CONF: high | FP: medium // FALSE POSITIVES: A legitimate product that installs into a folder named Quartz, Canvex or PaperLine. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose full path sits directly in one of the per-user install folders under AppData Local and ends in .exe. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: If a folder name belongs to a sanctioned product, drop that name from the group and confirm by hash and signer before excluding. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A process the sensor did not observe starting is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where FolderPath matches regex @"(?i)\\AppData\\Local\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\[^\\]+\.exe$" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: quartzline.exe --update-check, caira.exe --check and ironbark.exe --update-check, which the tasks run hourly and daily, often with a per-host --uid=.
Known limitations and deployment notes
- PowerQuery: A process the agent did not observe starting is not captured.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- PowerQuery assumes: The word-boundary escape is honoured by the SentinelOne regex engine.
- KQL – Defender XDR: A process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: The word-boundary escape is honoured by the Kusto regex engine.
// HUNT: Scheduled-task launches of the implant (--update-check / --check) // MITRE: T1053.005 // CONF: high FP: low COST: low // REQUIRES: Windows process creation telemetry with command line // FALSE POSITIVES: None expected. A product that happens to be called caira.exe with these exact flags would be rare. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | FileName=/^(quartzline|caira|ironbark)\.exe$/i | CommandLine=/--(update-check|check)\b/i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData]) | sort(@timestamp, order=desc, limit=200)
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.cmdline: Created command line
Recommended fields
src.process.name: Creating processtgt.process.image.path: Created process path
Optional fields
tgt.process.image.sha256: Hash. Population varies by tenant; verify with the readiness test.
Readiness test
event.type = 'Process Creation' tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.name, tgt.process.cmdline
// HUNT: Scheduled-task launches of the implant (--update-check / --check) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1053.005 // CONF: high | FP: low // FALSE POSITIVES: None expected. A product that happens to be called caira.exe with these exact flags would be rare. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process named quartzline, caira or ironbark whose command line carries the update-check or check flag. On a Process Creation event the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the command line // TUNING: None needed; confirm the hit is not a product that happens to share the name and flags. // LOOKBACK: 30d; set the console time range or the query window 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 process the agent did not observe starting is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.name matches '^(quartzline|caira|ironbark)\\.exe$' tgt.process.cmdline matches '--(update-check|check)\\b' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.image.path, tgt.process.cmdline, tgt.process.image.sha256, agent.uuid | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Optional fields
SHA1: Hash. SHA256 is often unpopulated in this table; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: Scheduled-task launches of the implant (--update-check / --check) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1053.005 // CONF: high | FP: low // FALSE POSITIVES: None expected. A product that happens to be called caira.exe with these exact flags would be rare. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process named quartzline, caira or ironbark whose command line carries the update-check or check flag. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: None needed; confirm the hit is not a product that happens to share the name and flags. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A process the sensor did not observe starting is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where FileName matches regex @"(?i)^(quartzline|caira|ironbark)\.exe$" | where ProcessCommandLine matches regex @"(?i)--(update-check|check)\b" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: any of the twelve SHA-256 values in Section 10 on a process start or an executable write. Use 90 days where retention allows.
Known limitations and deployment notes
- PowerQuery: A file modified in place after it was written is not matched by File Creation.
- PowerQuery assumes: tgt.process.image.sha256 and tgt.file.sha256 are populated on the tenant.
- PowerQuery assumes: File Creation covers a written executable; the CQL's separate executable-written event types have no distinct equivalent.
- PowerQuery assumes: in:anycase makes the hash comparison case-insensitive, which reproduces the CQL /i intent.
- KQL – Defender XDR: A started process whose image was not written inside the window is not matched; the process-execution half is not covered.
- KQL – Defender XDR: Advanced Hunting keeps 30 days, so hashes seen between 31 and 90 days ago appear only on the CQL tab.
- KQL – Defender XDR: SHA256 is often unpopulated; an empty result is not proof of absence.
- KQL – Defender XDR assumes: SHA256 is populated on file events for the tenant.
// HUNT: Known QuartzLine family hashes executed or written // MITRE: T1204.002, T1105 // CONF: high FP: low COST: low // REQUIRES: Windows process and file-write telemetry with SHA-256 // FALSE POSITIVES: None expected for the hash set. See the IOC table for which hashes are prevent and which are detect. // LOOKBACK: 90d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2|PeFileWritten|NewExecutableWritten)$/ | SHA256HashData=/^(7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3|25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653|069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527|74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124|d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b|4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811|3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d|0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77|f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8|835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca|8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86|90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97)$/i | table([@timestamp, #event_simpleName, ComputerName, UserName, FileName, ImageFileName, TargetFileName, SHA256HashData, CommandLine]) | sort(@timestamp, order=desc, limit=200)
5 required fields · View requirements
Required telemetry
- Process Creation
- File Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.image.sha256: Created process hashtgt.file.sha256: Written file hash
Recommended fields
tgt.file.path: Written file pathsrc.process.name: Acting process
Readiness test
event.type = 'File Creation' tgt.file.sha256 = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.image.sha256, tgt.file.sha256
// HUNT: Known QuartzLine family hashes executed or written
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1204.002, T1105
// CONF: high | FP: low
// FALSE POSITIVES: None expected for the hash set. See the IOC table for which hashes are prevent and which are detect.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: the SHA-256 of a started process or of a file written to disk is one of the twelve published family hashes. The process half reads the created process hash and the file half reads the written file hash.
// REQUIRES: SentinelOne Process Creation and File Creation telemetry with SHA-256
// TUNING: None needed for the hash set. The IOC table says which hashes are prevent and which are detect.
// LOOKBACK: 30d on this tab; the CQL tab covers 90d. Set the console time range or the query window 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 modified in place after it was written is not matched by File Creation.
// VALIDATION LEVEL: static-reviewed
(event.type = 'Process Creation' tgt.process.image.sha256 in:anycase ('7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3','25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653','069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527','74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124','d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b','4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811','3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d','0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77','f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8','835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca','8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86','90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97')) or (event.type = 'File Creation' tgt.file.sha256 in:anycase ('7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3','25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653','069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527','74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124','d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b','4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811','3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d','0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77','f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8','835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca','8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86','90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97'))
| columns event.type, event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.image.sha256, tgt.file.path, tgt.file.sha256, agent.uuid
| limit 200Automated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceFileEvents
Required fields
Timestamp: Event timeSHA256: File hash
Recommended fields
FolderPath: File pathInitiatingProcessFileName: Writing process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceFileEvents | where Timestamp > ago(1d) | project Timestamp, SHA256, FolderPath | take 5
// HUNT: Known QuartzLine family hashes executed or written
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1204.002, T1105
// CONF: high | FP: low
// FALSE POSITIVES: None expected for the hash set. See the IOC table for which hashes are prevent and which are detect.
// EQUIVALENCE: telemetry-gap - Partial pivot: only the file-written half is shown, on DeviceFileEvents. The process-execution half needs a second table and the gate accepts one table per query. SHA256 is often unpopulated, and SHA1 is not in the published indicator set.
// REQUIRES: Defender for Endpoint file-event telemetry (DeviceFileEvents) with SHA256 populated
// TUNING: Run the CQL tab for the process-execution half. Check SHA256 population before trusting an empty result.
// LOOKBACK: 30d (Advanced Hunting retention; the CQL tab covers 90d)
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A started process whose image was not written inside the window is not matched; the process-execution half is not covered. Advanced Hunting keeps 30 days, so hashes seen between 31 and 90 days ago appear only on the CQL tab. SHA256 is often unpopulated; an empty result is not proof of absence.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceFileEvents
| where Timestamp >= ago(30d)
| where SHA256 in~ ("7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3", "25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653", "069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527", "74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124", "d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b", "4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811", "3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d", "0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77", "f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8", "835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca", "8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86", "90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, FileName, FolderPath, SHA256
| sort by Timestamp desc
| take 200Looks for: lookups for C2, ad-redirect, search-hijack and post-install domains. The requesting process tells you whether this is a browser visit or an implant check-in.
Known limitations and deployment notes
- PowerQuery: Lookups answered from a cache the agent does not see are not captured.
- PowerQuery assumes: event.dns.request is the populated DNS name field; the vendor docs name dns.request, so check which one the tenant fills.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: Hosts that do not report DnsQueryResponse show nothing; an empty result is not proof of absence.
- KQL – Defender XDR assumes: DnsQueryResponse is attested in Microsoft-owned hunting repositories rather than on the Learn table page.
- KQL – Defender XDR assumes: The queried name sits under DnsQueryString or QueryName in AdditionalFields; the readiness test shows which key the tenant fills.
// HUNT: DNS lookups for QuartzLine, Caira, IronBark and LeafDesk infrastructure // MITRE: T1071.001, T1583.008 // CONF: high FP: low COST: low // REQUIRES: Windows DNS request telemetry with requesting process // FALSE POSITIVES: None expected. A hit from a browser means the user reached the ad chain or a hijacked search page. A hit from quartzline.exe, caira.exe or ironbark.exe means active C2. // LOOKBACK: 30d #event_simpleName=DnsRequest | DomainName=/((^|\.)(westbeavers|motherotters|healskills|topsmagnificentgrade|tabbyottercub|flawlessgradecheered|foxsilk|runnerfrogs|fasterhedgehogs|commonhedgehogs|guessgooseberries|biggerworldclassstandard|beatramiro|softwareslizards|purplepandagroup|royalproductive|pinkexploratorysearch|smallerbestsearch|searchedvictoryresults)\.com$|^thankyou\.(molehawks|charlottedetector)\.com$)/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName]) | sort(@timestamp, order=desc, limit=200)
4 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nameevent.dns.request: Resolved name
Recommended fields
src.process.name: Requesting process
Fallbacks
event.dns.request→dns.request: Same value under the vendor documented field name.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, event.dns.request, src.process.name
// HUNT: DNS lookups for QuartzLine, Caira, IronBark and LeafDesk infrastructure // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1071.001, T1583.008 // CONF: high | FP: low // FALSE POSITIVES: None expected. A hit from a browser means the user reached the ad chain or a hijacked search page. A hit from quartzline.exe, caira.exe or ironbark.exe means active C2. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a DNS resolution for one of the campaign second-level domains, or the two thankyou hosts. The acting process on a DNS event is src.process.*. // REQUIRES: SentinelOne DNS Resolved telemetry with the requesting process // TUNING: None needed. A browser hit means the user reached the ad chain or a hijacked search page; a hit from quartzline.exe, caira.exe or ironbark.exe means active C2. // LOOKBACK: 30d; set the console time range or the query window 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: Lookups answered from a cache the agent does not see are not captured. // VALIDATION LEVEL: static-reviewed event.type = 'DNS Resolved' event.dns.request matches '((^|\\.)(westbeavers|motherotters|healskills|topsmagnificentgrade|tabbyottercub|flawlessgradecheered|foxsilk|runnerfrogs|fasterhedgehogs|commonhedgehogs|guessgooseberries|biggerworldclassstandard|beatramiro|softwareslizards|purplepandagroup|royalproductive|pinkexploratorysearch|smallerbestsearch|searchedvictoryresults)\\.com$|^thankyou\\.(molehawks|charlottedetector)\\.com$)' | columns event.time, endpoint.name, src.process.user, event.dns.request, src.process.name, src.process.image.path, agent.uuid | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeAdditionalFields: Query details
Recommended fields
InitiatingProcessFileName: Requesting process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "DnsQueryResponse" | project Timestamp, ActionType, AdditionalFields | take 5
// HUNT: DNS lookups for QuartzLine, Caira, IronBark and LeafDesk infrastructure // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1071.001, T1583.008 // CONF: high | FP: low // FALSE POSITIVES: None expected. A hit from a browser means the user reached the ad chain or a hijacked search page. A hit from quartzline.exe, caira.exe or ironbark.exe means active C2. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate on the DNS name. Defender has no endpoint DNS table, so the name comes from the DnsQueryResponse action's additional fields. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint DNS response telemetry (DeviceEvents, DnsQueryResponse) // TUNING: None needed. A browser hit means the user reached the ad chain or a hijacked search page; a hit from quartzline.exe, caira.exe or ironbark.exe means active C2. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Hosts that do not report DnsQueryResponse show nothing; an empty result is not proof of absence. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceEvents | where Timestamp >= ago(30d) | where ActionType == "DnsQueryResponse" | extend QueryName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"])) | where QueryName matches regex @"(?i)((^|\.)(westbeavers|motherotters|healskills|topsmagnificentgrade|tabbyottercub|flawlessgradecheered|foxsilk|runnerfrogs|fasterhedgehogs|commonhedgehogs|guessgooseberries|biggerworldclassstandard|beatramiro|softwareslizards|purplepandagroup|royalproductive|pinkexploratorysearch|smallerbestsearch|searchedvictoryresults)\.com$|^thankyou\.(molehawks|charlottedetector)\.com$)" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, QueryName, InitiatingProcessFileName, InitiatingProcessFolderPath | sort by Timestamp desc | take 200
Looks for: lookups for the exact bucket hosts used for installers, the history tool, Caira and IronBark. Match the exact host only: ReliaQuest warns against broad S3 blocking.
Known limitations and deployment notes
- PowerQuery: A bucket in another region, or a path-style URL on the shared S3 host, is not matched.
- PowerQuery assumes: event.dns.request is the populated DNS name field; the vendor docs name dns.request, so check which one the tenant fills.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: Hosts that do not report DnsQueryResponse show nothing; an empty result is not proof of absence.
- KQL – Defender XDR assumes: DnsQueryResponse is attested in Microsoft-owned hunting repositories rather than on the Learn table page.
- KQL – Defender XDR assumes: The queried name sits under DnsQueryString or QueryName in AdditionalFields; the readiness test shows which key the tenant fills.
// HUNT: DNS lookups for the campaign S3 buckets (exact bucket hosts only) // MITRE: T1105, T1567.002 // CONF: medium FP: low COST: low // REQUIRES: Windows DNS request telemetry with requesting process // FALSE POSITIVES: A bucket name could be reused by an unrelated owner after takedown. Do not block amazonaws.com or S3 broadly. // LOOKBACK: 30d #event_simpleName=DnsRequest | DomainName=/^(duskhollow|chrome-history-backup|alberfine|tidefern|leolin15)\.s3\.us-east-2\.amazonaws\.com$/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName]) | sort(@timestamp, order=desc, limit=200)
4 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nameevent.dns.request: Resolved name
Recommended fields
src.process.name: Requesting process
Fallbacks
event.dns.request→dns.request: Same value under the vendor documented field name.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * | limit 5 | columns event.type, event.time, endpoint.name, event.dns.request, src.process.name
// HUNT: DNS lookups for the campaign S3 buckets (exact bucket hosts only) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1105, T1567.002 // CONF: medium | FP: low // FALSE POSITIVES: A bucket name could be reused by an unrelated owner after takedown. Do not block amazonaws.com or S3 broadly. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a DNS resolution for one of the five exact S3 bucket hosts in us-east-2. The acting process on a DNS event is src.process.*. // REQUIRES: SentinelOne DNS Resolved telemetry with the requesting process // TUNING: Do not widen this to amazonaws.com or S3 broadly. A bucket name can be reused by an unrelated owner after takedown, so confirm the requesting process. // LOOKBACK: 30d; set the console time range or the query window 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 bucket in another region, or a path-style URL on the shared S3 host, is not matched. // VALIDATION LEVEL: static-reviewed event.type = 'DNS Resolved' event.dns.request matches '^(duskhollow|chrome-history-backup|alberfine|tidefern|leolin15)\\.s3\\.us-east-2\\.amazonaws\\.com$' | columns event.time, endpoint.name, src.process.user, event.dns.request, src.process.name, src.process.image.path, agent.uuid | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeAdditionalFields: Query details
Recommended fields
InitiatingProcessFileName: Requesting process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "DnsQueryResponse" | project Timestamp, ActionType, AdditionalFields | take 5
// HUNT: DNS lookups for the campaign S3 buckets (exact bucket hosts only) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1105, T1567.002 // CONF: medium | FP: low // FALSE POSITIVES: A bucket name could be reused by an unrelated owner after takedown. Do not block amazonaws.com or S3 broadly. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate on the DNS name. Defender has no endpoint DNS table, so the name comes from the DnsQueryResponse action's additional fields. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint DNS response telemetry (DeviceEvents, DnsQueryResponse) // TUNING: Do not widen this to amazonaws.com or S3 broadly. A bucket name can be reused by an unrelated owner after takedown, so confirm the requesting process. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Hosts that do not report DnsQueryResponse show nothing; an empty result is not proof of absence. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceEvents | where Timestamp >= ago(30d) | where ActionType == "DnsQueryResponse" | extend QueryName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"])) | where QueryName matches regex @"(?i)^(duskhollow|chrome-history-backup|alberfine|tidefern|leolin15)\.s3\.us-east-2\.amazonaws\.com$" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, QueryName, InitiatingProcessFileName, InitiatingProcessFolderPath | sort by Timestamp desc | take 200
Looks for: the hidden cmd /C install, task registration with schtasks, findstr verification, taskkill on Chrome and whoami /groups, all started by the implant itself.
Known limitations and deployment notes
- PowerQuery: A shell started by a process the agent did not observe starting is not captured.
- PowerQuery assumes: On Process Creation, src.process.* is the creator and tgt.process.* is the new process.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: A shell started by a process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: in~ is case-insensitive, which reproduces the CQL /i intent.
// HUNT: Viewer or implant spawning shells and admin tools // MITRE: T1059.003, T1059.001, T1053.005, T1033 // CONF: high FP: low COST: low // REQUIRES: Windows process creation telemetry with parent name // FALSE POSITIVES: None expected. A PDF viewer has no reason to start cmd, PowerShell, schtasks, findstr, taskkill or whoami. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(quartzline|paperline|fielddesk|pagestone|leafdesk|caira|ironbark)\.exe$/i | FileName=/^(cmd|powershell|schtasks|findstr|taskkill|whoami)\.exe$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine]) | sort(@timestamp, order=desc, limit=200)
5 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creating processtgt.process.name: Created process name
Recommended fields
tgt.process.cmdline: Created command line
Readiness test
event.type = 'Process Creation' src.process.name = * tgt.process.name = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, tgt.process.name
// HUNT: Viewer or implant spawning shells and admin tools // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1059.003, T1059.001, T1053.005, T1033 // CONF: high | FP: low // FALSE POSITIVES: None expected. A PDF viewer has no reason to start cmd, PowerShell, schtasks, findstr, taskkill or whoami. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a viewer or implant process creating a shell or admin tool. On a Process Creation event the creator is src.process.* and the created process is tgt.process.*, so the CQL's parent field maps to src.process.name. // REQUIRES: SentinelOne Process Creation telemetry with the creating process // TUNING: None needed; a PDF viewer has no reason to start these tools. // LOOKBACK: 30d; set the console time range or the query window 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 shell started by a process the agent did not observe starting is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' src.process.name matches '^(quartzline|paperline|fielddesk|pagestone|leafdesk|caira|ironbark)\\.exe$' tgt.process.name matches '^(cmd|powershell|schtasks|findstr|taskkill|whoami)\\.exe$' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline, agent.uuid | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameInitiatingProcessFileName: Initiating process
Recommended fields
ProcessCommandLine: Created command line
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, InitiatingProcessFileName | take 5
// HUNT: Viewer or implant spawning shells and admin tools
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1059.003, T1059.001, T1053.005, T1033
// CONF: high | FP: low
// FALSE POSITIVES: None expected. A PDF viewer has no reason to start cmd, PowerShell, schtasks, findstr, taskkill or whoami.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a viewer or implant process creating a shell or admin tool. The creator is InitiatingProcessFileName and the created process is FileName.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: None needed; a PDF viewer has no reason to start these tools.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A shell started by a process the sensor did not observe starting is not captured.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("quartzline.exe", "paperline.exe", "fielddesk.exe", "pagestone.exe", "leafdesk.exe", "caira.exe", "ironbark.exe")
| where FileName in~ ("cmd.exe", "powershell.exe", "schtasks.exe", "findstr.exe", "taskkill.exe", "whoami.exe")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Chrome started with --hide-crash-restore-bubble --restore-last-session by anything other than a user shell or Chrome itself. This is the second half of the kill-and-relaunch that precedes the search-hijack. FP: browser-management or kiosk tools that restore sessions. A parent of quartzline.exe, caira.exe or ironbark.exe is never benign.
Known limitations and deployment notes
- PowerQuery: A Chrome launch the agent did not observe starting is not captured.
- PowerQuery assumes: contains and matches are case-insensitive by default, which reproduces the CQL /i intent.
- PowerQuery assumes: On Process Creation, src.process.* is the creator and tgt.process.* is the new process.
- KQL – Defender XDR: A Chrome launch the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: Both flags are matched as plain substrings.
// HUNT: Chrome relaunched with the crash-restore bubble hidden by a non-shell parent // MITRE: T1176, T1539 // CONF: high FP: medium COST: low // REQUIRES: Windows process creation telemetry with command line and parent name // FALSE POSITIVES: Browser management or kiosk tools that restore sessions with the same flags. // TUNING: Exclude parent names of sanctioned browser-management tools after confirming them. A parent of quartzline.exe, caira.exe or ironbark.exe is never benign. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | FileName=/^chrome\.exe$/i | CommandLine=/--hide-crash-restore-bubble/i | CommandLine=/--restore-last-session/i | ParentBaseFileName!=/^(explorer|chrome|msedge)\.exe$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, CommandLine]) | sort(@timestamp, order=desc, limit=200)
6 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.cmdline: Created command linesrc.process.name: Creating process
Recommended fields
src.process.user: User
Readiness test
event.type = 'Process Creation' tgt.process.name = * tgt.process.cmdline = * src.process.name = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, tgt.process.name, tgt.process.cmdline
// HUNT: Chrome relaunched with the crash-restore bubble hidden by a non-shell parent // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1176, T1539 // CONF: high | FP: medium // FALSE POSITIVES: Browser management or kiosk tools that restore sessions with the same flags. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: chrome.exe created with both the crash-bubble and restore-session flags by a creator that is not explorer, chrome or msedge. The creator is src.process.* and the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the command line and creating process // TUNING: Exclude creators of sanctioned browser-management tools after confirming them. A creator of quartzline.exe, caira.exe or ironbark.exe is never benign. // LOOKBACK: 30d; set the console time range or the query window 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 Chrome launch the agent did not observe starting is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.name matches '^chrome\\.exe$' tgt.process.cmdline contains '--hide-crash-restore-bubble' tgt.process.cmdline contains '--restore-last-session' !(src.process.name matches '^(explorer|chrome|msedge)\\.exe$') | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.cmdline, agent.uuid | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command lineInitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine, InitiatingProcessFileName | take 5
// HUNT: Chrome relaunched with the crash-restore bubble hidden by a non-shell parent
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1176, T1539
// CONF: high | FP: medium
// FALSE POSITIVES: Browser management or kiosk tools that restore sessions with the same flags.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: chrome.exe created with both flags by a creator that is not explorer, chrome or msedge. The creator is InitiatingProcessFileName. contains is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude creators of sanctioned browser-management tools after confirming them. A creator of quartzline.exe, caira.exe or ironbark.exe is never benign.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A Chrome launch the sensor did not observe starting is not captured.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where FileName =~ "chrome.exe"
| where ProcessCommandLine contains "--hide-crash-restore-bubble"
| where ProcessCommandLine contains "--restore-last-session"
| where InitiatingProcessFileName !in~ ("explorer.exe", "chrome.exe", "msedge.exe")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: the force-close step that precedes the relaunch. Weak alone, so pair it with Q2, Q3, Q7 or Q8 on the same host. FP: help-desk scripts and patchers that close Chrome. Exclude known parents and pivot on the host.
Known limitations and deployment notes
- PowerQuery: taskkill started by a creator other than cmd or powershell is not captured.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- PowerQuery assumes: On Process Creation, src.process.* is the creator and tgt.process.* is the new process.
- KQL – Defender XDR: taskkill started by a creator other than cmd or powershell is not captured.
- KQL – Defender XDR assumes: The command line is matched as a plain substring.
// HUNT: taskkill used against Chrome by a shell // MITRE: T1059.003 // CONF: medium FP: medium COST: low // REQUIRES: Windows process creation telemetry with command line and parent name // FALSE POSITIVES: Help desk scripts and software updaters that close Chrome before patching. // TUNING: Exclude known patching and help-desk parents. Keep any event within minutes of a Q2, Q3 or Q7 hit on the same ComputerName. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | FileName=/^taskkill\.exe$/i | CommandLine=/chrome\.exe/i | ParentBaseFileName=/^(cmd|powershell)\.exe$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, CommandLine]) | sort(@timestamp, order=desc, limit=200)
6 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.cmdline: Created command linesrc.process.name: Creating process
Recommended fields
src.process.user: User
Readiness test
event.type = 'Process Creation' tgt.process.name = * tgt.process.cmdline = * src.process.name = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, tgt.process.name, tgt.process.cmdline
// HUNT: taskkill used against Chrome by a shell // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1059.003 // CONF: medium | FP: medium // FALSE POSITIVES: Help desk scripts and software updaters that close Chrome before patching. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: taskkill.exe whose command line names chrome.exe, started by cmd or powershell. The creator is src.process.* and the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the command line and creating process // TUNING: Exclude known patching and help-desk creators. Keep any event within minutes of a Q2, Q3 or Q7 hit on the same host. // LOOKBACK: 30d; set the console time range or the query window 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: taskkill started by a creator other than cmd or powershell is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.name matches '^taskkill\\.exe$' tgt.process.cmdline matches 'chrome\\.exe' src.process.name matches '^(cmd|powershell)\\.exe$' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.cmdline, agent.uuid | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command lineInitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine, InitiatingProcessFileName | take 5
// HUNT: taskkill used against Chrome by a shell
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1059.003
// CONF: medium | FP: medium
// FALSE POSITIVES: Help desk scripts and software updaters that close Chrome before patching.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: taskkill.exe whose command line names chrome.exe, started by cmd or powershell. The creator is InitiatingProcessFileName. contains is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude known patching and help-desk creators. Keep any event within minutes of a Q2, Q3 or Q7 hit on the same host.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: taskkill started by a creator other than cmd or powershell is not captured.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where FileName =~ "taskkill.exe"
| where ProcessCommandLine contains "chrome.exe"
| where InitiatingProcessFileName in~ ("cmd.exe", "powershell.exe")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: quartzline_new.exe and replaceInPlace.ps1 (the in-place swap with retries), chrome-history-summarizer, the self-deleting carrier, and the Caira deployApp.ps1 under the deployment folder. FP: an internal script that is also called replaceInPlace.ps1. Keep only hits that also name quartzline_new.exe or sit on a host with a Q1 to Q3 hit.
Known limitations and deployment notes
- PowerQuery: A script started by a process the agent did not observe starting is not captured.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: A script started by a process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: The command line is matched with a case-insensitive regular expression.
// HUNT: Installer, self-update and history-tool staging by command line // MITRE: T1105, T1059.001, T1070.004, T1217 // CONF: high FP: medium COST: low // REQUIRES: Windows process creation telemetry with command line // FALSE POSITIVES: An internal deployment script that is also called replaceInPlace.ps1. // TUNING: For replaceInPlace.ps1 keep only hits whose command line also names quartzline_new.exe, or whose host shows a Q1 to Q3 hit. Exclude your own software-distribution parents. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | CommandLine=/(quartzline_new\.exe|replaceInPlace\.ps1|chrome-history-summarizer|quartzline_takeover_carrier|\\Caira\\deployment-[0-9a-f-]+\\deployApp\.ps1)/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine]) | sort(@timestamp, order=desc, limit=200)
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating processtgt.process.name: Created process name
Readiness test
event.type = 'Process Creation' tgt.process.cmdline = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.process.cmdline
// HUNT: Installer, self-update and history-tool staging by command line // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1105, T1059.001, T1070.004, T1217 // CONF: high | FP: medium // FALSE POSITIVES: An internal deployment script that is also called replaceInPlace.ps1. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose command line names one of the installer, self-update or history-tool staging artefacts. On a Process Creation event the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the command line // TUNING: For replaceInPlace.ps1 keep only hits whose command line also names quartzline_new.exe, or whose host shows a Q1 to Q3 hit. Exclude your own software-distribution creators. // LOOKBACK: 30d; set the console time range or the query window 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 started by a process the agent did not observe starting is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.cmdline matches '(quartzline_new\\.exe|replaceInPlace\\.ps1|chrome-history-summarizer|quartzline_takeover_carrier|\\\\Caira\\\\deployment-[0-9a-f-]+\\\\deployApp\\.ps1)' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline, agent.uuid | limit 200
Automated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: Installer, self-update and history-tool staging by command line // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1105, T1059.001, T1070.004, T1217 // CONF: high | FP: medium // FALSE POSITIVES: An internal deployment script that is also called replaceInPlace.ps1. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose command line names one of the installer, self-update or history-tool staging artefacts. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: For replaceInPlace.ps1 keep only hits whose command line also names quartzline_new.exe, or whose host shows a Q1 to Q3 hit. Exclude your own software-distribution creators. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A script started by a process the sensor did not observe starting is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where ProcessCommandLine matches regex @"(?i)(quartzline_new\.exe|replaceInPlace\.ps1|chrome-history-summarizer|quartzline_takeover_carrier|\\Caira\\deployment-[0-9a-f-]+\\deployApp\.ps1)" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: file writes into the per-user install folders, versioned installers such as QuartzLine_1.<n>.exe, and the short-lived staging names. Catches carriers that delete themselves within a second. FP: a sanctioned product using Quartz, Canvex or PaperLine as a folder name. Exclude after hash and signer confirmation.
Known limitations and deployment notes
- PowerQuery: The install-folder branch matches non-executable files too, because File Creation has no executable filter.
- PowerQuery: A file modified in place after it was written is not matched by File Creation.
- PowerQuery assumes: tgt.file.path holds the full path of the written file.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: The install-folder branch matches non-executable files too, because DeviceFileEvents has no executable filter.
- KQL – Defender XDR: A file modified in place after it was created is not matched by FileCreated.
- KQL – Defender XDR assumes: FolderPath holds the full path of the written file, including the file name.
// HUNT: Executables written to the install folders, installer names and staging names // MITRE: T1105, T1036.005 // CONF: high FP: medium COST: low // REQUIRES: Windows file-write telemetry for executables // FALSE POSITIVES: A sanctioned product using a folder named Quartz, Canvex or PaperLine. // TUNING: Exclude a folder name only after confirming the product by SHA256HashData and signer. The installer-name and staging-name branches have no known benign users. // LOOKBACK: 30d #event_simpleName=/^(PeFileWritten|NewExecutableWritten)$/ | TargetFileName=/(\\AppData\\Local\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\|\\(QuartzLine|IronBark|Caira)_[0-9]+(\.[0-9]+)+\.exe$|\\(chrome-history-summarizer[^\\]*|quartzline_takeover_carrier|quartzline_new|hosthealth|updater-helper)\.exe$)/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, TargetFileName, SHA256HashData]) | sort(@timestamp, order=desc, limit=200)
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.name: Writing process
Optional fields
tgt.file.sha256: Hash. Population varies by tenant; verify with the readiness test.
Readiness test
event.type = 'File Creation' tgt.file.path = * | limit 5 | columns event.type, event.time, endpoint.name, tgt.file.path
// HUNT: Executables written to the install folders, installer names and staging names // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1105, T1036.005 // CONF: high | FP: medium // FALSE POSITIVES: A sanctioned product using a folder named Quartz, Canvex or PaperLine. // EQUIVALENCE: approximate-analytic - Same intent: a file written into an install folder, a versioned installer name, or a staging name. The CQL reads executable-written events only; SentinelOne File Creation cannot filter to executables, so any file written to those paths matches. // REQUIRES: SentinelOne File Creation telemetry with the target path // TUNING: Exclude a folder name only after confirming the product by hash and signer. The installer-name and staging-name branches have no known benign users. // LOOKBACK: 30d; set the console time range or the query window 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: The install-folder branch matches non-executable files too, because File Creation has no executable filter. A file modified in place after it was written is not matched by File Creation. // VALIDATION LEVEL: static-reviewed event.type = 'File Creation' tgt.file.path matches '(\\\\AppData\\\\Local\\\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\\\|\\\\(QuartzLine|IronBark|Caira)_[0-9]+(\\.[0-9]+)+\\.exe$|\\\\(chrome-history-summarizer[^\\\\]*|quartzline_takeover_carrier|quartzline_new|hosthealth|updater-helper)\\.exe$)' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.file.path, tgt.file.sha256, agent.uuid | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceFileEvents
Required fields
Timestamp: Event timeActionType: Action typeFolderPath: Written file path
Recommended fields
InitiatingProcessFileName: Writing process
Optional fields
SHA256: Hash. SHA256 is often unpopulated; SHA1 is the safer pivot where present.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceFileEvents | where Timestamp > ago(1d) | where ActionType == "FileCreated" | project Timestamp, ActionType, FolderPath | take 5
// HUNT: Executables written to the install folders, installer names and staging names // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1105, T1036.005 // CONF: high | FP: medium // FALSE POSITIVES: A sanctioned product using a folder named Quartz, Canvex or PaperLine. // EQUIVALENCE: approximate-analytic - Same intent: a file created in an install folder, with a versioned installer name, or with a staging name. The CQL reads executable-written events only; DeviceFileEvents cannot filter to executables, so any file created at those paths matches. // REQUIRES: Defender for Endpoint file-event telemetry (DeviceFileEvents) // TUNING: Exclude a folder name only after confirming the product by hash and signer. The installer-name and staging-name branches have no known benign users. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: The install-folder branch matches non-executable files too, because DeviceFileEvents has no executable filter. A file modified in place after it was created is not matched by FileCreated. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceFileEvents | where Timestamp >= ago(30d) | where ActionType == "FileCreated" | where FolderPath matches regex @"(?i)(\\AppData\\Local\\(QuartzLine|Quartz|Caira|IronBark|HostHealthCache|DevicePerfCache|PaperLine|Canvex)\\|\\(QuartzLine|IronBark|Caira)_[0-9]+(\.[0-9]+)+\.exe$|\\(chrome-history-summarizer[^\\]*|quartzline_takeover_carrier|quartzline_new|hosthealth|updater-helper)\.exe$)" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, FileName, FolderPath, SHA256 | sort by Timestamp desc | take 200
Looks for: which remote addresses the implant processes reached. Use for scoping only: the C2 domains sit behind Cloudflare, so the addresses are shared and must not be blocked.
Known limitations and deployment notes
- PowerQuery: Connections made through a process the agent attributes to a different name are not counted.
- PowerQuery assumes: IP Connect events carry no direction filter here, so inbound-accepted connections from these process names, if any, are counted too.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- KQL – Defender XDR: Connection attempts that never completed are recorded under other action types and are not separated here.
- KQL – Defender XDR assumes: in~ is case-insensitive, which reproduces the CQL /i intent.
// HUNT: Outbound connections from implant processes (scope the C2 reach) // MITRE: T1071.001, T1041 // CONF: medium FP: low COST: low // REQUIRES: Windows network connection telemetry with initiating process // FALSE POSITIVES: None expected for these process names. C2 sits behind a shared CDN, so the addresses are context only. Do not block them. // LOOKBACK: 30d #event_simpleName=NetworkConnectIP4 | ContextBaseFileName=/^(quartzline|paperline|fielddesk|pagestone|leafdesk|caira|ironbark)\.exe$/i | groupBy([ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort], function=count(as=Connections), limit=1000) | sort(Connections, order=desc, limit=200)
6 required fields · View requirements
Required telemetry
- IP Connect
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Acting processdst.ip.address: Remote addressdst.port.number: Remote port
Readiness test
event.type = 'IP Connect' src.process.name = * dst.ip.address = * | limit 5 | columns event.type, event.time, endpoint.name, src.process.name, dst.ip.address, dst.port.number
// HUNT: Outbound connections from implant processes (scope the C2 reach) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1071.001, T1041 // CONF: medium | FP: low // FALSE POSITIVES: None expected for these process names. C2 sits behind a shared CDN, so the addresses are context only. Do not block them. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: an outbound connection from an implant-named process, counted per host, process, remote address and port. The acting process on an IP Connect event is src.process.*. // REQUIRES: SentinelOne IP Connect telemetry with the acting process // TUNING: C2 sits behind a shared CDN, so the addresses are context only. Do not block them. // LOOKBACK: 30d; set the console time range or the query window 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: Connections made through a process the agent attributes to a different name are not counted. // VALIDATION LEVEL: static-reviewed event.type = 'IP Connect' src.process.name matches '^(quartzline|paperline|fielddesk|pagestone|leafdesk|caira|ironbark)\\.exe$' | group connections = count(), first_seen = min(event.time), last_seen = max(event.time) by endpoint.name, src.process.name, dst.ip.address, dst.port.number | sort -connections | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Initiating processRemoteIP: Remote addressRemotePort: Remote port
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | project Timestamp, InitiatingProcessFileName, RemoteIP, RemotePort | take 5
// HUNT: Outbound connections from implant processes (scope the C2 reach)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1071.001, T1041
// CONF: medium | FP: low
// FALSE POSITIVES: None expected for these process names. C2 sits behind a shared CDN, so the addresses are context only. Do not block them.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: an outbound connection from an implant-named process, counted per host, process, remote address and port. The acting process is InitiatingProcessFileName.
// REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents)
// TUNING: C2 sits behind a shared CDN, so the addresses are context only. Do not block them.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Connection attempts that never completed are recorded under other action types and are not separated here.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0
DeviceNetworkEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("quartzline.exe", "paperline.exe", "fielddesk.exe", "pagestone.exe", "leafdesk.exe", "caira.exe", "ironbark.exe")
| summarize Connections = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort
| sort by Connections desc
| take 200Looks for: the history uploader pattern backup <pre-signed link>, which still fires if the tool is renamed.
Known limitations and deployment notes
- PowerQuery: A run launched through a creator other than powershell.exe is not captured.
- PowerQuery assumes: Case-insensitive matching is the PowerQuery default for matches, which reproduces the CQL /i intent.
- PowerQuery assumes: On Process Creation, src.process.* is the creator and tgt.process.* is the new process.
- KQL – Defender XDR: A run launched through a creator other than powershell.exe is not captured.
- KQL – Defender XDR assumes: endswith is case-insensitive, which reproduces the CQL /i intent.
// HUNT: Executable run by PowerShell with a backup argument and a pre-signed link // MITRE: T1567.002, T1560.001 // CONF: medium FP: low COST: low // REQUIRES: Windows process creation telemetry with command line and parent name // FALSE POSITIVES: Rare. A backup utility run from PowerShell with a URL argument would match. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^powershell\.exe$/i | FileName=/\.exe$/i | CommandLine=/\sbackup\s+https?:/i | table([@timestamp, ComputerName, UserName, FileName, ImageFileName, CommandLine, SHA256HashData]) | sort(@timestamp, order=desc, limit=200)
6 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timeendpoint.name: Host namesrc.process.name: Creating processtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.user: User
Optional fields
tgt.process.image.sha256: Hash. Population varies by tenant; verify with the readiness test.
Readiness test
event.type = 'Process Creation' 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: Executable run by PowerShell with a backup argument and a pre-signed link // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1567.002, T1560.001 // CONF: medium | FP: low // FALSE POSITIVES: Rare. A backup utility run from PowerShell with a URL argument would match. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: an executable created by powershell whose command line carries a backup argument followed by an http or https link. The creator is src.process.* and the created process is tgt.process.*. // REQUIRES: SentinelOne Process Creation telemetry with the command line and creating process // TUNING: Rare. Confirm whether a sanctioned backup utility is run from PowerShell with a URL argument before alerting. // LOOKBACK: 30d; set the console time range or the query window 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 run launched through a creator other than powershell.exe is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' src.process.name matches '^powershell\\.exe$' tgt.process.name matches '\\.exe$' tgt.process.cmdline matches '\\sbackup\\s+https?:' | columns event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.image.path, tgt.process.cmdline, tgt.process.image.sha256, agent.uuid | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command lineInitiatingProcessFileName: Initiating process
Optional fields
SHA1: Hash. SHA256 is often unpopulated in this table; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine, InitiatingProcessFileName | take 5
// HUNT: Executable run by PowerShell with a backup argument and a pre-signed link // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1567.002, T1560.001 // CONF: medium | FP: low // FALSE POSITIVES: Rare. A backup utility run from PowerShell with a URL argument would match. // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: an executable created by powershell whose command line carries a backup argument followed by an http or https link. The creator is InitiatingProcessFileName. matches regex with the (?i) prefix reproduces the CQL /i flag. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: Rare. Confirm whether a sanctioned backup utility is run from PowerShell with a URL argument before alerting. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A run launched through a creator other than powershell.exe is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where InitiatingProcessFileName =~ "powershell.exe" | where FileName endswith ".exe" | where ProcessCommandLine matches regex @"(?i)\sbackup\s+https?:" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Detection Rules by Platform
CrowdStrike: Custom IOA
| IOA name | Rule type | Pattern | Exclusions | Promotes | Posture and deployment path |
|---|---|---|---|---|---|
| Per-user QuartzLine or Caira binary | Process Creation | Image path matches \AppData\Local\QuartzLine\quartzline.exe or \AppData\Local\Caira\caira.exe | None | Promote Q2, Q3 | Prevent after 7 days in Detect. Both names and paths are in three snapshots. The IronBark path is in Expel and MCNC only, so keep it detect. |
| Chrome history uploader | Process Creation | Image name matches chrome-history-summarizer*.exe | None | Promote Q10, Q13 | Prevent after 7 days in Detect. Named by Expel and Rogue Authority. |
| Implant-spawned shell chain | Process Creation | Parent image quartzline, paperline, fielddesk, pagestone, leafdesk, caira or ironbark; child cmd, powershell, schtasks, findstr, taskkill or whoami | None | Promote Q7 | Detect only. The children are legitimate Windows tools, so never set prevent on them. Block the parent through the hash and path rules instead. |
| Chrome relaunch with hidden restore bubble | Process Creation | Chrome command line contains --hide-crash-restore-bubble and --restore-last-session; parent is not explorer or chrome | Sanctioned browser management | Promote Q8 | Detect only. Chrome is a legitimate product. |
| Staging and self-update by PowerShell | Process Creation | Command line names quartzline_new.exe, replaceInPlace.ps1 or the Caira deployment script | Internal deployment tooling | Promote Q10 | Detect only. The host process is PowerShell. |
Hash matches (Q4) and the domains belong in Falcon IOC Management, not Custom IOAs. Use the CSV in Section 10.
Alert packages
Ready-to-paste text and triage steps for the three detections closest to persistence and active C2.
Q1 and Q3: QuartzLine family scheduled task or launch
Subject: [HIGH] Detection: QuartzLine family persistence (scheduled task launching implant)
A scheduled task named QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck or HostHealthCache* was created, or an implant started with --update-check or --check. The implant relaunches every hour, and blocking C2 or deleting the file does not stop it. Treat browser-stored passwords, cookies and tokens on this host as exposed.
Triage checklist
- Note ComputerName, UserName and the task executable path.
- Run Q2 and Q11 on the host to see which folders and binaries exist.
- Run Q7 on the host: did the implant spawn cmd, schtasks or taskkill?
- Run Q5 and Q12: which C2 domains did it resolve, and when did Chrome last relaunch (Q8)?
- Check for the follow-on stages: Caira (CairaServiceCheck), IronBark, chrome-history-summarizer (Q10, Q13).
- Isolate the host. Do not delete files first: remove the tasks, then processes, then folders (Playbook 1).
- Reset the user's credentials and revoke sessions (N9).
- Search the environment for the same task names and hashes (Q1, Q4).
Pivot queries
// >> FILL IN: ComputerName="REPLACE_WITH_HOSTNAME" // Host-scoped: everything the implant did on this host #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ComputerName="REPLACE_WITH_HOSTNAME" | ParentBaseFileName=/^(quartzline|caira|ironbark)\.exe$/i | table([@timestamp, UserName, ParentBaseFileName, FileName, CommandLine]) | sort(@timestamp, order=asc)
// Environment-wide: every host with the persistence task #event_simpleName=ScheduledTaskRegistered | TaskName=/(quartzlineupdatecheck|cairaservicecheck|ironbarkupdatecheck|hosthealthcache)/i | groupBy([ComputerName, TaskName], function=count(as=Hits), limit=1000)
Q7: Viewer or implant spawning shells
Subject: [HIGH] Detection: QuartzLine hidden command shell (implant spawned cmd or PowerShell)
A process named like the QuartzLine family started a shell or admin tool. In the observed activity this is the server-ordered install: copy, task file, findstr check, schtasks register, taskkill on Chrome.
Triage checklist
- Read CommandLine for the child: schtasks create, findstr, taskkill chrome.exe or whoami /groups.
- Confirm the parent path is under AppData\Local (Q2).
- Check Q1 for the task it registered, and Q8 for the Chrome relaunch.
- Look for powershell children with quartzline_new.exe or deployApp.ps1 (Q10).
- Isolate and follow Playbook 1.
Q5: Campaign DNS lookup
Subject: [MEDIUM] Detection: QuartzLine infrastructure DNS lookup
A host resolved a C2, ad-redirect, search-hijack or post-install domain. If ContextBaseFileName is quartzline.exe, caira.exe or ironbark.exe the host is infected and checking in. If it is a browser, the user reached the ad chain or a hijacked search page.
Triage checklist
- Read ContextBaseFileName and DomainName.
- Implant process: treat as infected, run Q1, Q3, Q7 and isolate.
- Browser: check Q6 and Q11 for a download from a campaign bucket and for a written installer.
- If DNS filtering blocked it, find the device behind the source address. The block is not a cleanup.
SentinelOne: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| Per-user QuartzLine or Caira binary | Q2, Q3, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Chrome history uploader | Q10, Q13, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Implant-spawned shell chain | Q7, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Chrome relaunch with hidden restore bubble | Q8, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Staging and self-update by PowerShell | Q10, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
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.
Microsoft Defender: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| Per-user QuartzLine or Caira binary | Q2, Q3, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Chrome history uploader | Q10, Q13, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Implant-spawned shell chain | Q7, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Chrome relaunch with hidden restore bubble | Q8, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Staging and self-update by PowerShell | Q10, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
Q1, Q4, Q5, Q6, Q9, Q11 and Q12 stay a hunt in this pack, not a rule. A rule can generate only 150 alerts per run. Continuous (NRT) frequency needs a single table and no comment lines, so delete the generated comment header from the query first.
Machine-Readable IOC Appendix
Import the CSV as written. Bucket rows are exact hosts only: ReliaQuest warns against broadly blocking AWS S3 or other shared infrastructure. Do not block Cloudflare addresses.
type,value,action,severity,expiration,description,tags sha256,7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3,prevent,critical,2027-04-27,QuartzLine installer original build (paperline.exe),campaign:QuartzLine sha256,25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653,prevent,critical,2027-04-27,quartzline.exe / fielddesk.exe newer build pushed as update,campaign:QuartzLine sha256,069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527,prevent,critical,2027-04-27,chrome-history-summarizer-v0.0.1.exe (Chrome history uploader),campaign:QuartzLine sha256,74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124,prevent,critical,2027-04-27,caira.exe second-stage RAT (also pagestone.exe),campaign:QuartzLine sha256,d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b,detect,medium,2027-04-27,quartzline_takeover_carrier.exe self-deleting carrier,campaign:QuartzLine sha256,4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811,detect,medium,2027-04-27,deployApp.ps1 Caira deployment script,campaign:QuartzLine sha256,3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d,detect,medium,2027-04-27,hosthealth.exe short-lived stager,campaign:QuartzLine sha256,0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77,detect,medium,2027-04-27,updater-helper.exe downloads IronBark,campaign:QuartzLine sha256,f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8,detect,medium,2027-04-27,IronBark standalone installer,campaign:QuartzLine sha256,835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca,detect,medium,2027-04-27,ironbark.exe third stage,campaign:QuartzLine sha256,8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86,detect,medium,2027-04-27,leafdesk.exe LeafDesk/Canvex build of the same kit,campaign:QuartzLine sha256,90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97,detect,low,2027-01-27,Unnamed dropper listed by one source only,campaign:QuartzLine domain,westbeavers.com,prevent,high,2027-04-27,QuartzLine C2 (Cloudflare fronted),campaign:QuartzLine domain,motherotters.com,prevent,high,2027-04-27,QuartzLine C2 (Cloudflare fronted),campaign:QuartzLine domain,healskills.com,prevent,high,2027-04-27,QuartzLine C2 (Cloudflare fronted),campaign:QuartzLine domain,topsmagnificentgrade.com,prevent,high,2027-04-27,Caira C2,campaign:QuartzLine domain,tabbyottercub.com,prevent,high,2027-04-27,Caira C2,campaign:QuartzLine domain,flawlessgradecheered.com,prevent,high,2027-04-27,Caira C2,campaign:QuartzLine domain,beatramiro.com,prevent,high,2027-04-27,Google Ads redirect domain,campaign:QuartzLine domain,softwareslizards.com,prevent,high,2027-04-27,Google Ads redirect domain,campaign:QuartzLine domain,thankyou.molehawks.com,prevent,high,2027-04-27,Page opened after Chrome relaunch,campaign:QuartzLine domain,duskhollow.s3.us-east-2.amazonaws.com,prevent,high,2027-04-27,Installer and update bucket (exact host only),campaign:QuartzLine domain,chrome-history-backup.s3.us-east-2.amazonaws.com,prevent,high,2027-04-27,History tool download and upload bucket (exact host only),campaign:QuartzLine domain,alberfine.s3.us-east-2.amazonaws.com,prevent,high,2027-04-27,Caira delivery bucket (exact host only),campaign:QuartzLine domain,foxsilk.com,detect,medium,2027-04-27,LeafDesk C2 (observed down 2026-10-24),campaign:QuartzLine domain,runnerfrogs.com,detect,medium,2027-04-27,LeafDesk C2,campaign:QuartzLine domain,fasterhedgehogs.com,detect,medium,2027-04-27,LeafDesk C2,campaign:QuartzLine domain,leolin15.s3.us-east-2.amazonaws.com,detect,medium,2027-04-27,hosthealth.exe delivery bucket (exact host only),campaign:QuartzLine domain,tidefern.s3.us-east-2.amazonaws.com,detect,medium,2027-04-27,IronBark installer bucket (exact host only),campaign:QuartzLine domain,purplepandagroup.com,detect,medium,2027-04-27,Ad redirect before IronBark installer,campaign:QuartzLine domain,royalproductive.com,detect,medium,2027-04-27,Ad redirect before IronBark installer,campaign:QuartzLine domain,biggerworldclassstandard.com,detect,medium,2027-04-27,IronBark payload delivery,campaign:QuartzLine domain,guessgooseberries.com,detect,medium,2027-04-27,IronBark install reporting,campaign:QuartzLine domain,commonhedgehogs.com,detect,medium,2027-04-27,IronBark C2,campaign:QuartzLine domain,thankyou.charlottedetector.com,detect,medium,2027-04-27,Page IronBark opens after install,campaign:QuartzLine domain,pinkexploratorysearch.com,detect,medium,2027-04-27,Chrome default search and new-tab hijack,campaign:QuartzLine domain,smallerbestsearch.com,detect,medium,2027-04-27,Chrome default search and new-tab hijack,campaign:QuartzLine domain,searchedvictoryresults.com,detect,medium,2027-04-27,Chrome default search and new-tab hijack,campaign:QuartzLine # Cloudflare edge addresses published by one source are NOT imported: shared infrastructure, never block by address. # Prevent rows are named by two or more independent snapshots. Bucket rows are exact hosts only: never block amazonaws.com.
indicatorType,indicatorValue,action,title,description,expirationTime,severity,recommendedActions,rbacGroups,category,mitretechniques,GenerateAlert FileSha256,7f1db334fd3302cf98dd4afddf6f90e98e2a496fe7e86bf1832b89d02f3d73c3,Block,QuartzLine installer original build,QuartzLine installer original build (paperline.exe),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,25ea334b75beede8dcab4c4460313c3013c35e55c16cd066231d80ecfe4c0653,Block,quartzline.exe / fielddesk.exe newer build pushed as update,quartzline.exe / fielddesk.exe newer build pushed as update,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,069fd1e710b341fbe92337116779e6b50a40408f55f6547252cd2c05fe9c0527,Block,chrome-history-summarizer-v0.0.1.exe,chrome-history-summarizer-v0.0.1.exe (Chrome history uploader),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,74aaa6b54133bbb2e77b2ae874e9900a907c269058f798a0a1197288ba1f7124,Block,caira.exe second-stage RAT,caira.exe second-stage RAT (also pagestone.exe),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,d287a970294d54db5ab3ac5f7e9525c303b9aceac7117b165385c5655717333b,Audit,quartzline_takeover_carrier.exe self-deleting carrier,quartzline_takeover_carrier.exe self-deleting carrier,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,4c073764737e96fecf9d3e28384b2db628446c512c2df3696689d0c5e045b811,Audit,deployApp.ps1 Caira deployment script,deployApp.ps1 Caira deployment script,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,3c813ea19ff2e3e2cf566ec69753ba637bb243b4b4e8416dc8ebf68e93016a1d,Audit,hosthealth.exe short-lived stager,hosthealth.exe short-lived stager,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,0fa4082c6fda0c2885eade0e4f63a2abfeaa26581f903e6784682f5fbd9d0d77,Audit,updater-helper.exe downloads IronBark,updater-helper.exe downloads IronBark,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,f4e255dfdf3d23774b0067797cac0f986f1690abbeec217eb60029dcaa7425f8,Audit,IronBark standalone installer,IronBark standalone installer,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,835800058050be37366478c662f73d7fcb93a2669e44f98664546fbc8ee6c7ca,Audit,ironbark.exe third stage,ironbark.exe third stage,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,8644bb2ba39ddad352e82cc8fc827986940dec126527ed1cb6fa532e002bea86,Audit,leafdesk.exe LeafDesk/Canvex build of the same kit,leafdesk.exe LeafDesk/Canvex build of the same kit,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,90ddbf4be95b271de76384f4939eb6f165aa9461f8383a6e6f000f9256b34f97,Audit,Unnamed dropper listed by one source only,Unnamed dropper listed by one source only,2027-01-27T00:00:00.0Z,Low,Investigate the device and pivot into the pack's queries,,,,True DomainName,westbeavers.com,Block,QuartzLine C2,QuartzLine C2 (Cloudflare fronted),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,motherotters.com,Block,QuartzLine C2,QuartzLine C2 (Cloudflare fronted),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,healskills.com,Block,QuartzLine C2,QuartzLine C2 (Cloudflare fronted),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,topsmagnificentgrade.com,Block,Caira C2,Caira C2,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,tabbyottercub.com,Block,Caira C2,Caira C2,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,flawlessgradecheered.com,Block,Caira C2,Caira C2,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,beatramiro.com,Block,Google Ads redirect domain,Google Ads redirect domain,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,softwareslizards.com,Block,Google Ads redirect domain,Google Ads redirect domain,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,thankyou.molehawks.com,Block,Page opened after Chrome relaunch,Page opened after Chrome relaunch,2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,duskhollow.s3.us-east-2.amazonaws.com,Block,Installer and update bucket,Installer and update bucket (exact host only),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,chrome-history-backup.s3.us-east-2.amazonaws.com,Block,History tool download and upload bucket,History tool download and upload bucket (exact host only),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,alberfine.s3.us-east-2.amazonaws.com,Block,Caira delivery bucket,Caira delivery bucket (exact host only),2027-04-27T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,foxsilk.com,Audit,LeafDesk C2,LeafDesk C2 (observed down 2026-10-24),2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,runnerfrogs.com,Audit,LeafDesk C2,LeafDesk C2,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,fasterhedgehogs.com,Audit,LeafDesk C2,LeafDesk C2,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,leolin15.s3.us-east-2.amazonaws.com,Audit,hosthealth.exe delivery bucket,hosthealth.exe delivery bucket (exact host only),2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,tidefern.s3.us-east-2.amazonaws.com,Audit,IronBark installer bucket,IronBark installer bucket (exact host only),2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,purplepandagroup.com,Audit,Ad redirect before IronBark installer,Ad redirect before IronBark installer,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,royalproductive.com,Audit,Ad redirect before IronBark installer,Ad redirect before IronBark installer,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,biggerworldclassstandard.com,Audit,IronBark payload delivery,IronBark payload delivery,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,guessgooseberries.com,Audit,IronBark install reporting,IronBark install reporting,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,commonhedgehogs.com,Audit,IronBark C2,IronBark C2,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,thankyou.charlottedetector.com,Audit,Page IronBark opens after install,Page IronBark opens after install,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,pinkexploratorysearch.com,Audit,Chrome default search and new-tab hijack,Chrome default search and new-tab hijack,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,smallerbestsearch.com,Audit,Chrome default search and new-tab hijack,Chrome default search and new-tab hijack,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,searchedvictoryresults.com,Audit,Chrome default search and new-tab hijack,Chrome default search and new-tab hijack,2027-04-27T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True
Column names and allowed values are from Microsoft's documented parameter table. Prevent rows import as Block, without remediation; network indicators cannot use BlockAndRemediate. Check each expirationTime before importing: an indicator whose date has passed is already expired. Download the sample CSV from the Import page to confirm the column order before a bulk import. Each file takes at most 500 indicators. Learn describes the import per entity type, so if a mixed file is rejected, split it by indicatorType. An imported indicator does nothing unless the matching Advanced features are on (for example Custom network indicators and Allow or block file).
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.
PROCESS CHAINS
quartzline.exe / paperline.exe / fielddesk.exe / pagestone.exe / leafdesk.exe / caira.exe / ironbark.exe
-> cmd.exe /C ... (hidden) schtasks.exe findstr.exe taskkill.exe /F chrome.exe whoami.exe /groups
chrome.exe --hide-crash-restore-bubble --restore-last-session --profile-directory=Default
(parent is the implant, not explorer.exe)
powershell.exe ... quartzline_new.exe (in-place swap, up to ten retries, rollback)
powershell.exe -> chrome-history-summarizer-v0.0.1.exe backup <pre-signed link> (then deleted)
powershell.exe ... deployApp.ps1 -> whoami /groups -> %LOCALAPPDATA%\Caira\caira.exe
SCHEDULED TASK COMMANDS (may carry --uid=<id>)
QuartzlineUpdateCheck %LOCALAPPDATA%\QuartzLine\quartzline.exe --update-check
CairaServiceCheck %LOCALAPPDATA%\Caira\caira.exe --check
IronbarkUpdateCheck %LOCALAPPDATA%\IronBark\ironbark.exe --update-check
HostHealthCacheCheck-<32 hex>, HostHealthCacheCleanup-<32 hex> (stager tasks, delete themselves within about an hour)
NETWORK
POST /quarry/vein, /quarry/deposit (encrypted inner layer; no User-Agent header)
POST /quarry/sinter application/json (plain status report; keys caldera, plateau, marker, vortex, striation, esker)
/quarry/geode, /quarry/talc (seen by Expel)
/quarry/stratum, /quarry/gravel, /quarry/bedrock, /quarry/sandstone, /quarry/seam (in config, not seen)
Caira: /piglet/flange, /piglet/trestle, /piglet/corbet
LeafDesk: /timber/bracket, /timber/fiber
DECRYPTED CHECK-IN VALUES (Rogue Authority)
implant version 6.1.3, build QNPVXZGJYUSLTREHK, tag QZRT07; LeafDesk build KRMFDXZLQBHGJWPTVNFOLDERS (every profile under C:\Users) %LOCALAPPDATA%\QuartzLine \Quartz \Caira (deployment-<guid>) \IronBark \PaperLine %LOCALAPPDATA%\HostHealthCache \DevicePerfCache \Canvex FILES terrain.dat last line zenith=<id> (QuartzLine) topology.dat pinnacle=<id> (LeafDesk / Canvex) quartzline.exe, caira.exe, ironbark.exe, paperline.exe, fielddesk.exe, pagestone.exe, leafdesk.exe hosthealth.exe, updater-helper.exe, payload.exe, previous.exe, quartzline_new.exe quartzline_takeover_carrier.exe, chrome-history-summarizer-v0.0.1.exe deployApp.ps1, replaceInPlace.ps1, plan.b64, complete.json Installers: QuartzLine_1.<n>.exe, IronBark_1.<n>.exe, Caira_*.exe (Downloads folder) MUTEXES Local\pustBacktraceMutex00000000 (Caira) Local\austBacktraceMutex00000000 (LeafDesk) TASKS QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck, HostHealthCacheCheck-*, HostHealthCacheCleanup-*
# Signing and audit block. Falcon cannot query signer or serial, so use these on the endpoint.
# 1) Signer and serial of every binary in the per-user folders
$dirs = 'QuartzLine','Quartz','Caira','IronBark','PaperLine','Canvex','HostHealthCache','DevicePerfCache'
Get-ChildItem 'C:\Users' -Directory | ForEach-Object {
foreach ($d in $dirs) {
$p = Join-Path $_.FullName ('AppData\Local\' + $d)
if (Test-Path $p) { Get-ChildItem $p -Recurse -Filter *.exe -ErrorAction SilentlyContinue |
Get-AuthenticodeSignature | Select-Object Path, Status, @{n='Signer';e={$_.SignerCertificate.Subject}}, @{n='Serial';e={$_.SignerCertificate.SerialNumber}} }
}
}
# Indicators to compare (Rogue Authority, MCNC):
# Signer: Guangzhou Guoying Communication Technology Co., Ltd.
# Issuer: Sectigo Public Code Signing CA EV R36
# Serial: 1b56cb4e99fb9444645a1ce7ffc0a46b (revoked 2026-10-09, Privilege Withdrawn)
# SHA-256 thumbprint: EA277BE59F1F1854B1BEDBA0439A011FCFB0A23D90DBB8A99F5AE87512A17470
# LeafDesk: ZEPHYR LAWN CARE, LLC, Microsoft ID Verified CS EOC CA 03,
# serial 3300030c217d23bc4078cae8f3000000030c21 (three-day certificate)
# IronBark installer: certificate issued to Amir Dow (revoked)
# A valid signature is not proof of safety. Flag any signer whose name does not match the product.# HUNT ONLY, not imported # Sources disagree or are single-source. Review before acting. Cloudflare edge addresses for the QuartzLine C2 domains Published by MCNC only. Shared CDN space: never block by address. pdfmaestro (domain and CDN host) Listed by MCNC as a campaign name and block entry. No other snapshot explains it. Hunt DNS for it; do not import until a second source confirms. SHA-256 90ddbf... (see Section 4) MCNC lists it as an initial dropper with no name. Imported as detect, low confidence. Role conflicts MCNC calls 25ea..., 3c81... and 0fa4... "initial dropper". Expel and Rogue Authority give the roles used in this pack (update build, hosthealth.exe, updater-helper.exe).
Detection Validation Gates
| Gate | Check | Pass condition |
|---|---|---|
| Telemetry ready | Confirm each source is searchable: process creation with command line, path and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); scheduled task creation (CrowdStrike: ScheduledTaskRegistered. SentinelOne: Task Register. Defender: DeviceEvents ScheduledTaskCreated); DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: use proxy or resolver logs); executable written (CrowdStrike: PeFileWritten. SentinelOne: File Creation. Defender: DeviceFileEvents); plus proxy and resolver logs from Section 5. | A sample event from each source is searchable in the last hour. |
| Benign baseline | Run Q2, Q8, Q9, Q10 and Q11 over 14 days before alerting. | Fewer than 10 hits per week per query, each explained by a named product, script or admin. |
| Positive tests | Q1: on a lab host run schtasks /create /tn QuartzlineUpdateCheck /tr notepad.exe /sc once /st 23:59, then delete it. Q8: on a lab host launch chrome.exe with the two flags from a script. Q13: run a harmless executable from PowerShell with the argument backup https://example.invalid. Never use live malware or test on production hosts. | Each test fires its query within the ingest delay, and the lab task is removed afterward. |
| Promotion | Promote Q1, Q3, Q7 and Q5 first (high confidence, low FP), then Q4. Promote the two prevent IOAs after 7 days in Detect with no unexplained hits. | Detect for 14 days with no unexplained hits, then enable prevention where the platform supports it. |
Hardening: Tiered & Deployable
- Import the Section 10 CSV and block the prevent-set domains at DNS and proxy. Exact bucket hosts only, never S3 broadly. A DNS or proxy block stops new contact but does not clean the host. Framework: MITRE M1037, M1021; CIS Controls v8 9.2 and 9.3. Verify: Playbook 5 and Q5.
- Find and remove the persistence. Delete the tasks first, then end the processes, then delete the folders, because the tasks relaunch the implant. Reimage if cleanup cannot be confirmed. Framework: MITRE M1047; vendor guidance from Expel, ReliaQuest and MCNC. Verify: Playbook 1 and Q1.
- Reset credentials and revoke sessions for users of any infected device. Treat browser-stored passwords, cookies and tokens as exposed. Framework: MITRE M1032, M1026; NIST SP 800-63B. Verify: identity provider sign-in logs (N9).
- Turn on the logging this hunt needs. Command-line capture, Task Scheduler events, and the Task Scheduler operational log. Framework: MITRE M1047; CIS Controls v8 8.5. Verify: Playbook 4.
- Do not trust a signature alone. The viewer was EV-signed and a sibling build used a short-lived Microsoft Trusted Signing certificate. Educate help desk: a signer, file details and window title that name different companies is a red flag. Framework: MITRE M1017. Source: Rogue Authority.
- Lock Chrome settings by policy. Set the default search provider, new-tab page and download restrictions, and block extension installs outside an allowlist. A managed setting overrides a value written into the profile. Framework: MITRE M1054, M1021; CIS Google Chrome Benchmark; Chrome Enterprise policy documentation. Verify: Playbook 2 and chrome://policy.
- Add Attack Surface Reduction rule 01443614 in audit mode. It blocks executables that do not meet prevalence, age or trusted-list criteria, which a freshly published build may fail. Framework: MITRE M1038, M1049; Microsoft Defender ASR documentation. Verify: Playbook 3.
- Restrict execution from user-writable paths. QuartzLine installs into %LOCALAPPDATA%, so admin lockdown does not stop it. Use AppLocker or WDAC in audit mode first, then enforce, with publisher rules for approved per-user software. Framework: MITRE M1038; CIS Controls v8 2.5; NIST SP 800-53 CM-7, CM-11. Verify: Get-AppLockerPolicy -Effective.
- Alert on desktop software with no User-Agent. Add a proxy rule or detection for POSTs with an empty User-Agent from non-browser processes. Framework: MITRE M1031; best-practice, no formal benchmark. Verify: N1.
- Software request path. Users should get PDF and productivity tools from an approved catalog. Remove standing user rights to install. Framework: MITRE M1017, M1038; CIS Controls v8 2.3; MCNC advice to use local IT for approved software.
- Trust by publisher, not by valid signature. WDAC publisher or managed-installer rules so a freshly issued EV certificate does not by itself grant execution. Framework: MITRE M1045; Microsoft WDAC documentation.
- Shrink the value of stolen sessions. Shorter session lifetimes, phishing-resistant MFA and device-bound sessions where your identity provider supports them. Framework: MITRE M1032, M1027; NIST SP 800-63B. Best-practice, no formal benchmark for session binding.
- Cover unmanaged devices. Expel found a case where the only signal was a network block on a host with no EDR agent. Framework: CIS Controls v8 1.1, 1.2.
Deployable Playbooks
Each step carries its prerequisites, reboot requirement and rollback. Replace every REPLACE_WITH value before use, and test in non-production first.
Playbook 1 · Find and remove the persistence (T1053.005; M1047)
Step 1.1 · Discover tasks, folders and identity files (read-only)
What it does: Lists the QuartzLine-family tasks, per-user folders and terrain.dat or topology.dat identity lines on one host.
Prerequisites: Elevated PowerShell on the host.
Reboot required: No. These commands only read state.
Configuration
# READ-ONLY discovery. Run in an elevated PowerShell.
$taskNames = 'QuartzlineUpdateCheck','CairaServiceCheck','IronbarkUpdateCheck'
Get-ScheduledTask | Where-Object { $taskNames -contains $_.TaskName -or $_.TaskName -like 'HostHealthCache*' } |
Select-Object TaskName, TaskPath, State,
@{n='Execute';e={$_.Actions.Execute}}, @{n='Arguments';e={$_.Actions.Arguments}}
$dirs = 'QuartzLine','Quartz','Caira','IronBark','PaperLine','Canvex','HostHealthCache','DevicePerfCache'
Get-ChildItem 'C:\Users' -Directory | ForEach-Object {
foreach ($d in $dirs) {
$p = Join-Path $_.FullName ('AppData\Local\' + $d)
if (Test-Path $p) { $p }
}
foreach ($f in 'QuartzLine\terrain.dat','Canvex\topology.dat') {
$p = Join-Path $_.FullName ('AppData\Local\' + $f)
if (Test-Path $p) { Select-String -Path $p -Pattern '^(zenith|pinnacle)=' }
}
}Verify
# Expected on a clean host: no output. Any task or folder listed is a finding; keep the output as evidence.
Rollback
none required: read-only checks.
Step 1.2 · Remove tasks, then processes, then folders
What it does: Exports each task as evidence, removes the tasks first so nothing relaunches, ends the processes, then deletes the folders. Dry run by default.
Prerequisites: Elevated PowerShell; the host is isolated; discovery output reviewed; C:\IR is writable.
Reboot required: No.
Configuration
# Removal in the order MCNC specifies: tasks, then processes, then folders.
# Defaults to a dry run. Set $Apply = $true only after reviewing the discovery output.
$Apply = $false
$ev = 'C:\IR\quartzline'
New-Item -ItemType Directory -Force $ev | Out-Null
$taskNames = 'QuartzlineUpdateCheck','CairaServiceCheck','IronbarkUpdateCheck'
# 1) Tasks: export the XML as evidence, then remove
Get-ScheduledTask | Where-Object { $taskNames -contains $_.TaskName -or $_.TaskName -like 'HostHealthCache*' } | ForEach-Object {
Export-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath | Out-File (Join-Path $ev ($_.TaskName + '.xml'))
if ($Apply) { Unregister-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath -Confirm:$false }
else { "DRY RUN: would remove task $($_.TaskName)" }
}
# 2) Processes
$procs = 'quartzline','caira','ironbark','hosthealth','updater-helper','payload','paperline','fielddesk','pagestone'
Get-Process -Name $procs -ErrorAction SilentlyContinue | ForEach-Object {
if ($Apply) { Stop-Process -Id $_.Id -Force } else { "DRY RUN: would stop $($_.Name) ($($_.Id))" }
}
# 3) Folders (all profiles)
$dirs = 'QuartzLine','Quartz','Caira','IronBark','PaperLine','Canvex','HostHealthCache','DevicePerfCache'
Get-ChildItem 'C:\Users' -Directory | ForEach-Object {
foreach ($d in $dirs) {
$p = Join-Path $_.FullName ('AppData\Local\' + $d)
if (Test-Path $p) { Remove-Item $p -Recurse -Force -WhatIf:(-not $Apply) }
}
}Verify
# Re-run step 1.1. Expected: no output. Then run Q1 and Q3 for 24 hours: no new hits from this host.
Rollback
# Deleting malware needs no undo. The task XML exported to C:\IR\quartzline is the evidence copy. Do not re-register it on a production host. # If the dry run listed something legitimate, leave $Apply = $false and exclude it from the list.
Playbook 2 · Lock Chrome settings (T1176, T1539; M1054, M1021)
Step 2.1 · Managed search, new-tab, download and extension policy
What it does: Makes the default search engine and new-tab page read-only to the user and the profile, restricts dangerous downloads and extensions.
Prerequisites: Windows with Chrome; approved search name, search URL, new-tab URL and extension IDs decided; a pilot group first. The extension block applies to every extension not on the allowlist.
Reboot required: No. Restart Chrome for the policy to load.
Configuration
# Run as admin. Back up first, then set managed Chrome policy.
New-Item -ItemType Directory -Force 'C:\IR' | Out-Null
reg export 'HKLM\SOFTWARE\Policies\Google\Chrome' 'C:\IR\chrome-policy-before.reg' /y 2>$null
$k = 'HKLM:\SOFTWARE\Policies\Google\Chrome'
New-Item -Path $k -Force | Out-Null
Set-ItemProperty $k -Name 'DefaultSearchProviderEnabled' -Type DWord -Value 1
Set-ItemProperty $k -Name 'DefaultSearchProviderName' -Type String -Value 'REPLACE_WITH_APPROVED_SEARCH_NAME'
Set-ItemProperty $k -Name 'DefaultSearchProviderSearchURL' -Type String -Value 'REPLACE_WITH_APPROVED_SEARCH_URL' # must contain {searchTerms}
Set-ItemProperty $k -Name 'NewTabPageLocation' -Type String -Value 'REPLACE_WITH_APPROVED_NEW_TAB_URL'
Set-ItemProperty $k -Name 'DownloadRestrictions' -Type DWord -Value 1 # block dangerous downloads
Set-ItemProperty $k -Name 'SafeBrowsingProtectionLevel' -Type DWord -Value 2 # enhanced protection
# Extension control: block all, then allow only approved IDs (pilot first: this affects every user)
New-Item -Path "$k\ExtensionInstallBlocklist" -Force | Out-Null
Set-ItemProperty "$k\ExtensionInstallBlocklist" -Name '1' -Type String -Value '*'
New-Item -Path "$k\ExtensionInstallAllowlist" -Force | Out-Null
Set-ItemProperty "$k\ExtensionInstallAllowlist" -Name '1' -Type String -Value 'REPLACE_WITH_APPROVED_EXTENSION_ID'Verify
# Open chrome://policy and click Reload policies. Expected: each policy listed with status OK. Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Google\Chrome' | Select-Object DefaultSearchProviderEnabled, DownloadRestrictions, SafeBrowsingProtectionLevel
Rollback
Remove-Item 'HKLM:\SOFTWARE\Policies\Google\Chrome' -Recurse -Force # Or restore the exported backup: reg import C:\IR\chrome-policy-before.reg
Playbook 3 · Block unknown executables (T1204.002, T1036.005; M1038, M1049)
Step 3.1 · ASR prevalence rule in audit mode
What it does: Records which executables the rule would block over two weeks without stopping anything. Review before moving to Block.
Prerequisites: Microsoft Defender Antivirus in active mode with cloud-delivered protection; Windows 10 1709 or later or Windows Server 2016 or later.
Reboot required: No.
Configuration
# Audit mode only: logs what would be blocked, blocks nothing. # Rule: Block executable files from running unless they meet a prevalence, age, or trusted list criterion # Requires cloud-delivered protection. $id = '01443614-cd74-433a-b99e-2ecdc07bfc25' Add-MpPreference -AttackSurfaceReductionRules_Ids $id -AttackSurfaceReductionRules_Actions AuditMode
Verify
(Get-MpPreference).AttackSurfaceReductionRules_Ids (Get-MpPreference).AttackSurfaceReductionRules_Actions # Expected: the rule id with action 2 (audit). Review Defender event 1122 for would-block events.
Rollback
Remove-MpPreference -AttackSurfaceReductionRules_Ids '01443614-cd74-433a-b99e-2ecdc07bfc25'
Playbook 4 · Logging for the hunts (M1047)
Step 4.1 · Command line, task events and the Task Scheduler log
What it does: Enables process command-line capture, scheduled task audit events (4698, 4699, 4702) and the Task Scheduler operational log.
Prerequisites: Local admin or Group Policy rights. Command-line capture can record secrets passed as arguments; apply your log access controls.
Reboot required: No.
Configuration
# Logging that the hunts in this pack depend on. Run as admin. New-Item -ItemType Directory -Force 'C:\IR' | Out-Null auditpol /backup /file:C:\IR\auditpol-before.csv auditpol /set /subcategory:"Other Object Access Events" /success:enable /failure:enable auditpol /set /subcategory:"Process Creation" /success:enable reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v ProcessCreationIncludeCmdLine_Enabled /t REG_DWORD /d 1 /f wevtutil sl Microsoft-Windows-TaskScheduler/Operational /e:true
Verify
auditpol /get /subcategory:"Other Object Access Events" wevtutil gl Microsoft-Windows-TaskScheduler/Operational | findstr enabled
Rollback
auditpol /restore /file:C:\IR\auditpol-before.csv reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v ProcessCreationIncludeCmdLine_Enabled /f wevtutil sl Microsoft-Windows-TaskScheduler/Operational /e:false
Playbook 5 · Sinkhole the prevent-set domains (T1071.001, T1583.008; M1037)
Step 5.1 · Empty zones on the Windows DNS Server
What it does: Answers NXDOMAIN for the nine domains and three exact bucket hosts that two or more independent snapshots name. Detect-only domains are not listed.
Prerequisites: Windows DNS Server with the DnsServer PowerShell module; internal clients use it for resolution. If you use a DNS filter or proxy, apply the same list there instead.
Reboot required: No.
Configuration
# Windows DNS Server: answer NXDOMAIN for the prevent-set domains by hosting empty zones.
# Only domains named by two or more independent snapshots are listed. Exact hosts, no wildcard on amazonaws.com.
$blocked = @(
'westbeavers.com',
'motherotters.com',
'healskills.com',
'topsmagnificentgrade.com',
'tabbyottercub.com',
'flawlessgradecheered.com',
'beatramiro.com',
'softwareslizards.com',
'thankyou.molehawks.com',
'duskhollow.s3.us-east-2.amazonaws.com',
'chrome-history-backup.s3.us-east-2.amazonaws.com',
'alberfine.s3.us-east-2.amazonaws.com'
)
foreach ($d in $blocked) {
if (-not (Get-DnsServerZone -Name $d -ErrorAction SilentlyContinue)) {
Add-DnsServerPrimaryZone -Name $d -ZoneFile "$d.dns"
}
}Verify
Resolve-DnsName westbeavers.com -Server REPLACE_WITH_DNS_SERVER -ErrorAction SilentlyContinue # Expected: name does not exist. Then watch Q5 for blocked hosts and find the devices behind them.
Rollback
foreach ($d in $blocked) { Remove-DnsServerZone -Name $d -Force }
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate (host, user) | Network-contain every host with a Q1, Q2, Q3, Q4 or Q7 hit. Map blocked DNS or proxy hits to devices, starting with unmanaged hosts and anything without EDR. A blocked connection means the device is still infected and will retry. Release containment only after cleanup is verified. | IR lead; network team | Falcon containment status; DNS or proxy source-to-host mapping |
| Isolate: by platform | CrowdStrike: network-contain the host. SentinelOne: network quarantine (Disconnect from Network; confirm the label in your console version). Microsoft Defender: Isolate device (full network isolation). | IR lead; network team | Falcon containment status; DNS or proxy source-to-host mapping |
| Preserve | Export the task XML and the contents of the per-user folders (including terrain.dat and any deployment-<guid> folder) before deleting. Keep Chrome profile folders if reset might destroy evidence. | IR lead; forensics | Task XML; folder archive; hash list |
| Eradicate | Follow Playbook 1 in this order: remove tasks, end processes, delete folders and the original installers from Downloads. Check for renamed tasks that point at AppData\Local with --uid=, --check or --update-check, and note any new folder name. Remove unapproved Chrome and Edge extensions and reset Chrome settings. Reimage if cleanup cannot be confirmed. | IR lead; endpoint team | Re-run of step 1.1 with no output; Q1 to Q3 quiet for 24 hours |
| Credentials and sessions | Force a password reset for every user of the device. Revoke active sessions in the identity provider and cloud services. Treat anything saved in the browser as compromised, including cookies and tokens, because IronBark decrypted Chrome protected data in one case. | Identity team; help desk | Reset log; revoked-session report |
| Recover | Return the host to service after verified cleanup. Keep Q1, Q2, Q3, Q5 and Q7 under watch for 30 days. Push the Chrome policy (Playbook 2) and the execution controls before reconnecting the user. | IR lead; endpoint team | Monitoring dashboard; policy report |
| Hunt and report | Search the whole environment for the Section 10 indicators, including IronBark ones, which a hunt built only on QuartzLine hashes can miss. Brief stakeholders and report the malvertising to the ad platform where appropriate. | Threat hunt; communications | Hunt results; stakeholder brief |
Sequence reasoning: deleting the file does not remove the task, and killing processes before the tasks lets the task restart them. [#1] [#4]
Detection Coverage Map
| Technique | Behavior | CQL | IOA | CrowdStrike coverage | SentinelOne | Defender XDR |
|---|---|---|---|---|---|---|
| T1583.008, T1189 | Google ad, redirect chain, S3 download | Q5, Q6 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike | |
| T1204.002, T1036.005 | Per-user install, signed lure, known hashes | Q2, Q4, Q11 | Q2 | Good | Partial: Q11 approximate | Partial: Q4 telemetry gap, Q11 approximate |
| T1053.005 | QuartzlineUpdateCheck, CairaServiceCheck, IronbarkUpdateCheck | Q1, Q3 | Q2 | Good | Partial: Q1 approximate | Good, with assumptions |
| T1059.003, T1059.001, T1033 | Hidden cmd, schtasks, findstr, taskkill, whoami | Q7, Q9 | Q7 | Good | Good, with assumptions | Good, with assumptions |
| T1176, T1539 | Chrome kill, relaunch and search hijack | Q8, Q9 | Q8 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike |
| T1105, T1070.004 | Updates, deployment, carrier and tool deletion | Q10, Q11 | Q10 | Good | Partial: Q11 approximate | Partial: Q11 approximate |
| T1567.002, T1217 | Chrome history upload | Q13, Q6 | Q10 | Good | Good, with assumptions | Good, with assumptions |
| T1071.001 | C2 check-ins with no User-Agent | Q5, Q12 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike | |
| T1553.002 | EV certificate and Trusted Signing abuse | GAP | GAP | GAP | ||
| T1027 | Inner encoding layer on C2 traffic | GAP | GAP | GAP |
Gaps. Signer and serial checks (T1553.002) are outside endpoint telemetry and need native check N6. The User-Agent test and the encrypted C2 content need proxy logs (N1). The first ad click and unmanaged devices are also outside endpoint telemetry. Settings-style files such as terrain.dat are not executables, so executable-write telemetry cannot see them: use N5.
Validation. Run Section 11 before promoting: telemetry ready, 14-day baseline, safe positive tests, then staged promotion.
Hunt Summary Ticket
TITLE: QuartzLine (CLOUDHAZE): trojanized PDF viewer with the zenith backdoor, Google Ads malvertising
SEVERITY: High. Active campaign, 38 incidents at 32 customers by 2026-10-20 (Expel), persistence
survives file deletion and C2 blocking, follow-on RAT and stealer stages
SCOPE: Windows endpoints (process, file, DNS, scheduled task telemetry); web proxy and DNS filter;
Chrome settings; identity provider sessions for users of any infected device
HYPOTHESIS: A user clicks a Google ad on an unrelated site, downloads a working signed PDF viewer,
and the hidden zenith module registers an hourly scheduled task, relaunches Chrome, uploads
browsing history, and later installs the Caira RAT and IronBark.
QUERIES: 13 CQL queries (Q1-Q13) on Falcon sensor telemetry. Q1, Q3, Q7, Q5 first. Two prevent IOAs
promotable (Q2/Q3 binary path, Q10/Q13 history tool). 38 IOCs in IOC Management: 16 prevent, 22 detect.
DO FIRST: 1) Run Q1, Q3 and Q5 over 30 days. 2) Map every blocked DNS or proxy hit to a device.
3) Remove tasks, then processes, then folders (Playbook 1). 4) Reset credentials and revoke
sessions. 5) Import the Section 10 CSV (exact hosts only, no Cloudflare addresses).
FINDINGS: [fill in after the hunt]
GAPS: Signer and serial checks, the User-Agent test, encrypted C2 content, the first ad click and
unmanaged devices are outside endpoint telemetry. Settings-style files are not executables.
ACTIONS: Chrome policy lock, ASR prevalence rule, restrict execution from user-writable paths,
DNS and proxy blocks for the prevent set, approved-software path, command-line logging.
OWNER: REPLACE_WITH_OWNER
VERSION: v0.1 (Draft) 2026-10-27Changelog
References
| Tier | Source | Used for | Access date |
|---|---|---|---|
| T1 | Expel: QuartzLine: A working PDF viewer with a backdoor inside (2026-10-15, updated 2026-10-21) | Primary vendor casework: 38 incidents at 32 customers by 2026-10-20, Google Ads delivery, timeline, scheduled tasks, IronBark ad funnel and certificate, full IOC list. | 2026-10-27 |
| T1 | Rogue Authority: A signed PDF viewer that quietly takes orders: the QuartzLine zenith backdoor (2026-10-09, updated 2026-10-25) | Independent reverse engineering: zenith module, terrain.dat, /quarry/ protocol, no User-Agent, certificate revocation, LeafDesk/Canvex build, install order and IOC table. | 2026-10-27 |
| T1 | ReliaQuest Threat Research post on X (QuartzLine PDF viewer) | Independent confirmation of the redirect chain through two domains, the S3 installer, both scheduled tasks, two C2 domains, and the warning that quarantining the installer does not remediate. | 2026-10-27 |
| T2 | MCNC: QuartzLine Infostealer Campaign (PDF linked from the MCNC news page) | Regional operator view: education-sector focus, 6-step cleanup order, URL block list, extra hash and folder names. The HTML page returned HTTP 403, so the linked PDF was snapshotted. | 2026-10-27 |
| T2 | MCNC QuartzLine PDF (snapshot source) | The PDF that was actually fetched and saved as 04-mcnc.txt. | 2026-10-27 |