Operation FlashHole: Lazarus CrossWeb EX Abuse, TechHub and TouchShift
Executive Summary
Attacker objective. Operation FlashHole is a Lazarus cyberespionage campaign against South Korean organisations, with the earliest evidence dating to July 2025. Kaspersky GReAT confirmed at least three victims in software, construction and wired communication equipment manufacturing, and assesses that the software sector is targeted to steal source code. [#1] [#2]
How it gets in. Targets receive spear-phishing links to AI-assisted lure sites on GitHub Pages: a fake résumé page and later an interior design portfolio. Each site loads an external JavaScript file from an attacker-controlled host. Visiting the site most likely starts an infection involving the mandatory South Korean financial security product CrossWeb EX. Securelist could not establish the exact abuse method, and no CVE is assigned. [#1] [#2]
What runs. The legitimate fsquirt.exe is executed under the CrossWeb EX process and injected with shellcode holding the TechHub DLL. TechHub uses a private GitHub repository and a Personal Access Token as its C2 channel and pulls TouchHub, which installs a service that side-loads TouchShift as mscoree.dll. A second TechHub then deploys ClientHub and LPEClient, and LPEClient fetches the Cubridge orchestrator. LPEClient protects payload delivery with ML-KEM-1024 post-quantum key encapsulation. Most of the chain lives only in memory. [#1]
Why this pack. The disk and network footprint is small, so the pack hunts the seams that Securelist documents: a CrossWeb EX parent starting fsquirt.exe, a service running from System32\RasConv, a mscoree.dll in the wrong folder, GitHub lookups from processes that should never make them, and the seven published hashes and seven published hosts. Queries are written for Windows endpoint telemetry.
Defender priority: where CrossWeb EX or other mandatory Korean security software is installed, alert on any fsquirt.exe child of the CrossWeb EX service (Q1), any process or service running from RasConv or DrvConh (Q3, Q4) and mscoree.dll outside the system folders (Q5). Then sweep the Section 10 hashes and hosts, and block fsquirt.exe outbound traffic (Playbook 2).
Source Review & Web Hunter Notes
| # | Tier | Source | Key finding | Carry forward |
|---|---|---|---|---|
| 1 | T1 | Kaspersky GReAT (Securelist): Dissecting Operation FlashHole, a complex attack by Lazarus (21 Oct 2026) | Primary technical report: attack flow, TechHub, Cubridge, TouchHub, TouchShift, ClientHub, LPEClient, GitHub C2 design, file paths, seven hashes, eight C2 entries. | yes |
| 2 | T1 | Kaspersky press release: Kaspersky identifies new Lazarus APT campaign utilizing AI and post-quantum encryption (21 Oct 2026) | Same vendor, not independent. Confirms victim sectors, July 2025 start, AI-generated lure content, CrossWeb EX abuse and ML-KEM-1024. Says a potential vulnerability in CrossWeb EX may have enabled entry and that post-quantum use dates to at least September 2024. | yes |
| 3 | T3 | Mallory: Lazarus Targets South Korean Firms With Modular FlashHole Espionage Campaign (21 Oct 2026) | Aggregator summary that cites Securelist as its source. Not independent. Used only to cross-check the timeline; no indicator is taken from it. | partial |
Web Hunter decisions
- Atomic indicators come from the raw Securelist page only. The snapshot was saved from the fetched HTML, not a summary. A summarised fetch dropped two file paths (the qorestor and Dell mscoree.dll entries), which is why the raw page was used. Every hash and host in Section 10 appears in snapshot 01.
- No independent corroboration was found. Searches returned only Securelist, the press release and derivative aggregators. The pack is single-vendor intelligence, so nothing ships at prevent or critical.
- Hashes are MD5. Securelist publishes MD5 only. Falcon IOC Management takes MD5, and Q6 sweeps the same values.
- Five of seven hosts are compromised legitimate sites. They ship at detect with medium severity and a shorter expiry. Blocking at the network edge can be done, but expect the legitimate owners to clean up and the indicator to age out.
- Not included. The COPPERHEDGE cluster, SyncHole indicators, and the Dream Job MISTPEN and ForestTiger chain are discussed in Securelist as related activity. Their indicators are not shipped here. A separate Lazarus pack in the library covers other tooling.
- Names. Every family, campaign and alias in this pack appears in the Securelist snapshot: TechHub (CLOUDBURST, NickelLoader), Cubridge (SIDESHOW, LightlessCan), TouchHub, TouchShift, ClientHub (CookiePlus overlap) and LPEClient.
Contradictions and gaps
- Delivery wording. Securelist describes both a watering-hole strategy and spear-phishing links to GitHub Pages sites. It says it could not determine precisely what triggered the chain, and the press release says a potential CrossWeb EX vulnerability may be the entry. No CVE is named.
- Unpublished infrastructure. The GitHub account and repository names, the Dropbox account and the PAT are not published, so GitHub C2 is hunted by behavior only. The Cubridge authentication token and ZipCrypto password in the report are not imported.
- Telemetry limits. Most of the chain is in memory. Disk artifacts such as ActivationStore.dat, msadc.inc and desktops.ini are not PE files, so Falcon PE write events will not see them; use the native check N1.
- Hash coverage. Only seven hashes are published, six of them for one component. Treat them as a floor, not a boundary.
Overall confidence: Medium-high. The vendor of record documents the chain in detail and the press release agrees. There is no independent confirmation and some mechanism details are acknowledged as unknown.
Hunt Brief & Attack Chain
Hunt hypotheses (ordered by fidelity)
| ID | Hypothesis | MITRE | Telemetry required | Expected FP | Confidence | Queries |
|---|---|---|---|---|---|---|
| H1 | The CrossWeb EX service starts fsquirt.exe, the TechHub injection host. | T1189, T1055, T1620 | Process creation with command line and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | None expected | High | Q1, Q2 |
| H2 | A service or process runs from System32\RasConv or DrvConh, or ImeBroker.exe runs with -TimeBroker. | T1543.003, T1036.005 | Process creation with image path (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); service registry values (CrowdStrike: AsepValueUpdate. SentinelOne: Registry Value Modified. Defender: DeviceRegistryEvents) | None expected | High | Q3, Q4 |
| H3 | mscoree.dll is written to a folder other than System32, SysWOW64 or WinSxS. | T1574.002 | Executable file written (CrowdStrike: PeFileWritten, NewExecutableWritten. SentinelOne: File Creation. Defender: DeviceFileEvents) | Rare .NET servicing copies | High | Q5 |
| H4 | Any of the seven published hashes appears on a host. | T1574.002, T1055 | File hashes on file-write and process events (CrowdStrike: MD5HashData. SentinelOne: process image MD5 where mapped. Defender: MD5) | None expected | High | Q6 |
| H5 | A host resolves a published lure or C2 host. | T1071.001, T1102, T1189 | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents DnsQueryResponse) | Browsing to compromised legitimate sites | Medium | Q7 |
| H6 | fsquirt.exe or ImeBroker.exe talks to GitHub, or a rare non-browser process does. | T1102.002, T1071.001 | DNS lookup with requesting process (as above) | Developer tooling for Q9 | High for Q8, Medium for Q9 | Q8, Q9 |
| H7 | Staging files and Cubridge and ClientHub traffic that endpoint telemetry cannot see. | T1105, T1001.003, T1573 | Disk file presence; proxy and web gateway logs | n/a | Medium | Native N1 to N5 |
Attack chain
| Step | Behavior | Telemetry | Hunt angle |
|---|---|---|---|
| 1 | Spear-phishing link to a GitHub Pages lure site (resume or interior design portfolio), page loads external JavaScript from a script tag. | Mail gateway; web proxy (outside endpoint telemetry) | N3, Q7 |
| 2 | CrossWeb EX is abused; fsquirt.exe runs under the CrossWeb EX process and receives shellcode containing TechHub. | Process creation with parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | Q1, Q2 |
| 3 | TechHub talks to a private GitHub repository by API and PAT, retrieves further payloads including TouchHub. | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents) | Q8, Q9, N4 |
| 4 | TouchHub copies printfilterpipelinesvc.exe to RasConv\ImeBroker.exe, writes mscoree.dll and ActivationStore.dat, timestomps against monitor.sys and registers a service. | File write, service registry value, process creation | Q3, Q4, Q5, Q6, N1, N2 |
| 5 | TouchShift (LockClrVersion export) decrypts and runs a second TechHub in memory. | Process creation under the service; DNS | Q3, Q8 |
| 6 | TechHub deploys ClientHub and LPEClient; LPEClient profiles the host, negotiates ML-KEM-1024 keys and reflectively loads Cubridge. | In-memory; proxy logs of ClientHub and Cubridge traffic | Q7, N5 (gap) |
| 7 | Cubridge loads modules and plugins: AD queries, file collection, browser credential theft, ZipCrypto archiving. | In-memory; archives and DNS | Q7 (gap) |
Consolidated IOC Table
Atomic indicators (importable)
| Type | Value | Confidence | Action | Context |
|---|---|---|---|---|
| MD5 | ec84d6cb2ae7974767aedac246b50a3e | medium | detect | TouchShift mscoree.dll variant |
| MD5 | a28cba214058fcae2883d8cffc883abd | medium | detect | TouchShift mscoree.dll variant |
| MD5 | c105d6b16f544582772de0159f24c00a | medium | detect | TouchShift mscoree.dll variant |
| MD5 | 2f8475a90a25624ed02f1d18d4e6d65d | medium | detect | TouchShift mscoree.dll variant |
| MD5 | 676fabe30a28b53925fba98e34b35986 | medium | detect | TouchShift mscoree.dll variant |
| MD5 | b4a7eff35f048f06fb0a2d7631f23a7d | medium | detect | TouchShift mscoree.dll variant |
| MD5 | ff07641dc56914dd90ee0bd7404d7ad7 | medium | detect | ClientHub loader liblzma.dll |
| Domain | javadevhouse.co.kr | medium | detect | Host named in a script tag on a GitHub Pages lure site |
| Domain | pythonapischool.com | medium | detect | Host named in a script tag on a GitHub Pages lure site |
| Domain | cubedesign.co.kr | medium | detect | Cubridge C2 (compromised site) |
| Domain | fp-news.co.kr | medium | detect | Cubridge C2 (compromised site) |
| Domain | k-wbc.co.kr | medium | detect | ClientHub C2 (compromised site) |
| Domain | rcsh.co.kr | medium | detect | ClientHub C2 (compromised site) |
| Domain | www.ksog.org | medium | detect | ClientHub C2 (compromised site) |
C2 URL paths (hunt only)
| Component | URL path | Note |
|---|---|---|
| Cubridge | cubedesign.co.kr/news | Hardcoded base. Cubridge appends two words from fixed lists and an 8-digit number, for example /news/economy/article/12345678. |
| Cubridge | cubedesign.co.kr/mobile/fashion | |
| Cubridge | fp-news.co.kr/shop/cart | |
| ClientHub | k-wbc.co.kr/skin/social/social_view.php | GET requests carry Sec-CH-UA, Sec-Fetch-Mode and Sec-Fetch-Dest headers. |
| ClientHub | rcsh.co.kr/modules/bbs/tiles/bbs_div/inputForm.php | |
| ClientHub | www.ksog.org/insert_file/handle.php | |
| Lure script | javadevhouse.co.kr/ajax/libs/jquery/1.7.3/jquery.min.js | Embedded in the resume site; looks like a jQuery library path. |
| Lure script | pythonapischool.com/api/detach | Embedded in the interior design site. |
File paths (hunt only, from Securelist)
| Path | Role |
|---|---|
C:\Windows\System32\RasConv\ImeBroker.exe | Copy of printfilterpipelinesvc.exe, registered as a service, run with -TimeBroker |
C:\Windows\System32\RasConv\mscoree.dll | TouchShift side-load payload |
C:\Windows\System32\RasConv\ActivationStore.dat | TechHub configuration file |
C:\Windows\System32\DrvConh\mscoree.dll | TouchShift variant |
C:\Windows\System32\DrvConh\ActivationStore.dat | TechHub configuration file |
C:\ProgramData\RasConv\mscoree.dll | TouchShift variant |
C:\ProgramData\Apple\mscoree.dll | TouchShift variant |
C:\ProgramData\ssh\mscoree.dll | TouchShift variant |
C:\ProgramData\qorestor\mscoree.dll | TouchShift variant |
C:\ProgramData\Dell\mscoree.dll | TouchShift variant |
C:\ProgramData\Dell\Dell1.tmp | Listed artifact |
C:\ProgramData\Dell\Dell3.tmp | Listed artifact |
C:\ProgramData\Package.txt | Listed artifact |
C:\ProgramData\desktops.ini | Listed artifact |
C:\Program Files\Common Files\System\msadc\msadc.inc | ClientHub external configuration |
C:\Windows\System32\drivers\monitor.sys | Legitimate file whose timestamps are copied onto the dropped files |
Legitimate-name caution: ImeBroker.exe, mscoree.dll, liblzma.dll, fsquirt.exe, printfilterpipelinesvc.exe and monitor.sys are real Windows or product file names. Match them by folder and hash, never by name alone, and never prevent on them.
Affected Surface & Telemetry Matrix
| Surface | Telemetry | Priority | Gap |
|---|---|---|---|
| Windows endpoints with CrossWeb EX or other mandatory Korean security software | Process creation with command line and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | Critical | Only hosts with the product are the entry point; inventory first (Playbook 1) |
| All Windows endpoints and servers | Executable file written (CrowdStrike: PeFileWritten. SentinelOne: File Creation. Defender: DeviceFileEvents); service registry values (CrowdStrike: AsepValueUpdate. SentinelOne: Registry Value Modified. Defender: DeviceRegistryEvents) | High | Non-PE files such as ActivationStore.dat and msadc.inc are not covered; use native N1. Confirm Services ImagePath coverage on a tenant |
| DNS and egress | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents DnsQueryResponse); proxy logs | High | Cubridge and ClientHub run in memory in an unknown host process; HTTP content is outside endpoint telemetry |
| Email and web gateway | Message trace; proxy URL logs for *.github.io | High | Outside endpoint telemetry |
| Hosts without a sensor | Native checks N1 to N5 | Medium | Unmanaged Korean-market laptops and contractor devices |
| Memory | Reflectively loaded Cubridge, ClientHub and LPEClient | Medium | No in-memory module telemetry in these queries; rely on the process and network seams |
ATT&CK Mapping
| Tactic | Technique | Name | Observed behavior | Query or control |
|---|---|---|---|---|
| Initial Access | T1566.002 | Spearphishing Link | Emails with links to tailored GitHub Pages resume and portfolio sites | N3, Q7 |
| Initial Access | T1189 | Drive-by Compromise | Visiting the lure site most likely starts the chain through CrossWeb EX (assessed) | Q1, Q2 |
| Execution | T1055, T1620 | Process Injection; Reflective Code Loading | Shellcode with TechHub DLL injected into fsquirt.exe; reflective loading of Cubridge, ClientHub, LPEClient plugins | Q1 |
| Persistence | T1543.003 | Windows Service | TouchHub registers a service named from a netsvcs group name plus two letters, description Microsoft Service | Q3, Q4 |
| Persistence / Defense Evasion | T1574.002 | DLL Side-Loading | TouchShift as mscoree.dll beside ImeBroker.exe; ClientHub loader as liblzma.dll | Q3, Q5, Q6 |
| Defense Evasion | T1036.005 | Match Legitimate Name or Location | printfilterpipelinesvc.exe copied to ImeBroker.exe; legitimate DLL names | Q3, Q5 |
| Defense Evasion | T1070.006 | Timestomp | MAC times of dropped files copied from monitor.sys | N1 |
| Defense Evasion | T1562.001 | Impair Defenses | LPEClient disables a user-mode syscall instrumentation hook | Gap (in-memory) |
| Defense Evasion | T1027 | Obfuscated Files or Information | Encrypted embedded payloads, AES-CBC key from XOR of argument and file name | Q6 |
| Command and Control | T1102.002 | Web Service: Bidirectional Communication | TechHub issues, files and PATCH calls against a private GitHub repository; a ClientHub variant uses Dropbox | Q8, Q9 |
| Command and Control | T1071.001, T1001.003 | Web Protocols; Protocol Impersonation | Cubridge URLs built from news-style word lists; ClientHub sends browser client-hint headers | Q7, N5 |
| Command and Control | T1573 | Encrypted Channel | RSA with RC6 or XOR/AES, SNOW 1.0, GOST, Threefish, ML-KEM-1024 | Gap (payload content) |
| Discovery | T1087.002, T1082, T1057, T1083 | Domain Account, System, Process and File Discovery | ADFinder LDAP plugin, LPEClient profiling, process collector, FileCollector | Gap (in-memory) |
| Credential Access | T1555.003 | Credentials from Web Browsers | Browser stealer tool injected into Chromium browsers; DPAPI key from Local State | Gap (in-memory) |
| Collection | T1560.002, T1005 | Archive via Library; Data from Local System | Legacy ZipCrypto archives of files, screenshots and listed paths | Gap (in-memory) |
Native Audit-Log Hunts
These checks need no Falcon query. Run them in the product named in each row.
N1 · Disk: Operation FlashHole artifacts
Where: Any host, as administrator.
$paths = @(
'C:\Windows\System32\RasConv\ImeBroker.exe','C:\Windows\System32\RasConv\mscoree.dll','C:\Windows\System32\RasConv\ActivationStore.dat',
'C:\Windows\System32\DrvConh\mscoree.dll','C:\Windows\System32\DrvConh\ActivationStore.dat',
'C:\ProgramData\RasConv\mscoree.dll','C:\ProgramData\Apple\mscoree.dll','C:\ProgramData\ssh\mscoree.dll',
'C:\ProgramData\qorestor\mscoree.dll','C:\ProgramData\Dell\mscoree.dll','C:\ProgramData\Dell\Dell1.tmp',
'C:\ProgramData\Dell\Dell3.tmp','C:\ProgramData\Package.txt','C:\ProgramData\desktops.ini',
'C:\Program Files\Common Files\System\msadc\msadc.inc')
$paths | Where-Object { Test-Path -LiteralPath $_ } | ForEach-Object { Get-Item -LiteralPath $_ -Force | Select-Object FullName, Length, CreationTime, LastWriteTime }Any hit on a RasConv, DrvConh, qorestor or ActivationStore.dat path is high confidence. ProgramData\desktops.ini and Dell paths are generic names, so judge them by location and hash. Hash anything found with Get-FileHash -Algorithm MD5 and compare to Section 10.
N2 · Services: Microsoft Service description with a RasConv path
Where: Any Windows host.
Get-CimInstance Win32_Service |
Where-Object { $_.PathName -match 'RasConv|DrvConh|-TimeBroker' -or ($_.Description -eq 'Microsoft Service' -and $_.PathName -notmatch '^"?C:\\Windows\\System32\\svchost\.exe') } |
Select-Object Name, DisplayName, State, StartMode, PathName, DescriptionTouchHub names the service after a netsvcs group member plus two random letters, so the name varies. Match on the path and the description.
N3 · Mail and web proxy: GitHub Pages lure links
Where: Mail gateway and proxy.
# Mail gateway: messages to South Korea-based staff containing links to *.github.io from first-time senders # Proxy: requests to *.github.io followed within minutes by a script fetch from javadevhouse.co.kr or pythonapischool.com # Proxy: any request to the Section 4 URL paths
Securelist assesses with medium to high confidence that targets received phishing emails with links to a site hosted under username.github.io. Prioritise resume, portfolio and interior design themes sent to developers, network engineers and construction staff.
N4 · Proxy and firewall: GitHub API from hosts that do not run developer tools
Where: Web proxy, firewall or secure web gateway.
# Destination api.github.com or raw.githubusercontent.com # Group by source host; keep hosts outside developer and CI groups # Look for steady small requests (issue creation and PATCH calls) and file uploads with 16-character random suffixes in names
TechHub creates an issue titled 1[ID] with body hel, updates it to hey and exchanges files named [1|2][ID][random key]. Inspect-capable proxies may show these; otherwise use volume and cadence.
N5 · Proxy: ClientHub and Cubridge traffic shape
Where: TLS-inspecting proxy.
# Cubridge: POST to news-style URLs such as /<news|economy|...>/<article|list|story>/<8-digit number> on a Korean media or interior design site, # headers X-CSRF-Token and X-Requested-With on a non-browser client # ClientHub: GET requests with Sec-CH-UA, Sec-CH-UA-Platform, Sec-CH-UA-Mobile, Sec-Fetch-Mode, Sec-Fetch-Dest from a non-browser client
These header patterns come from the Securelist analysis. They need a decrypting proxy and are best used to scope a confirmed host, not as a standalone alert.
N6 · Inventory: CrossWeb EX and INISAFE products
Where: Software inventory or the playbook in Section 13.
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object { $_.DisplayName -match 'INISAFE|CrossWeb' } | Select-Object DisplayName, DisplayVersion, InstallDateSecurelist found the parent INISAFECrossWebEXSvc.exe from INISAFE CrossWeb EX V3 version 3.4.1.2. Every host that has the product is in scope for Q1 and Q2.
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.
All 9 queries run on Falcon sensor telemetry for Windows hosts. Mail, proxy and in-memory activity need the native checks in Section 7. Q4 depends on Services ImagePath writes being recorded; confirm that on one host first.
Looks for: The chain start: the legitimate Windows Bluetooth file-transfer wizard fsquirt.exe started with an INISAFE CrossWeb EX parent. Securelist reports TechHub shellcode injected into fsquirt.exe under the CrossWeb EX process, with the parent INISAFECrossWebEXSvc.exe and a high integrity level.
Known limitations and deployment notes
- PowerQuery: A launch by a process the agent did not observe starting is not captured.
- PowerQuery assumes: src.process.name holds the creator image name on a Process Creation event, per the src and tgt rule.
- PowerQuery assumes: The creator name begins with INISAFECrossWebEX on the tenant, the same prefix the CQL tab matches.
- KQL – Defender XDR: A launch by a process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: InitiatingProcessFileName holds the creator image name and begins with INISAFECrossWebEX on the tenant.
// HUNT: fsquirt.exe spawned by CrossWeb EX (TechHub injection host) // MITRE: T1189, T1055, T1620 // CONF: high // FP: low // COST: low // REQUIRES: Process creation with command line and parent (Falcon ProcessRollup2) // FALSE POSITIVES: none expected: fsquirt.exe is normally started by a user or explorer.exe, not by a financial security service // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^INISAFECrossWebEX/i | FileName=/^fsquirt\.exe$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, ImageFileName, CommandLine, SHA256HashData])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.time: Event timeevent.type: Event typesrc.process.name: Creator process nametgt.process.name: Created process name
Recommended fields
tgt.process.image.path: Created process pathtgt.process.cmdline: Created command line
Optional fields
tgt.process.image.sha256: Hash. Population varies by tenant.
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' src.process.name = * tgt.process.name = * | limit 5 | columns event.time, event.type, src.process.name, tgt.process.name
// HUNT: fsquirt.exe spawned by CrossWeb EX (TechHub injection host)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1189, T1055, T1620
// CONF: high | FP: low
// FALSE POSITIVES: none expected: fsquirt.exe is normally started by a user or explorer.exe, not by a financial security service
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a created fsquirt.exe whose creator image name starts with INISAFECrossWebEX. On a Process Creation event the creator is src.process and the created process is tgt.process. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne Process Creation events with creator and created process names
// TUNING: None needed for the published TTP; fsquirt.exe is normally started by a user or explorer.exe.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A launch by a process the agent did not observe starting is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' src.process.name matches '^INISAFECrossWebEX' tgt.process.name in:anycase ('fsquirt.exe')
| 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
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Initiating process nameFileName: Created process name
Recommended fields
FolderPath: Created process pathProcessCommandLine: Created command line
Optional fields
SHA256: Hash. SHA256 is often unpopulated in DeviceProcessEvents; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, InitiatingProcessFileName, FileName | take 5
// HUNT: fsquirt.exe spawned by CrossWeb EX (TechHub injection host) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1189, T1055, T1620 // CONF: high | FP: low // FALSE POSITIVES: none expected: fsquirt.exe is normally started by a user or explorer.exe, not by a financial security service // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a created fsquirt.exe whose initiating process name starts with INISAFECrossWebEX. startswith and =~ are case-insensitive, which reproduces the CQL /i intent. The parent is InitiatingProcessFileName. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: None needed for the published TTP; fsquirt.exe is normally started by a user or explorer.exe. // LOOKBACK: 30d (Advanced Hunting retention) // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A launch 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 startswith "INISAFECrossWebEX" | where FileName =~ "fsquirt.exe" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: Every process the INISAFE CrossWeb EX service starts, stacked by count. Securelist could not determine how CrossWeb EX was abused, so any child other than the vendor's own helpers is a lead. Read bottom-up: rare child names on few hosts first. FP: CrossWeb EX updaters and helper installers start child processes on a schedule. Baseline 30 days, then exclude the vendor's signed helper names that appear on most hosts.
Known limitations and deployment notes
- PowerQuery: Distinct hosts is an estimate; a small count on a large estate can differ by one or two.
- PowerQuery assumes: src.process.name holds the creator image name on a Process Creation event.
- PowerQuery assumes: estimate_distinct is an estimate, not an exact host count.
- KQL – Defender XDR: Distinct devices is an estimate; a small count on a large estate can differ by one or two.
- KQL – Defender XDR assumes: InitiatingProcessFileName begins with INISAFECrossWebEX on the tenant.
- KQL – Defender XDR assumes: dcount is an estimate, not an exact device count.
// HUNT: Stack of child processes under CrossWeb EX // MITRE: T1189, T1055 // CONF: medium // FP: medium // COST: low // REQUIRES: Process creation with parent (Falcon ProcessRollup2) // FALSE POSITIVES: vendor updater and helper processes // TUNING: baseline for 30 days and exclude FileName values that run on more than half of CrossWeb EX hosts; keep anything running from a user-writable or System32 subfolder path // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^INISAFECrossWebEX/i | groupBy([FileName, ImageFileName], function=[count(as=runs), count(aid, distinct=true, as=hosts)]) | sort(hosts, order=asc) | table([FileName, ImageFileName, hosts, runs])
6 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.time: Event timeevent.type: Event typesrc.process.name: Creator process nametgt.process.name: Created process nametgt.process.image.path: Created process pathagent.uuid: Host identity
Fallbacks
agent.uuid→endpoint.name: Counts hosts by name instead of by agent identity.
Readiness test
event.type = 'Process Creation' src.process.name = * tgt.process.name = * tgt.process.image.path = * agent.uuid = * | limit 5 | columns event.time, event.type, src.process.name, tgt.process.name, tgt.process.image.path, agent.uuid
// HUNT: Stack of child processes under CrossWeb EX // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1189, T1055 // CONF: medium | FP: medium // FALSE POSITIVES: vendor updater and helper processes // EQUIVALENCE: equivalent-with-schema-assumptions - Same stack count: children of a process whose name starts with INISAFECrossWebEX, grouped by created process name and path with run and distinct-host counts, rarest hosts first. The creator is src.process on a Process Creation event. // REQUIRES: SentinelOne Process Creation events with creator and created process names and paths // TUNING: Baseline for 30 days and exclude created process names that run on more than half of CrossWeb EX hosts; keep anything running from a user-writable or System32 subfolder path. // LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Distinct hosts is an estimate; a small count on a large estate can differ by one or two. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' src.process.name matches '^INISAFECrossWebEX' | group runs = count(), hosts = estimate_distinct(agent.uuid) by tgt.process.name, tgt.process.image.path | sort +hosts | limit 200
Automated validation: static-passed
5 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Initiating process nameFileName: Created process nameFolderPath: Created process pathDeviceId: Device identity
Fallbacks
DeviceId→DeviceName: Counts devices by name instead of by identity.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, InitiatingProcessFileName, FileName, FolderPath, DeviceId | take 5
// HUNT: Stack of child processes under CrossWeb EX // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1189, T1055 // CONF: medium | FP: medium // FALSE POSITIVES: vendor updater and helper processes // EQUIVALENCE: equivalent-with-schema-assumptions - Same stack count: children of a process whose name starts with INISAFECrossWebEX, grouped by created process name and path with run and distinct-device counts, rarest first. dcount is an estimate. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: Baseline for 30 days and exclude created process names that run on more than half of CrossWeb EX hosts; keep anything running from a user-writable or System32 subfolder path. // LOOKBACK: 30d (Advanced Hunting retention) // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Distinct devices is an estimate; a small count on a large estate can differ by one or two. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where InitiatingProcessFileName startswith "INISAFECrossWebEX" | summarize runs = count(), hosts = dcount(DeviceId) by FileName, FolderPath | sort by hosts asc | take 200
Looks for: The persistence service. TouchHub copies printfilterpipelinesvc.exe to C:\Windows\System32\RasConv\ImeBroker.exe and starts it with -TimeBroker so it side-loads the TouchShift mscoree.dll. The real ImeBroker.exe lives directly in System32, so the RasConv and DrvConh folders and the -TimeBroker argument are the discriminators. DrvConh appears in Securelist's paths for the same pattern.
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 created image path with backslash separators on Windows.
- 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 with backslash separators on Windows.
// HUNT: Process image in RasConv or DrvConh, or ImeBroker -TimeBroker // MITRE: T1543.003, T1574.002, T1036.005 // CONF: high // FP: low // COST: low // REQUIRES: Process creation with image path and command line (Falcon ProcessRollup2) // FALSE POSITIVES: none expected: RasConv and DrvConh are not standard System32 subfolders // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ImageFileName=/\\(RasConv|DrvConh)\\/i or CommandLine=/ImeBroker\.exe\W+-TimeBroker/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, ImageFileName, CommandLine, SHA256HashData])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.time: Event timeevent.type: Event typetgt.process.image.path: Created process pathtgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creator process name
Optional fields
tgt.process.image.sha256: Hash. Population varies by tenant.
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' tgt.process.image.path = * tgt.process.cmdline = * | limit 5 | columns event.time, event.type, tgt.process.image.path, tgt.process.cmdline
// HUNT: Process image in RasConv or DrvConh, or ImeBroker -TimeBroker // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1543.003, T1574.002, T1036.005 // CONF: high | FP: low // FALSE POSITIVES: none expected: RasConv and DrvConh are not standard System32 subfolders // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: the created image path contains a RasConv or DrvConh directory, or the command line is ImeBroker.exe followed by -TimeBroker. The created process is tgt.process on a Process Creation event. matches is case-insensitive, which reproduces the CQL /i intent. // REQUIRES: SentinelOne Process Creation events with created image path and command line // TUNING: None needed for the published TTP; RasConv and DrvConh are not standard System32 subfolders. // LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate // CONFIGURATION: No lookup objects required. // 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 '\\\\(RasConv|DrvConh)\\\\' or tgt.process.cmdline matches 'ImeBroker\\.exe\\W+-TimeBroker') | 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 | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFolderPath: Created process pathProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Optional fields
SHA256: Hash. SHA256 is often unpopulated in DeviceProcessEvents; 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: Process image in RasConv or DrvConh, or ImeBroker -TimeBroker // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.003, T1574.002, T1036.005 // CONF: high | FP: low // FALSE POSITIVES: none expected: RasConv and DrvConh are not standard System32 subfolders // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: the created image path contains a RasConv or DrvConh directory, or the command line is ImeBroker.exe followed by -TimeBroker. contains is case-insensitive and the regex carries (?i), which reproduces the CQL /i intent. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: None needed for the published TTP; RasConv and DrvConh are not standard System32 subfolders. // LOOKBACK: 30d (Advanced Hunting retention) // 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 contains "\\RasConv\\" or FolderPath contains "\\DrvConh\\" or ProcessCommandLine matches regex @"(?i)ImeBroker\.exe\W+-TimeBroker" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: The service registration step. TouchHub builds a random service name from a netsvcs svchost group name plus two letters, sets the description Microsoft Service, and runs the ImeBroker.exe -TimeBroker command line. Query the service ImagePath value, not the random name. Validate in your tenant that AsepValueUpdate records Services ImagePath writes.
Known limitations and deployment notes
- PowerQuery: A service created through an API that does not raise a registry value event is not captured.
- PowerQuery assumes: registry.keyPath carries the full key path including the Services segment.
- PowerQuery assumes: registry.value holds the string data written to ImagePath.
- PowerQuery assumes: src.process.name is the process that wrote the value.
- KQL – Defender XDR: A service created through an API that does not raise a registry value event is not captured.
- KQL – Defender XDR assumes: RegistryKey carries the full key path including the Services segment.
- KQL – Defender XDR assumes: RegistryValueData holds the string data written to ImagePath.
// HUNT: Service ImagePath set to RasConv or DrvConh binary // MITRE: T1543.003 // CONF: high // FP: low // COST: low // REQUIRES: Registry autostart value updates (Falcon AsepValueUpdate); validate Services key coverage in tenant // FALSE POSITIVES: none expected // LOOKBACK: 30d #event_simpleName=AsepValueUpdate | RegObjectName=/\\Services\\/i | RegValueName=/^ImagePath$/i | RegStringValue=/\\(RasConv|DrvConh)\\|-TimeBroker/i | table([@timestamp, ComputerName, UserName, RegObjectName, RegValueName, RegStringValue, ContextBaseFileName])
5 required fields · View requirements
Required telemetry
- Registry Value Modified
Required fields
event.time: Event timeevent.type: Event typeregistry.keyPath: Registry key pathregistry.valueName: Registry value nameregistry.value: Registry value data
Recommended fields
src.process.name: Writing process
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Registry Value Modified' registry.keyPath = * registry.valueName = * registry.value = * | limit 5 | columns event.time, event.type, registry.keyPath, registry.valueName, registry.value
// HUNT: Service ImagePath set to RasConv or DrvConh binary
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1543.003
// CONF: high | FP: low
// FALSE POSITIVES: none expected
// EQUIVALENCE: equivalent-with-schema-assumptions - Same registry predicate: an ImagePath value under a Services key whose data names a RasConv or DrvConh directory or carries -TimeBroker. The CQL reads autostart value updates; this reads registry value modifications, a superset that the key and value predicates narrow.
// REQUIRES: SentinelOne Registry Value Modified events with key path, value name and value data
// TUNING: None needed for the published TTP.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A service created through an API that does not raise a registry value event is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Registry Value Modified' registry.keyPath contains '\\Services\\' registry.valueName in:anycase ('ImagePath') registry.value matches '\\\\(RasConv|DrvConh)\\\\|-TimeBroker'
| columns event.time, endpoint.name, src.process.user, registry.keyPath, registry.valueName, registry.value, src.process.name
| limit 200Automated validation: static-passed
5 required fields · View requirements
Required telemetry
- DeviceRegistryEvents
Required fields
Timestamp: Event timeActionType: Action typeRegistryKey: Registry key pathRegistryValueName: Registry value nameRegistryValueData: Registry value data
Recommended fields
InitiatingProcessFileName: Writing process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceRegistryEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, RegistryKey, RegistryValueName, RegistryValueData | take 5
// HUNT: Service ImagePath set to RasConv or DrvConh binary // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.003 // CONF: high | FP: low // FALSE POSITIVES: none expected // EQUIVALENCE: equivalent-with-schema-assumptions - Same registry predicate: an ImagePath value set under a Services key whose data names a RasConv or DrvConh directory or carries -TimeBroker. The CQL reads autostart value updates; this reads RegistryValueSet on DeviceRegistryEvents. // REQUIRES: Defender for Endpoint registry telemetry (DeviceRegistryEvents) // TUNING: None needed for the published TTP. // LOOKBACK: 30d (Advanced Hunting retention) // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A service created through an API that does not raise a registry value event is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceRegistryEvents | where Timestamp >= ago(30d) | where ActionType == "RegistryValueSet" | where RegistryKey contains "\\Services\\" | where RegistryValueName =~ "ImagePath" | where RegistryValueData contains "\\RasConv\\" or RegistryValueData contains "\\DrvConh\\" or RegistryValueData contains "-TimeBroker" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, RegistryKey, RegistryValueName, RegistryValueData | sort by Timestamp desc | take 200
Looks for: TouchShift side-loads as mscoree.dll. Securelist lists it under System32 RasConv and DrvConh and under ProgramData RasConv, Apple, ssh, qorestor and Dell. The genuine mscoree.dll sits directly in System32, SysWOW64 and WinSxS, so those are excluded and every other location surfaces. FP: some .NET Framework servicing and developer SDK installs place a copy of mscoree.dll in versioned folders. Tune by excluding the signed servicing parents (TrustedInstaller, msiexec from a known deployment tool).
Known limitations and deployment notes
- PowerQuery: An overwrite of an existing mscoree.dll raises File Modification and is not captured.
- PowerQuery assumes: tgt.file.path holds the full path with backslash separators on Windows.
- PowerQuery assumes: A DLL that overwrites an existing file raises File Modification rather than File Creation and is not covered.
- KQL – Defender XDR: An overwrite of an existing mscoree.dll raises FileModified and is not captured.
- KQL – Defender XDR: The MD5 column the CQL tab projects has no counterpart here; SHA1 and SHA256 are shown instead.
- KQL – Defender XDR assumes: FolderPath holds the full path including the file name, with backslash separators on Windows.
- KQL – Defender XDR assumes: A DLL that overwrites an existing file raises FileModified rather than FileCreated and is not covered.
// HUNT: mscoree.dll created outside System32, SysWOW64 and WinSxS // MITRE: T1574.002, T1036.005 // CONF: high // FP: low // COST: low // REQUIRES: Executable file writes (Falcon PeFileWritten, NewExecutableWritten) // FALSE POSITIVES: rare .NET SDK or servicing copies // TUNING: exclude ContextBaseFileName=TrustedInstaller.exe and your software-deployment agent; keep the ProgramData and System32 subfolder paths from Section 4 // LOOKBACK: 30d #event_simpleName=/^(PeFileWritten|NewExecutableWritten)$/ | TargetFileName=/\\mscoree\.dll$/i | TargetFileName!=/\\Windows\\(System32|SysWOW64)\\mscoree\.dll$|\\Windows\\WinSxS\\/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, TargetFileName, MD5HashData, SHA256HashData])
3 required fields · View requirements
Required telemetry
- File Creation
Required fields
event.time: Event timeevent.type: Event typetgt.file.path: Created file path
Recommended fields
src.process.name: Writing process
Optional fields
tgt.file.sha256: Hash. Population varies by tenant.
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'File Creation' tgt.file.path = * | limit 5 | columns event.time, event.type, tgt.file.path
// HUNT: mscoree.dll created outside System32, SysWOW64 and WinSxS // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1574.002, T1036.005 // CONF: high | FP: low // FALSE POSITIVES: rare .NET SDK or servicing copies // EQUIVALENCE: equivalent-with-schema-assumptions - Same file predicate: a file named mscoree.dll created anywhere except directly in the Windows System32 or SysWOW64 directory or under WinSxS. The CQL reads executable file writes; this reads File Creation events, which covers a newly created DLL. // REQUIRES: SentinelOne File Creation events with target file path // TUNING: Exclude TrustedInstaller.exe and your software-deployment agent by src.process.name; keep the ProgramData and System32 subfolder paths from Section 4. // LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An overwrite of an existing mscoree.dll raises File Modification and is not captured. // VALIDATION LEVEL: static-reviewed event.type = 'File Creation' tgt.file.path contains 'mscoree.dll' tgt.file.path matches '\\\\mscoree\\.dll$' !(tgt.file.path matches '\\\\Windows\\\\(System32|SysWOW64)\\\\mscoree\\.dll$|\\\\Windows\\\\WinSxS\\\\') | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.file.path, tgt.file.md5, tgt.file.sha256 | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceFileEvents
Required fields
Timestamp: Event timeActionType: Action typeFileName: File nameFolderPath: File path
Recommended fields
InitiatingProcessFileName: Writing process
Optional fields
SHA1: Hash. SHA256 is often unpopulated; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceFileEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, FileName, FolderPath | take 5
// HUNT: mscoree.dll created outside System32, SysWOW64 and WinSxS // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1574.002, T1036.005 // CONF: high | FP: low // FALSE POSITIVES: rare .NET SDK or servicing copies // EQUIVALENCE: equivalent-with-schema-assumptions - Same file predicate: a file named mscoree.dll created anywhere except directly in the Windows System32 or SysWOW64 directory or under WinSxS. The CQL reads executable file writes; this reads FileCreated on DeviceFileEvents. // REQUIRES: Defender for Endpoint file telemetry (DeviceFileEvents) // TUNING: Exclude TrustedInstaller.exe and your software-deployment agent by InitiatingProcessFileName; keep the ProgramData and System32 subfolder paths from Section 4. // LOOKBACK: 30d (Advanced Hunting retention) // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An overwrite of an existing mscoree.dll raises FileModified and is not captured. The MD5 column the CQL tab projects has no counterpart here; SHA1 and SHA256 are shown instead. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceFileEvents | where Timestamp >= ago(30d) | where ActionType == "FileCreated" | where FileName =~ "mscoree.dll" | where not(FolderPath matches regex @"(?i)\\Windows\\(System32|SysWOW64)\\mscoree\.dll$|\\Windows\\WinSxS\\") | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, FolderPath, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: The seven MD5 values Securelist publishes: six TouchShift mscoree.dll variants and the ClientHub loader liblzma.dll. Matches on file write and on process image. This is the only sweep for the hashes; they are single-source, so they ship at detect.
Known limitations and deployment notes
- PowerQuery: A hash match depends on MD5 being populated; a tenant that stores only SHA1 or SHA256 sees nothing.
- PowerQuery assumes: tgt.process.image.md5 and tgt.file.md5 are populated on the tenant; MD5 population varies and a null hash returns nothing.
- PowerQuery assumes: A file that is modified in place raises File Modification and is not covered.
- KQL – Defender XDR: Defender cannot match the published MD5 hashes: the declared tables expose SHA1 and SHA256 only.
// HUNT: Operation FlashHole published MD5 hashes // MITRE: T1574.002, T1055 // CONF: high // FP: low // COST: low // REQUIRES: File write and process telemetry carrying MD5HashData (Falcon PeFileWritten, NewExecutableWritten, ProcessRollup2) // FALSE POSITIVES: none expected for these hashes // LOOKBACK: 30d #event_simpleName=/^(PeFileWritten|NewExecutableWritten|ProcessRollup2|SyntheticProcessRollup2)$/ | MD5HashData=/^(ec84d6cb2ae7974767aedac246b50a3e|a28cba214058fcae2883d8cffc883abd|c105d6b16f544582772de0159f24c00a|2f8475a90a25624ed02f1d18d4e6d65d|676fabe30a28b53925fba98e34b35986|b4a7eff35f048f06fb0a2d7631f23a7d|ff07641dc56914dd90ee0bd7404d7ad7)$/i | table([@timestamp, ComputerName, UserName, FileName, TargetFileName, ImageFileName, MD5HashData, SHA256HashData])
4 required fields · View requirements
Required telemetry
- Process Creation
- File Creation
Required fields
event.time: Event timeevent.type: Event typetgt.process.image.md5: Created process MD5tgt.file.md5: Created file MD5
Recommended fields
src.process.name: Creator or writing process
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' tgt.process.image.md5 = * | limit 5 | columns event.time, event.type, tgt.process.image.md5, tgt.file.md5
// HUNT: Operation FlashHole published MD5 hashes
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1574.002, T1055
// CONF: high | FP: low
// FALSE POSITIVES: none expected for these hashes
// EQUIVALENCE: equivalent-with-schema-assumptions - Same MD5 set matched against the created process image on Process Creation events and against the created file on File Creation events, the two populations the CQL reads. in:anycase reproduces the CQL /i intent.
// REQUIRES: SentinelOne Process Creation and File Creation events carrying MD5 hashes
// TUNING: None needed for a published hash set.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A hash match depends on MD5 being populated; a tenant that stores only SHA1 or SHA256 sees nothing.
// VALIDATION LEVEL: static-reviewed
(event.type = 'Process Creation' tgt.process.image.md5 in:anycase ('ec84d6cb2ae7974767aedac246b50a3e', 'a28cba214058fcae2883d8cffc883abd', 'c105d6b16f544582772de0159f24c00a', '2f8475a90a25624ed02f1d18d4e6d65d', '676fabe30a28b53925fba98e34b35986', 'b4a7eff35f048f06fb0a2d7631f23a7d', 'ff07641dc56914dd90ee0bd7404d7ad7')) or (event.type = 'File Creation' tgt.file.md5 in:anycase ('ec84d6cb2ae7974767aedac246b50a3e', 'a28cba214058fcae2883d8cffc883abd', 'c105d6b16f544582772de0159f24c00a', '2f8475a90a25624ed02f1d18d4e6d65d', '676fabe30a28b53925fba98e34b35986', 'b4a7eff35f048f06fb0a2d7631f23a7d', 'ff07641dc56914dd90ee0bd7404d7ad7'))
| columns event.time, endpoint.name, src.process.user, event.type, src.process.name, tgt.process.name, tgt.process.image.path, tgt.file.path, tgt.process.image.md5, tgt.file.md5
| limit 2001 required field · View requirements
Required telemetry
- none
Required fields
Timestamp: Event time
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp | take 5
// HUNT: Operation FlashHole published MD5 hashes // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1574.002, T1055 // CONF: high | FP: low // FALSE POSITIVES: none expected for these hashes // EQUIVALENCE: unsupported-without-redesign - The CQL matches published MD5 hashes only, and the Advanced Hunting tables declared for this pack expose SHA1 and SHA256 but no MD5 column, so no faithful Defender query exists for this card. // REQUIRES: A published SHA1 or SHA256 for the same samples, which the source intel does not provide // TUNING: Use the CQL or PowerQuery tab for this card, or convert the hashes to SHA1 or SHA256 from the original samples. // LOOKBACK: 30d on the CQL tab // CONFIGURATION: Use the CQL tab for this card. // KNOWN GAPS: Defender cannot match the published MD5 hashes: the declared tables expose SHA1 and SHA256 only. // VALIDATION LEVEL: static-reviewed
Looks for: Lookups for the two lure script hosts and the five hosts Securelist lists as Cubridge or ClientHub C2. Five are compromised legitimate sites, so a hit by a browser may be an innocent visit. A non-browser process, or one host resolving a name nobody else does, is the signal. FP: ordinary browsing to the compromised sites. Split the result by ContextBaseFileName and prioritise non-browser processes and hosts with CrossWeb EX installed.
Known limitations and deployment notes
- PowerQuery: A lookup made through a resolver the agent does not observe is not captured.
- PowerQuery assumes: event.dns.request is the populated name field on the tenant; some schema versions use dns.request instead.
- PowerQuery assumes: src.process.name is the requesting process on a DNS Resolved event.
- KQL – Defender XDR: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
- KQL – Defender XDR assumes: DnsQueryResponse events are populated and AdditionalFields carries the name under DnsQueryString or QueryName.
- KQL – Defender XDR assumes: InitiatingProcessFileName is the requesting process.
// HUNT: DNS lookups for published lure and C2 hosts // MITRE: T1071.001, T1102, T1189 // CONF: medium // FP: medium // COST: low // REQUIRES: DNS lookups with requesting process (Falcon DnsRequest) // FALSE POSITIVES: users who legitimately visit the compromised Korean sites // TUNING: exclude ContextBaseFileName for chrome.exe, msedge.exe, firefox.exe and whale.exe only after confirming no CrossWeb EX host resolved the name; rank by distinct host count ascending // LOOKBACK: 30d #event_simpleName=DnsRequest | DomainName=/^(javadevhouse\.co\.kr|pythonapischool\.com|cubedesign\.co\.kr|fp-news\.co\.kr|k-wbc\.co\.kr|rcsh\.co\.kr|(www\.)?ksog\.org)$/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName])
3 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.time: Event timeevent.type: Event typeevent.dns.request: Requested name
Recommended fields
src.process.name: Requesting process
Fallbacks
event.dns.request→dns.request: Some schema versions populate the other name; check which one returns values.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * | limit 5 | columns event.time, event.type, event.dns.request, src.process.name
// HUNT: DNS lookups for published lure and C2 hosts
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1071.001, T1102, T1189
// CONF: medium | FP: medium
// FALSE POSITIVES: users who legitimately visit the compromised Korean sites
// EQUIVALENCE: equivalent-with-schema-assumptions - Same DNS predicate: a lookup whose requested name equals one of the published lure or C2 hosts, with the requesting process. The name is event.dns.request and the requester is src.process on a DNS Resolved event. in:anycase reproduces the CQL /i intent.
// REQUIRES: SentinelOne DNS Resolved events with the requested name and requesting process
// TUNING: Exclude chrome.exe, msedge.exe, firefox.exe and whale.exe by src.process.name only after confirming no CrossWeb EX host resolved the name; rank by distinct host count ascending.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A lookup made through a resolver the agent does not observe is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved' event.dns.request in:anycase ('javadevhouse.co.kr', 'pythonapischool.com', 'cubedesign.co.kr', 'fp-news.co.kr', 'k-wbc.co.kr', 'rcsh.co.kr', 'ksog.org', 'www.ksog.org')
| columns event.time, endpoint.name, src.process.user, src.process.name, event.dns.request
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeAdditionalFields: Requested name
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 published lure and C2 hosts
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1071.001, T1102, T1189
// CONF: medium | FP: medium
// FALSE POSITIVES: users who legitimately visit the compromised Korean sites
// EQUIVALENCE: equivalent-with-schema-assumptions - Same DNS predicate: a lookup whose name equals one of the published lure or C2 hosts, with the requesting process. Defender has no endpoint DNS table, so the name is read from AdditionalFields of DnsQueryResponse events on DeviceEvents. in~ reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint DNS telemetry (DeviceEvents, ActionType DnsQueryResponse)
// TUNING: Exclude chrome.exe, msedge.exe, firefox.exe and whale.exe by InitiatingProcessFileName only after confirming no CrossWeb EX host resolved the name; rank by distinct device count ascending.
// LOOKBACK: 30d (Advanced Hunting retention)
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType == "DnsQueryResponse"
| extend DnsName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"]))
| where DnsName in~ ("javadevhouse.co.kr", "pythonapischool.com", "cubedesign.co.kr", "fp-news.co.kr", "k-wbc.co.kr", "rcsh.co.kr", "ksog.org", "www.ksog.org")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, DnsName
| sort by Timestamp desc
| take 200Looks for: TechHub's C2 channel. It talks to private GitHub repositories through the GitHub API using a Personal Access Token. fsquirt.exe is a local Bluetooth transfer wizard and the rogue ImeBroker.exe is a service host, so neither has a reason to resolve a GitHub name.
Known limitations and deployment notes
- PowerQuery: A lookup made through a resolver the agent does not observe is not captured.
- PowerQuery assumes: event.dns.request is the populated name field on the tenant; some schema versions use dns.request instead.
- PowerQuery assumes: src.process.name is the requesting process on a DNS Resolved event.
- KQL – Defender XDR: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
- KQL – Defender XDR assumes: DnsQueryResponse events are populated and AdditionalFields carries the name under DnsQueryString or QueryName.
- KQL – Defender XDR assumes: InitiatingProcessFileName is the requesting process.
// HUNT: fsquirt.exe or ImeBroker.exe resolving GitHub hosts // MITRE: T1102.002, T1071.001 // CONF: high // FP: low // COST: low // REQUIRES: DNS lookups with requesting process (Falcon DnsRequest) // FALSE POSITIVES: none expected // LOOKBACK: 30d #event_simpleName=DnsRequest | DomainName=/^(api\.github\.com|github\.com|raw\.githubusercontent\.com)$/i | ContextBaseFileName=/^(fsquirt|ImeBroker)\.exe$/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName])
4 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.time: Event timeevent.type: Event typeevent.dns.request: Requested namesrc.process.name: Requesting process
Fallbacks
event.dns.request→dns.request: Some schema versions populate the other name; check which one returns values.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * src.process.name = * | limit 5 | columns event.time, event.type, event.dns.request, src.process.name
// HUNT: fsquirt.exe or ImeBroker.exe resolving GitHub hosts
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1102.002, T1071.001
// CONF: high | FP: low
// FALSE POSITIVES: none expected
// EQUIVALENCE: equivalent-with-schema-assumptions - Same DNS predicate: fsquirt.exe or ImeBroker.exe requesting a GitHub host. The name is event.dns.request and the requester is src.process on a DNS Resolved event. in:anycase reproduces the CQL /i intent.
// REQUIRES: SentinelOne DNS Resolved events with the requested name and requesting process
// TUNING: None needed for the published TTP.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A lookup made through a resolver the agent does not observe is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved' event.dns.request in:anycase ('api.github.com', 'github.com', 'raw.githubusercontent.com') src.process.name in:anycase ('fsquirt.exe', 'ImeBroker.exe')
| columns event.time, endpoint.name, src.process.user, src.process.name, event.dns.request
| limit 200Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeInitiatingProcessFileName: Requesting processAdditionalFields: Requested name
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "DnsQueryResponse" | project Timestamp, ActionType, InitiatingProcessFileName, AdditionalFields | take 5
// HUNT: fsquirt.exe or ImeBroker.exe resolving GitHub hosts
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1102.002, T1071.001
// CONF: high | FP: low
// FALSE POSITIVES: none expected
// EQUIVALENCE: equivalent-with-schema-assumptions - Same DNS predicate: fsquirt.exe or ImeBroker.exe requesting a GitHub host. Defender has no endpoint DNS table, so the name is read from AdditionalFields of DnsQueryResponse events on DeviceEvents. in~ reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint DNS telemetry (DeviceEvents, ActionType DnsQueryResponse)
// TUNING: None needed for the published TTP.
// LOOKBACK: 30d (Advanced Hunting retention)
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType == "DnsQueryResponse"
| where InitiatingProcessFileName in~ ("fsquirt.exe", "ImeBroker.exe")
| extend DnsName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"]))
| where DnsName in~ ("api.github.com", "github.com", "raw.githubusercontent.com")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, DnsName
| sort by Timestamp desc
| take 200Looks for: A broad net for TechHub variants that run in other host processes (it exists in memory, as a side-loaded DLL and as a service). Stack by process name and read the rare ones. This is a hunt for analysts, not an alert. FP: developer tools, CI agents, package managers and collaboration clients resolve GitHub constantly. Build the exclusion list from 30 days of data; do not alert on this query.
Known limitations and deployment notes
- PowerQuery: Distinct hosts is an estimate; a small count on a large estate can differ by one or two.
- PowerQuery assumes: event.dns.request is the populated name field on the tenant; some schema versions use dns.request instead.
- PowerQuery assumes: src.process.name is the requesting process on a DNS Resolved event.
- PowerQuery assumes: estimate_distinct is an estimate, not an exact host count.
- KQL – Defender XDR: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
- KQL – Defender XDR assumes: DnsQueryResponse events are populated and AdditionalFields carries the name under DnsQueryString or QueryName.
- KQL – Defender XDR assumes: dcount is an estimate, not an exact device count.
// HUNT: Rare non-browser processes resolving api.github.com // MITRE: T1102.002, T1071.001 // CONF: medium // FP: high // COST: low // REQUIRES: DNS lookups with requesting process (Falcon DnsRequest) // FALSE POSITIVES: git, IDEs, CI runners, package managers, collaboration apps // TUNING: extend the excluded names with your sanctioned developer tooling, restrict to non-developer host groups, and sort by host count ascending // LOOKBACK: 30d #event_simpleName=DnsRequest | DomainName=/^(api\.github\.com|raw\.githubusercontent\.com)$/i | ContextBaseFileName!=/^(chrome|msedge|firefox|brave|whale|iexplore|git|git-remote-https|gh|code|githubdesktop|devenv|node|python|pwsh|powershell|onedrive)\.exe$/i | groupBy([ContextBaseFileName], function=[count(as=lookups), count(aid, distinct=true, as=hosts)]) | sort(hosts, order=asc) | table([ContextBaseFileName, hosts, lookups])
5 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.time: Event timeevent.type: Event typeevent.dns.request: Requested namesrc.process.name: Requesting processagent.uuid: Host identity
Fallbacks
agent.uuid→endpoint.name: Counts hosts by name instead of by agent identity.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * src.process.name = * agent.uuid = * | limit 5 | columns event.time, event.type, event.dns.request, src.process.name, agent.uuid
// HUNT: Rare non-browser processes resolving api.github.com
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1102.002, T1071.001
// CONF: medium | FP: high
// FALSE POSITIVES: git, IDEs, CI runners, package managers, collaboration apps
// EQUIVALENCE: equivalent-with-schema-assumptions - Same stack count: lookups of api.github.com or raw.githubusercontent.com by any process outside the excluded browser and developer-tool names, grouped by requesting process with lookup and distinct-host counts, rarest hosts first. in:anycase reproduces the CQL /i intent.
// REQUIRES: SentinelOne DNS Resolved events with the requested name and requesting process
// TUNING: Extend the excluded names with your sanctioned developer tooling, restrict to non-developer host groups, and keep the sort by host count ascending.
// LOOKBACK: 30d; set the time picker or query window, the published query carries no time predicate
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Distinct hosts is an estimate; a small count on a large estate can differ by one or two.
// VALIDATION LEVEL: static-reviewed
event.type = 'DNS Resolved' event.dns.request in:anycase ('api.github.com', 'raw.githubusercontent.com') src.process.name = * !(src.process.name in:anycase ('chrome.exe', 'msedge.exe', 'firefox.exe', 'brave.exe', 'whale.exe', 'iexplore.exe', 'git.exe', 'git-remote-https.exe', 'gh.exe', 'code.exe', 'githubdesktop.exe', 'devenv.exe', 'node.exe', 'python.exe', 'pwsh.exe', 'powershell.exe', 'onedrive.exe'))
| group lookups = count(), hosts = estimate_distinct(agent.uuid) by src.process.name
| sort +hosts
| limit 200Automated validation: static-passed
5 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Action typeInitiatingProcessFileName: Requesting processAdditionalFields: Requested nameDeviceId: Device identity
Fallbacks
DeviceId→DeviceName: Counts devices by name instead of by identity.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "DnsQueryResponse" | project Timestamp, ActionType, InitiatingProcessFileName, AdditionalFields, DeviceId | take 5
// HUNT: Rare non-browser processes resolving api.github.com
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1102.002, T1071.001
// CONF: medium | FP: high
// FALSE POSITIVES: git, IDEs, CI runners, package managers, collaboration apps
// EQUIVALENCE: equivalent-with-schema-assumptions - Same stack count: lookups of api.github.com or raw.githubusercontent.com by any process outside the excluded browser and developer-tool names, grouped by requesting process with lookup and distinct-device counts, rarest first. Defender has no endpoint DNS table, so the name is read from AdditionalFields of DnsQueryResponse events on DeviceEvents.
// REQUIRES: Defender for Endpoint DNS telemetry (DeviceEvents, ActionType DnsQueryResponse)
// TUNING: Extend the excluded names with your sanctioned developer tooling, restrict to non-developer device groups, and keep the sort by device count ascending.
// LOOKBACK: 30d (Advanced Hunting retention)
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The DnsQueryResponse action type is attested in Microsoft hunting repositories but not catalogued on Microsoft Learn.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType == "DnsQueryResponse"
| where InitiatingProcessFileName !in~ ("chrome.exe", "msedge.exe", "firefox.exe", "brave.exe", "whale.exe", "iexplore.exe", "git.exe", "git-remote-https.exe", "gh.exe", "code.exe", "githubdesktop.exe", "devenv.exe", "node.exe", "python.exe", "pwsh.exe", "powershell.exe", "onedrive.exe")
| extend DnsName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"]))
| where DnsName in~ ("api.github.com", "raw.githubusercontent.com")
| summarize lookups = count(), hosts = dcount(DeviceId) by InitiatingProcessFileName
| sort by hosts asc
| take 200Detection Rules by Platform
CrowdStrike: Custom IOA
| IOA name | Rule type | Pattern | Exclusions | Promotes | Deployment path |
|---|---|---|---|---|---|
| fsquirt.exe launched by CrossWeb EX | Process Creation | Parent image name starts INISAFECrossWebEX; image fsquirt.exe | None | Promote Q1 | Detect from day one. Do not prevent: fsquirt.exe is a legitimate Windows binary and this rests on one vendor report. |
| Process or service from RasConv or DrvConh | Process Creation | Image path contains \RasConv\ or \DrvConh\, or command line ImeBroker.exe -TimeBroker | None | Promote Q3 | Detect. Raise to prevent only after a second independent source or a confirmed true positive in your environment. |
| mscoree.dll created outside system folders | File Creation | File name mscoree.dll; path not directly under System32, SysWOW64 or WinSxS | TrustedInstaller; your deployment agent | Promote Q5 | Detect. Legitimate .NET servicing can write elsewhere; tune for 14 days first. |
| Fsquirt or ImeBroker resolving GitHub | Network Connection | Image fsquirt.exe or ImeBroker.exe; remote name api.github.com or raw.githubusercontent.com | None | Promote Q8 | Detect. An IOA on a network connection by two binaries that never need GitHub is low noise. |
No rule is recommended at prevent. The pack rests on one vendor report and every pattern touches a legitimate Windows file name, so each IOA ships at detect.
SentinelOne: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| fsquirt.exe launched by CrossWeb EX | Q1, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Process or service from RasConv or DrvConh | Q3, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| mscoree.dll created outside system folders | Q5, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Fsquirt or ImeBroker resolving GitHub | Q8, 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 |
|---|---|---|---|
| fsquirt.exe launched by CrossWeb EX | Q1, 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 |
| Process or service from RasConv or DrvConh | 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 |
| mscoree.dll created outside system folders | Q5, 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 |
| Fsquirt or ImeBroker resolving GitHub | 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 |
Q2, Q4, Q6, Q7 and Q9 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
All 14 importable indicators ship at detect. Five of the seven hosts are compromised legitimate sites, so expect cleanup and shorter lifetimes. The hashes are MD5 only and single-source.
type,value,action,severity,expiration,description,tags md5,ec84d6cb2ae7974767aedac246b50a3e,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,a28cba214058fcae2883d8cffc883abd,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,c105d6b16f544582772de0159f24c00a,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,2f8475a90a25624ed02f1d18d4e6d65d,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,676fabe30a28b53925fba98e34b35986,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,b4a7eff35f048f06fb0a2d7631f23a7d,detect,high,2027-04-21,TouchShift mscoree.dll side-load payload,campaign:OperationFlashHole md5,ff07641dc56914dd90ee0bd7404d7ad7,detect,high,2027-04-21,ClientHub loader liblzma.dll,campaign:OperationFlashHole domain,javadevhouse.co.kr,detect,high,2027-04-21,Script host linked from GitHub Pages lure site,campaign:OperationFlashHole domain,pythonapischool.com,detect,high,2027-04-21,Script host linked from GitHub Pages lure site,campaign:OperationFlashHole domain,cubedesign.co.kr,detect,medium,2027-01-21,Cubridge C2 (compromised site),campaign:OperationFlashHole domain,fp-news.co.kr,detect,medium,2027-01-21,Cubridge C2 (compromised site),campaign:OperationFlashHole domain,k-wbc.co.kr,detect,medium,2027-01-21,ClientHub C2 (compromised site),campaign:OperationFlashHole domain,rcsh.co.kr,detect,medium,2027-01-21,ClientHub C2 (compromised site),campaign:OperationFlashHole domain,www.ksog.org,detect,medium,2027-01-21,ClientHub C2 (compromised site),campaign:OperationFlashHole # Hunt-only paths (not importable): see Section 4 and Q3/Q5. Auth token and ZipCrypto password are in the Securelist snapshot, not imported.
indicatorType,indicatorValue,action,title,description,expirationTime,severity,recommendedActions,rbacGroups,category,mitretechniques,GenerateAlert DomainName,javadevhouse.co.kr,Audit,Script host linked from GitHub Pages lure site,Script host linked from GitHub Pages lure site,2027-04-21T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,pythonapischool.com,Audit,Script host linked from GitHub Pages lure site,Script host linked from GitHub Pages lure site,2027-04-21T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,cubedesign.co.kr,Audit,Cubridge C2,Cubridge C2 (compromised site),2027-01-21T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,fp-news.co.kr,Audit,Cubridge C2,Cubridge C2 (compromised site),2027-01-21T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,k-wbc.co.kr,Audit,ClientHub C2,ClientHub C2 (compromised site),2027-01-21T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,rcsh.co.kr,Audit,ClientHub C2,ClientHub C2 (compromised site),2027-01-21T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True DomainName,www.ksog.org,Audit,ClientHub C2,ClientHub C2 (compromised site),2027-01-21T00: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. Left out because this block maps only SHA-1, SHA-256, IPv4, domain and URL indicators: md5 7. 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.
Parent INISAFECrossWebEXSvc.exe (INISAFE CrossWeb EX V3) starting fsquirt.exe Process image in C:\Windows\System32\RasConv\ or C:\Windows\System32\DrvConh\ ImeBroker.exe run with the argument -TimeBroker (the genuine ImeBroker.exe is in System32 itself) Service with description "Microsoft Service" whose ImagePath is outside svchost.exe mscoree.dll created in System32 subfolders or in ProgramData\RasConv, Apple, ssh, qorestor, Dell fsquirt.exe or ImeBroker.exe resolving api.github.com Non-browser client sending Sec-CH-UA and Sec-Fetch-* headers (ClientHub) or X-CSRF-Token with X-Requested-With (Cubridge) GitHub issue titled 1[ID] with body hel, later patched to hey (TechHub handshake)
TechHub - downloader using GitHub with a Personal Access Token (CLOUDBURST by Mandiant, NickelLoader by ESET) Cubridge - modular payload orchestrator (SIDESHOW by Mandiant, LightlessCan by ESET) TouchHub - installer that registers the ImeBroker.exe service TouchShift - DLL side-loaded as mscoree.dll, export LockClrVersion ClientHub - SNOW 1.0 payload loader, overlaps CookiePlus LPEClient - profiling and payload delivery, ML-KEM-1024 key exchange Cubridge modules and plugins: ActionModule.dll, FunctionModule.dll, ADFinder (AdFinder.dll), FileCollector (Dll.dll), browser stealer, process collector
[ ] Every host with INISAFE CrossWeb EX or other mandatory financial security software is inventoried with version [ ] CrossWeb EX is updated to the vendor's current release or removed where the sites you use no longer require it [ ] fsquirt.exe outbound is blocked by host firewall on hosts that do not use Bluetooth file transfer [ ] api.github.com and raw.githubusercontent.com are allowed only from developer and CI host groups at the proxy [ ] Links to *.github.io from first-time external senders are held or rewritten at the mail gateway [ ] Service creation is audited (Security 4697, System 7045) and forwarded [ ] Application control denies unsigned DLLs under ProgramData and System32 subfolders in audit mode first [ ] Staff targeted by résumé and portfolio lures (developers, network engineers, construction) have been briefed
Detection Validation Gates
| Gate | Check | Pass condition |
|---|---|---|
| Telemetry ready | Confirm every source feeds the SIEM: Process creation with command line, image path and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); Executable file written (CrowdStrike: PeFileWritten. SentinelOne: File Creation. Defender: DeviceFileEvents); DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents); service registry values (CrowdStrike: AsepValueUpdate. SentinelOne: Registry Value Modified. Defender: DeviceRegistryEvents); plus proxy and mail logs. | A sample event from each source is searchable in the last hour, and a test service creation appears as an ImagePath write. |
| Benign baseline | Run Q2, Q5, Q7 and Q9 over 14 to 30 days before alerting. Run Q1, Q3, Q4, Q6 and Q8 over 90 days. | Fewer than 10 hits per week per tuned query, each explained by a named process. Q1, Q3, Q4, Q6, Q8 return zero or a confirmed true positive. |
| Positive tests | On a lab host, start fsquirt.exe from a renamed copy of a test parent named INISAFECrossWebEXSvc.exe; create a dummy service with an ImagePath under C:\Windows\System32\RasConv; copy a benign DLL named mscoree.dll into C:\ProgramData\Apple. | Q1, Q3, Q4 and Q5 fire. Delete the test objects afterwards. |
| Promotion | Promote Q1, Q3, Q5, Q8 to Custom IOA at detect after the baseline. Import the Section 10 CSV at detect. | No prevent action without a second independent source or a confirmed incident. |
Hardening: Tiered & Deployable
- Inventory and patch CrossWeb EX and sibling security software. Securelist traced the chain to INISAFE CrossWeb EX V3 version 3.4.1.2 and says the abuse method is unknown, while the press release says a vulnerability may be involved. Update to the vendor's current release and remove the product where it is no longer required. Framework: MITRE M1051 (Update Software); ⚠ best-practice, no formal benchmark for this product. Verify: Playbook 1.
- Stop fsquirt.exe reaching the network. The Bluetooth file transfer wizard has no need to reach the internet, and it is the TechHub injection host. Block its outbound traffic on hosts that do not use Bluetooth transfer. Framework: MITRE M1037 (Filter Network Traffic); CIS Controls v8 safeguard 4.4 (host firewall). Verify: Playbook 2.
- Audit service creation. Persistence is a new service. Turn on Security 4697 and keep System 7045 forwarded so Q4 and N2 have a second source. Framework: MITRE M1047 (Audit); CIS Controls v8 safeguard 8.5. Verify: Playbook 3.
- Restrict GitHub API access to the hosts that need it. Allow api.github.com and raw.githubusercontent.com only for developer and CI groups at the proxy. Framework: MITRE M1037; NIST SP 800-53 SC-7. Verify: native hunt N4.
- Hold or rewrite GitHub Pages links from first-time external senders. Resume and portfolio lures are the delivery vector. Framework: MITRE M1031 (Network Intrusion Prevention), M1017 (User Training). Verify: native hunt N3.
- Application control in audit mode for DLLs in ProgramData and System32 subfolders. Side-loading depends on a writable folder holding a DLL. Framework: MITRE M1038 (Execution Prevention); Microsoft App Control for Business guidance.
- Retire mandatory kernel-adjacent browser security plugins. South Korea's plan to phase out mandatory installation of security software begins in 2026 (Securelist). Track the product retirement for each bank and government site your staff use. ⚠ best-practice, no formal benchmark.
- Default-deny egress for servers and non-developer endpoints. Framework: MITRE M1037; NIST SP 800-53 SC-7(5).
- Brief likely lure targets. Developers, network engineers and construction staff in Korea-facing roles. Framework: MITRE M1017.
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 · CrossWeb EX inventory (T1189; M1051)
Step 1.1 · Inventory CrossWeb EX and INISAFE products (read-only)
What it does: Lists installed INISAFE and CrossWeb products with versions and finds the service binary the report names.
Prerequisites: Local administrator or an endpoint management tool to run it fleet-wide.
Reboot required: No. These commands only read state.
Configuration
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object { $_.DisplayName -match 'INISAFE|CrossWeb' } | Select-Object DisplayName, DisplayVersion, InstallDate
Get-CimInstance Win32_Service | Where-Object { $_.PathName -match 'INISAFE' } | Select-Object Name, State, StartMode, PathNameVerify
# Expected: a list of hosts with the product. Compare each version to the vendor's current release.
Rollback
none required: read-only inventory.
Playbook 2 · Block fsquirt.exe outbound (T1055, T1102; M1037)
Step 2.1 · Add an outbound block rule for fsquirt.exe
What it does: Stops the TechHub injection host from reaching the internet. fsquirt.exe is the local Bluetooth file transfer wizard.
Prerequisites: Windows Defender Firewall enabled; a pilot group; confirm the group does not rely on internet-reachable Bluetooth transfer (it does not use IP).
Reboot required: No.
Configuration
New-NetFirewallRule -DisplayName 'HuntPack block fsquirt.exe outbound' -Direction Outbound -Action Block -Program "$env:SystemRoot\System32\fsquirt.exe" -Profile Any
Verify
Get-NetFirewallRule -DisplayName 'HuntPack block fsquirt.exe outbound' | Get-NetFirewallApplicationFilter | Select-Object Program # Expected: the System32 fsquirt.exe path
Rollback
Remove-NetFirewallRule -DisplayName 'HuntPack block fsquirt.exe outbound'
Playbook 3 · Service creation auditing (T1543.003; M1047)
Step 3.1 · Enable security system extension auditing
What it does: Records Security event 4697 when a service is installed, a second source for Q4 and N2.
Prerequisites: Administrator rights; log forwarding capacity for the extra events; Group Policy if you manage audit policy centrally, since a local setting may be overwritten.
Reboot required: No.
Configuration
auditpol /set /subcategory:"Security System Extension" /success:enable /failure:enable
Verify
auditpol /get /subcategory:"Security System Extension" # Expected: Success and Failure
Rollback
auditpol /set /subcategory:"Security System Extension" /success:disable /failure:disable
Playbook 4 · Compromise check (T1574.002, T1543.003; M1047)
Step 4.1 · Hash and locate TouchShift candidates (read-only)
What it does: Finds mscoree.dll outside the system folders and hashes it so it can be compared with the Section 10 MD5 list.
Prerequisites: Administrator rights; the Section 10 CSV.
Reboot required: No.
Configuration
Get-ChildItem -Path 'C:\ProgramData','C:\Windows\System32' -Filter mscoree.dll -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.DirectoryName -ne 'C:\Windows\System32' } |
ForEach-Object { [pscustomobject]@{ Path = $_.FullName; MD5 = (Get-FileHash -Algorithm MD5 -LiteralPath $_.FullName).Hash } }Verify
# Any result is an investigation lead. A match to a Section 10 MD5 is a confirmed hit.
Rollback
none required: read-only search.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Contain any host with a Q1, Q3, Q4, Q5 or Q6 hit, or a Q8 hit. Disable the account that was logged on. Block the Section 10 hosts at proxy and DNS. Treat the host as holding browser credentials and cloud tokens. | IR lead; network team | Falcon containment status; proxy block log |
| 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; proxy block log |
| Preserve | Capture memory first, because ClientHub, LPEClient and Cubridge run in memory. Image the disk, including the RasConv and DrvConh folders and ActivationStore.dat. Export proxy, DNS and Security 4697 and System 7045 logs. | IR lead; forensics | Memory and disk images; log exports; hashes |
| Scope | Run Q6 and Q7 across all hosts. Find every host with CrossWeb EX and run Q1, Q2. Search for ZipCrypto archives and screenshots staged for exfiltration. Look for other hosts the browser-stolen credentials could reach. | Threat hunter | Host list with timeline |
| Eradicate | Stop and delete the rogue service; remove the RasConv or DrvConh folder contents and any mscoree.dll beside a renamed binary; remove ActivationStore.dat and msadc.inc. Reset passwords and revoke sessions for every account used on the host, including browser-saved ones. Rebuild the host if a Cubridge module ran. | IR lead; IT operations | Removal record; credential reset log |
| Recover | Reinstall CrossWeb EX from the vendor's current release or remove it. Apply Playbooks 2 and 3. Watch Q1 to Q9 for 30 days. | IT operations | Patch and policy records |
| Share | Report the incident to the national CERT where required. GitHub accounts used for C2 can be reported to GitHub once identified. | IR lead; legal | Case reference |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | CrowdStrike coverage | SentinelOne | Defender XDR |
|---|---|---|---|---|---|---|
| T1566.002, T1189 | Lure site delivery | Q7 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike | |
| T1055, T1620 | fsquirt.exe injection under CrossWeb EX | Q1, Q2 | Q1 | Good | Good, with assumptions | Good, with assumptions |
| T1543.003, T1036.005 | ImeBroker service from RasConv or DrvConh | Q3, Q4 | Q3 | Good | Good, with assumptions | Good, with assumptions |
| T1574.002 | TouchShift and ClientHub loader DLL side-loading | Q5, Q6 | Q5 | Good | Good, with assumptions | Partial: Q6 unavailable |
| T1102.002, T1071.001 | GitHub API C2 by TechHub | Q8, Q9 | Q8 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike |
| T1001.003, T1573 | Cubridge and ClientHub encrypted C2 over compromised sites | Q7 | Partial | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike | |
| T1070.006 | Timestomping against monitor.sys | GAP | GAP | GAP | ||
| T1562.001 | LPEClient syscall hook removal | GAP | GAP | GAP | ||
| T1087.002, T1555.003, T1560.002 | In-memory discovery, browser credential theft, ZipCrypto staging | GAP | GAP | GAP |
Gaps: timestomping, in-memory defense evasion and the Cubridge and ClientHub plugins are outside endpoint telemetry for these queries. Validation gates are in Section 11.
Hunt Summary Ticket
TITLE: Operation FlashHole (Lazarus): CrossWeb EX abuse to TechHub, Cubridge and LPEClient
SEVERITY: High. Nation-state espionage against South Korean software, construction and
wired communication equipment organisations; Kaspersky GReAT disclosure dated 2026-10-21
SCOPE: Windows endpoints with CrossWeb EX or similar mandatory Korean security software;
process, file, DNS and service-registry telemetry; mail and proxy logs
HYPOTHESIS: A tailored GitHub Pages lure triggers CrossWeb EX to run fsquirt.exe with TechHub
shellcode. TechHub uses GitHub as C2 and installs TouchHub, which registers an
ImeBroker.exe service that side-loads TouchShift (mscoree.dll). ClientHub and LPEClient
then deliver Cubridge in memory.
QUERIES: 9 CQL queries (Q1-Q9) on Falcon sensor telemetry. Q1, Q3, Q5, Q8 promotable to Custom IOA at detect.
14 importable indicators (7 MD5, 7 domains) at detect.
DO FIRST: 1) Inventory CrossWeb EX hosts. 2) Run Q1, Q3, Q4, Q5, Q6, Q8 over 90 days.
3) Block fsquirt.exe outbound (Playbook 2). 4) Import the Section 10 CSV at detect.
FINDINGS: [fill in after the hunt]
GAPS: Mail and web lure delivery, timestomping and all in-memory Cubridge, ClientHub and
LPEClient activity are outside endpoint telemetry. Non-PE disk artifacts need the native check N1.
ACTIONS: Update or remove CrossWeb EX; restrict GitHub API egress; audit service creation;
app control in audit mode for side-loaded DLLs; brief likely lure targets.
OWNER: REPLACE_WITH_OWNER
VERSION: v0.1 (Draft) 2026-10-21Changelog
References
| Tier | Source | Used for | Access date |
|---|---|---|---|
| T1 | Kaspersky GReAT, Securelist: Dissecting Operation FlashHole, a complex attack by Lazarus (21 Oct 2026) | Technical analysis, file paths, hashes and C2 hosts | 2026-10-21 |
| T1 | Kaspersky: Kaspersky identifies new Lazarus APT campaign utilizing AI and post-quantum encryption (21 Oct 2026) | Victim sectors, timeline, AI lure content, ML-KEM-1024 context | 2026-10-21 |
| T3 | Mallory: Lazarus Targets South Korean Firms With Modular FlashHole Espionage Campaign | Derivative timeline cross-check only | 2026-10-21 |