TonRAT / "Photo-ZIP" Hospitality Campaign

Microsoft-reported multi-stage intrusion delivering a Node.js implant (TonRAT) with TON-blockchain C2 resolution — targeting hotels & hospitality across Europe and Asia.
Threat
TonRAT / Photo-ZIP
Severity
ACTIVE ITW
Type
Network / C2 · Node.js implant
Initial Access
Phishing · photo-ZIP / LNK
Version
v0.1 · 2026-06-27
Author
HuntPack
Confidence
High (vendor-attributed)
01

Executive Summary

Microsoft (2026-06-25) reported a campaign — active since April 2026 and not yet attributed to a known actor — that targets the hospitality sector (front-desk, reception, reservations staff at hotels) in Europe and Asia. The intrusion is themed around guest photos and complaints: victims download a photo-themed ZIP (photo-<random>.zip) that contains a fake image shortcut (IMG-*.png.lnk / PHOTO-*.png.lnk). Opening the LNK launches powershell.exe -ep bypass running an obfuscated BigInt-arithmetic decoder, which pulls a .ps1 to %TEMP%, drops a legitimate Node.js runtime into AppData\Local\Nodejs, and runs node.exe with a JavaScript implant tracked as TonRAT.

TonRAT's distinguishing trait is C2 resolution via the TON blockchain API — it reads attacker-controlled domains from on-chain records, then opens an encrypted WebSocket on non-standard ports (8443, 8445, 8453, 5555, 56001–56003). Persistence is dual: Run (Node.js component) and RunOnce (ProgramData EXE). The actor laundered sender authentication through abused Calendly + a Google share redirect chain so phishing passes SPF/DKIM/DMARC/CompAuth.

The strongest defensive angle is endpoint behavior: a signed-but-living-off-the-land chain (LNK → PowerShell → iwr → node.exe from a non-standard path) plus Run/RunOnce writes and a Defender exclusion add. Falcon EDR covers this well; this pack leans into process-lineage and registry CQL hunts rather than network signatures alone, because the blockchain-resolved C2 rotates.

Defender priority: Hunt for node.exe executing from C:\Users\*\AppData\Local\Nodejs\*.js with a domain argument — this is the implant launch and the single highest-fidelity signal in the chain. Pair it with the LNK→PowerShell→iwr ancestry hunt to catch the delivery stage.

02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry Fwd
1 · PrimaryMicrosoft Security Blog (2026-06-25)Full kill chain, TonRAT implant, TON-blockchain C2, dual persistence, IOCs (hashes, IPs, domains, ports), auth-laundering chain, lure languages/targets.Yes
2 · CorroboratingThe Hacker NewsIndependent write-up of the Microsoft report; confirms hospitality targeting, Node.js implant, Calendly/Google-share laundering.Partial

Hunter notes: Microsoft did not attribute the campaign to a named actor. Two waves are described: Wave 1 (IMG-*.png.lnk, fixed-IP C2, .info domains) and Wave 2 (PHOTO-*.png.lnk, Cloudflare-fronted photo-*.cfd, csc.exe→cvtres.exe compile-after-delivery). All IOCs in this pack trace to the Microsoft primary source. Blockchain-resolved C2 means domain/IP IOCs are perishable — prioritize behavioral hunts.

03

Hunt Brief & Attack Chain

Hunt hypotheses (high-fidelity first)

  1. H1 — Implant launch: node.exe runs from AppData\Local\Nodejs\*.js with a domain argument. CONF HIGH Covers T1059.007. Requires ProcessRollup2.
  2. H2 — LNK delivery: A .lnk spawns powershell.exe -ep bypass whose command line contains iwr/Invoke-WebRequest + -OutFile. CONF HIGH T1059.001 / T1204.002.
  3. H3 — PS1 drop to TEMP: PowerShell writes a randomly-named .ps1 into %TEMP%. CONF MED T1059.001 / T1105.
  4. H4 — Run/RunOnce persistence: Registry value write under ...\CurrentVersion\Run or RunOnce pointing at a Node.js component or a ProgramData\<random>\*.exe. CONF HIGH T1547.001.
  5. H5 — Defender exclusion abuse: Add-MpPreference -ExclusionProcess targeting a %TEMP%\<random>.exe. CONF HIGH T1562.001.
  6. H6 — Compile-after-delivery (Wave 2): csc.execvtres.exe producing a .dll, parented from the PowerShell/Node chain. CONF MED T1027.004.
  7. H7 — Non-standard-port C2 + geo lookup: Outbound to ports 8443/8445/8453/5555/56001–56003 or to ip-api.com, from node.exe / dropped EXE. CONF MED T1571 / T1016.
  8. H8 — Known-bad atomic IOCs: Listed SHA256 hashes, Wave-1 C2 IPs, and campaign domains. CONF HIGH (perishable for net IOCs).

Attack chain

#StepTelemetryHunt Angle
1Phishing (lure: guest complaint / bedbug / verification call) → browser downloads photo-*.zipMail gateway, proxy, FileCreateInfoZIP with photo-* name + LNK content; auth-laundering sender
2User opens IMG-*.png.lnk / PHOTO-*.png.lnk (1,989–2,079 B)ProcessRollup2LNK parent of powershell.exe — H2
3PowerShell -ep bypass BigInt decoder → iwr -OutFile %TEMP%\<rand>.ps1ProcessRollup2, FileCreateInfoCmdLine iwr+OutFile; ps1 write to TEMP — H2/H3
4Drop legit Node.js runtime to AppData\Local\Nodejs; run node.exe <rand>.js <domain>ProcessRollup2, PeFileWrittennode.exe from AppData + JS + domain arg — H1
5(Wave 2) csc.execvtres.exe compile .dllProcessRollup2Compiler chain off the implant — H6
6Persistence: Run (Node) + RunOnce (ProgramData EXE)RegGenericValueUpdateASEP value write — H4
7Evasion: Add-MpPreference -ExclusionProcess; Inno-Setup is-*.tmp /SL5 /VERYSILENTProcessRollup2Exclusion-add CmdLine — H5
8C2: resolve domains via TON blockchain API → encrypted WebSocket on non-standard ports; geo via ip-api.comNetworkConnectIP4, DnsRequestOdd ports / known IPs / ip-api.com — H7/H8
04

Consolidated IOC Table

Network IOCs are perishable — C2 is resolved on-chain and rotates; Wave-2 fronts behind Cloudflare. Treat IPs/domains as hunt/enrich, not permanent detect. All values below trace to the Microsoft primary source.

TypeValueConfActionContext
SHA25604ec44f2618460f5c77c5e56014a512cc03a123c9c5b6b6b1273e2a1681ac2e1highdetectPE xmnrwv9l.exe
SHA2569f10e3b6e5745784f26d18c38ce01fba054b19749c17260978ac11472564aee2highdetectLNK IMG-386443483.png.lnk (Wave 1)
SHA25697448688b292bfec6d83b153588076fe59b111c35ac4e42a916238df16a71e2fhighdetectLNK PHOTO-215746435.png.lnk (Wave 2)
SHA256c5baa0c16b0074a1e94b48aa0177e9bfc23746aca8a5b42848a6685da85658b5highdetectPS qFWe908J.ps1
SHA256b7f46b192cd83a1d2487cb048cca645f6e8855b9673d500d50bbdb04eebc6beahighdetectDLL bjygtujc.dll (Wave 2 compile)
SHA256d14ba95cdce1ef7dc9ad3ac74949ca5db38b27378ee30f30a23cf26f9e875a11medenrichLegit node-v24.13.0-win-x64 (~89.9 MB) — benign binary, hunt on PATH not hash
IP178.16.54.27highhuntWave 1 C2
IP95.217.97.121highhuntWave 1 C2
IP193.202.84.32highhuntWave 1 C2
IP178.16.55.179highhuntWave 1 C2
IP208.95.112.1medenrichip-api.com geolocation lookup (shared infra — context only)
Domainsafedocphoto[.]infohighhuntWave 1 C2 domain
Domainrecallnine[.]infohighhuntWave 1 C2 domain
Domainkentjerk[.]infohighhuntWave 1 C2 domain
Domainphotodoc-secure[.]infohighhuntWave 1 C2 domain
Domainsec-safe-dc[.]infohighhuntWave 1 C2 domain
Domainphoto-26254[.]cfdmedhuntWave 2 example (photo-<digits>.cfd, Cloudflare-fronted)
Domain patternphoto-<digits>[.]cfd · TLDs .cfd / .click / .bondmedhuntWave 2 C2 / Turnstile gate naming pattern
Ports8443, 8445, 8453, 5555, 56001, 56002, 56003medhuntEncrypted WebSocket C2 — non-standard
Auth-launderingem1618.calendly.com · "Booking Manager (via Calendly)"medenrichAbused Calendly sender; Google share redirect chain
05

Affected Surface & Telemetry Matrix

SurfaceRequired TelemetryPriorityGap Risk
Windows endpoints (front-desk / reception workstations)Falcon ProcessRollup2, RegGenericValueUpdate, PeFileWrittenCriticalLow — well covered by Falcon
PowerShell / script hostProcessRollup2 CommandLine; (native) PS ScriptBlock 4104HighMed — confirm ScriptBlock logging on
Outbound networkNetworkConnectIP4, DnsRequestMedMed — C2 rotates / Cloudflare-fronted
Email gateway (initial access)Mail gw logs; SPF/DKIM/DMARC/CompAuth verdictsMedHigh — laundered auth passes; not in Falcon
Microsoft Defender AV configExclusion change events / Add-MpPreference CmdLineHighLow
06

ATT&CK Mapping

TacticTechniqueObserved BehaviorQuery / Control
Initial AccessT1566.002 Phishing: Spearphishing LinkBrowser download of photo-*.zip via Calendly/Google-share chainMail gw hunt · S7
Initial AccessT1199 Trusted RelationshipAbused Calendly + Google share redirect to pass SPF/DKIM/DMARCMail gw hunt · S7
ExecutionT1059.001 PowerShellpowershell.exe -ep bypass BigInt decoder + iwr -OutFileQ2, Q3
ExecutionT1059.007 JavaScriptnode.exe runs JS implant (TonRAT) from AppDataQ1
ExecutionT1204.002 User Execution: Malicious FileUser opens *.png.lnkQ2
Defense EvasionT1027 Obfuscated Files / InformationBigInt-arithmetic PowerShell decoderQ2, Q3
Defense EvasionT1027.004 Compile After DeliveryWave 2 csc.execvtres.exe.dllQ6
Defense EvasionT1036 MasqueradingLNK named *.png.lnk; legit Node.js runtime abusedQ1, Q2
Defense EvasionT1562.001 Impair Defenses: Disable/Modify ToolsAdd-MpPreference -ExclusionProcessQ5
PersistenceT1547.001 Registry Run Keys / Startup FolderRun (Node) + RunOnce (ProgramData EXE)Q4
DiscoveryT1016 System Network Configuration DiscoveryGeolocation via ip-api.comQ7
Command & ControlT1571 Non-Standard PortEncrypted WebSocket on 8443/8445/8453/5555/56001-56003Q7
07

Native Audit-Log Hunts (non-CQL)

Email gateway / M365

  • Hunt inbound mail from *.calendly.com senders with display name containing Booking Manager / (via Calendly) to reception/reservations mailboxes — especially where the body links into a share.google/google.com/share_google redirect chain.
  • Flag links resolving to photo-*.cfd / *.click / *.bond or a Cloudflare Turnstile gate. Note: these pass SPF/DKIM/DMARC/CompAuth — do not rely on auth verdicts alone.
  • Target accounts to watch (lure recipients): reception, frontdesk, recepcja, recepce, accueil. Lure languages: Japanese, Danish, Dutch.

Windows PowerShell logging (Event ID 4104 ScriptBlock)

  • Search ScriptBlock text for BigInt arithmetic patterns and Invoke-WebRequest/iwr with -OutFile writing to $env:TEMP.
  • Confirm ScriptBlock logging (GPO: Turn on PowerShell Script Block Logging) is enabled fleet-wide — front-desk images often miss it.

Microsoft Defender

  • Review Defender exclusion change events (Operational log) for newly added -ExclusionProcess entries pointing at %TEMP% EXEs.
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
Q1 · node.exe implant launch from AppData\Local\Nodejs
CONF HIGHFP LOWCOST LOW

Looks for: the TonRAT launch — node.exe executing a .js from AppData\Local\Nodejs. Highest-fidelity signal in the chain.

// HUNT: TonRAT node.exe implant launch from AppData\Local\Nodejs
// MITRE: T1059.007, T1036 | CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ImageFileName=/\\node\.exe$/i
| CommandLine=/AppData\\Local\\Nodejs\\/i
| CommandLine=/\.js/i
| table([ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData, ProcessStartTime], limit=200)
Q2 · LNK spawns powershell.exe -ep bypass with iwr
CONF HIGHFP LOWCOST LOW

Looks for: the delivery stage — PowerShell launched with -ep bypass whose command line downloads via iwr/Invoke-WebRequest. Pair with Q1.

// HUNT: PowerShell -ep bypass running Invoke-WebRequest (Photo-ZIP delivery)
// MITRE: T1059.001, T1204.002, T1027 | CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ImageFileName=/\\powershell\.exe$/i
| CommandLine=/-ep\s+bypass|-executionpolicy\s+bypass/i
| CommandLine=/iwr|invoke-webrequest/i
| CommandLine=/-outfile/i
| table([ComputerName, UserName, ParentBaseFileName, CommandLine, SHA256HashData, ProcessStartTime], limit=200)
Q3 · PowerShell writes a .ps1 into %TEMP%
CONF HIGHFP MEDCOST LOW

Looks for: the second-stage drop — a .ps1 file written into the user TEMP path by a PowerShell process. FP: admin/automation scripts legitimately stage .ps1 in TEMP; scope to interactive front-desk hosts and correlate with Q2 ancestry.

// HUNT: .ps1 written to %TEMP% (random-named second stage)
// MITRE: T1059.001, T1105 | CONF: high  FP: med  COST: low | REQUIRES: FileCreateInfo
// TUNING: exclude known admin tooling paths / signed deployment agents writing to TEMP
#event_simpleName=/PeFileWritten|NewExecutableWritten/
| TargetFileName=/\\(Local|Temp)\\Temp\\[A-Za-z0-9]{4,12}\.ps1$/i
| ContextBaseFileName=/powershell\.exe/i
| table([ComputerName, UserName, ContextBaseFileName, TargetFileName, Timestamp], limit=200)
Q4 · Run / RunOnce persistence write (Node + ProgramData EXE)
CONF HIGHFP MEDCOST LOW

Looks for: dual ASEP persistence — a Run/RunOnce value whose data points at AppData\Local\Nodejs or a ProgramData\<random>\*.exe. FP: legitimate installers write Run keys; constrain on the Node/ProgramData data pattern below and triage by value data, not just key path.

// HUNT: Run/RunOnce persistence to Nodejs component or ProgramData EXE
// MITRE: T1547.001 | CONF: high  FP: med  COST: low | REQUIRES: RegGenericValueUpdate
// TUNING: exclude vendor software Run-key writes; keep only Nodejs / ProgramData payload data
#event_simpleName=/RegGenericValueUpdate|AsepValueUpdate/
| RegObjectName=/\\CurrentVersion\\Run(Once)?$/i
| RegStringValue=/AppData\\Local\\Nodejs\\|ProgramData\\[^\\]+\\[^\\]+\.exe/i
| table([ComputerName, UserName, RegObjectName, RegValueName, RegStringValue], limit=200)
Q5 · Add-MpPreference Defender exclusion on a TEMP EXE
CONF HIGHFP LOWCOST LOW

Looks for: defense evasion — Add-MpPreference -ExclusionProcess targeting a randomly-named EXE in %TEMP%.

// HUNT: Add-MpPreference exclusion on a %TEMP% executable
// MITRE: T1562.001 | CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| CommandLine=/Add-MpPreference/i
| CommandLine=/-ExclusionProcess|-ExclusionPath/i
| CommandLine=/\\Temp\\[A-Za-z0-9]{4,16}\.exe/i
| table([ComputerName, UserName, ImageFileName, ParentBaseFileName, CommandLine, ProcessStartTime], limit=200)
Q6 · csc.exe → cvtres.exe compile-after-delivery (Wave 2)
CONF MEDFP MEDCOST LOW

Looks for: Wave-2 in-place compilation — cvtres.exe spawned by csc.exe (the .NET compiler chain producing a .dll). FP: legit .NET build/dev tooling and some installers invoke csc/cvtres; scope to front-desk hosts and correlate with the PowerShell/Node ancestry from Q1/Q2.

// HUNT: csc.exe -> cvtres.exe compile chain (Wave 2 DLL build)
// MITRE: T1027.004 | CONF: med  FP: med  COST: low | REQUIRES: ProcessRollup2
// TUNING: exclude developer workstations / known build agents; alert on reception/front-desk images
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ImageFileName=/\\cvtres\.exe$/i
| ParentBaseFileName=/csc\.exe/i
| table([ComputerName, UserName, ImageFileName, ParentBaseFileName, CommandLine, ProcessStartTime], limit=200)
Q7 · Non-standard-port C2 + ip-api.com geo lookup
CONF MEDFP MEDCOST MED

Looks for: the encrypted-WebSocket C2 on the campaign's non-standard ports, plus the ip-api.com geolocation IP. FP: 8443 is a common alt-HTTPS port and 5555 sees ADB/dev traffic; constrain by initiating process (node.exe / dropped EXE) and treat the rarer ports (8445/8453/56001-56003) as higher-signal.

// HUNT: TonRAT non-standard-port C2 and ip-api.com geolocation
// MITRE: T1571, T1016 | CONF: med  FP: med  COST: med | REQUIRES: NetworkConnectIP4
// TUNING: scope RemotePort to node.exe / dropped-EXE initiators; exclude known internal services on 8443
#event_simpleName=NetworkConnectIP4
| (RemotePort=8443 or RemotePort=8445 or RemotePort=8453 or RemotePort=5555 or RemotePort=56001 or RemotePort=56002 or RemotePort=56003 or RemoteAddressIP4=/^208\.95\.112\.1$/)
| ContextBaseFileName=/node\.exe|\.exe$/i
| table([ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort, Timestamp], limit=200)
Q8 · Known-bad atomic IOCs (hashes · Wave-1 C2 IPs · domains)
CONF HIGHFP LOWCOST LOW

Looks for: any execution/connection matching the published SHA256 hashes, Wave-1 C2 IPs, or campaign DNS. Net IOCs are perishable (on-chain rotation) — run as a hunt, not a standing block.

// HUNT: TonRAT atomic IOC sweep (hashes / Wave-1 IPs / domains)
// MITRE: multiple | CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2, NetworkConnectIP4, DnsRequest
#event_simpleName=/ProcessRollup2|NetworkConnectIP4|DnsRequest/
| SHA256HashData=/^(04ec44f2618460f5c77c5e56014a512cc03a123c9c5b6b6b1273e2a1681ac2e1|9f10e3b6e5745784f26d18c38ce01fba054b19749c17260978ac11472564aee2|97448688b292bfec6d83b153588076fe59b111c35ac4e42a916238df16a71e2f|c5baa0c16b0074a1e94b48aa0177e9bfc23746aca8a5b42848a6685da85658b5|b7f46b192cd83a1d2487cb048cca645f6e8855b9673d500d50bbdb04eebc6bea)$/i
   OR RemoteAddressIP4=/^(178\.16\.54\.27|95\.217\.97\.121|193\.202\.84\.32|178\.16\.55\.179)$/
   OR DomainName=/(safedocphoto|recallnine|kentjerk|photodoc-secure|sec-safe-dc)\.info$/i
| table([ComputerName, ImageFileName, SHA256HashData, RemoteAddressIP4, DomainName, Timestamp], limit=max)
09

CrowdStrike Custom IOA Recommendations

IOA namePatternExclusionsAction
TonRAT — Node implant from AppDataProcess node.exe; CommandLine matches AppData\\Local\\Nodejs\\.*\.jsNone expected — legit Node installs to Program Files / nvm, not user AppData\Local\NodejsDetect → Block
Photo-ZIP — LNK→PS downloadParent *.lnk; child powershell.exe; CmdLine -ep bypass + iwr/-OutFileAllowlist signed admin LNK launchers if anyDetect → Block
Defender exclusion on TEMP EXEAdd-MpPreference + -ExclusionProcess + \Temp\*.exeExclude approved security/IT automationDetect
Node→ProgramData persistenceRun/RunOnce value data referencing Nodejs or ProgramData\<rand>\*.exeExclude vendor installer value namesDetect

Promotion path: Q1 and Q2 are the strongest IOA candidates (low FP, attacker-specific path/lineage). Deploy in Detect on a pilot ring of front-desk hosts, confirm zero benign hits over a baseline window, then escalate Q1 to Block.

10

Machine-Readable IOC Appendix

Grouped quick-copy blocks for direct ingestion / triage. Network IOCs are perishable — set short expirations and prefer detect on hashes, hunt on net infra.

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
sha256,04ec44f2618460f5c77c5e56014a512cc03a123c9c5b6b6b1273e2a1681ac2e1,prevent,critical,2026-12-27,TonRAT PE xmnrwv9l.exe,campaign:TonRAT-PhotoZIP
sha256,9f10e3b6e5745784f26d18c38ce01fba054b19749c17260978ac11472564aee2,prevent,critical,2026-12-27,TonRAT LNK Wave1,campaign:TonRAT-PhotoZIP
sha256,97448688b292bfec6d83b153588076fe59b111c35ac4e42a916238df16a71e2f,prevent,critical,2026-12-27,TonRAT LNK Wave2,campaign:TonRAT-PhotoZIP
sha256,c5baa0c16b0074a1e94b48aa0177e9bfc23746aca8a5b42848a6685da85658b5,prevent,critical,2026-12-27,TonRAT PS qFWe908J.ps1,campaign:TonRAT-PhotoZIP
sha256,b7f46b192cd83a1d2487cb048cca645f6e8855b9673d500d50bbdb04eebc6bea,prevent,critical,2026-12-27,TonRAT DLL bjygtujc.dll,campaign:TonRAT-PhotoZIP
ipv4,178.16.54.27,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
ipv4,95.217.97.121,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
ipv4,193.202.84.32,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
ipv4,178.16.55.179,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
domain,safedocphoto.info,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
domain,recallnine.info,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
domain,kentjerk.info,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
domain,photodoc-secure.info,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
domain,sec-safe-dc.info,detect,high,2026-09-27,TonRAT Wave1 C2,campaign:TonRAT-PhotoZIP
Behavioral Signatureshunt logic
node.exe executing *.js from C:\Users\*\AppData\Local\Nodejs\ + domain arg
*.png.lnk (1989-2079 bytes) -> powershell.exe -ep bypass -> iwr -OutFile %TEMP%\*.ps1
Run/RunOnce value data referencing Nodejs OR C:\ProgramData\<random>\*.exe
Add-MpPreference -ExclusionProcess %TEMP%\<random>.exe
csc.exe -> cvtres.exe compiling a .dll on a non-developer host (Wave 2)
Inno-Setup is-*.tmp installer launched with /SL5 /VERYSILENT
Outbound encrypted WebSocket to ports 8443/8445/8453/5555/56001-56003
Named Tooling / Patternsenrichment
Implant: TonRAT (Node.js / JavaScript; TON-blockchain C2 resolution)
Legit runtime abused: node-v24.13.0-win-x64 (sha256 d14ba95cdce1ef7dc9ad3ac74949ca5db38b27378ee30f30a23cf26f9e875a11)
Wave 2 C2 pattern: photo-<digits>.cfd  (TLDs .cfd / .click / .bond; Cloudflare-fronted; Turnstile gate)
Geo lookup: ip-api.com (208.95.112.1)
Auth laundering: em1618.calendly.com / "Booking Manager (via Calendly)"
  redirect chain: calendly.com/url?q= -> share.google/TOKEN -> www.google.com/share_google -> photo-*.cfd
Lure recipients: reception, frontdesk, recepcja, recepce, accueil (JP/DA/NL lures)
Mail / ASR Audit Checklistprevention audit
[ ] ASR: Block executable content from email client and webmail (BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550)
[ ] ASR: Block JavaScript/VBScript from launching downloaded executable content (D3E037E1-3EB8-44C8-A917-57927947596D)
[ ] ASR: Block process creations originating from PSExec and WMI commands
[ ] Block/quarantine inbound .lnk and double-extension *.png.lnk at mail gateway
[ ] Mark-of-the-Web enforced; SmartScreen on for downloaded archives
[ ] PowerShell Script Block Logging (4104) enabled on front-desk images
[ ] Tamper Protection ON so Add-MpPreference exclusions cannot be silently added
[ ] Flag inbound *.calendly.com senders with "Booking Manager (via Calendly)" display names
11

Detection Validation Gates

GateCheckPass criteria
Telemetry readyConfirm ProcessRollup2, RegGenericValueUpdate, NetworkConnectIP4 flowing from front-desk hostsEvents present in last 24h on target host group
Benign baselineRun Q3, Q4, Q6, Q7 over 7-day window pre-deployCatalogue benign hits; build TUNING exclusions before alerting
Positive testIn a lab: drop node.exe to AppData\Local\Nodejs and run a benign .js + domain argQ1 fires; field projection populated
Field validationConfirm RegStringValue / ContextBaseFileName populate as expected in tenantNon-empty values in Q4/Q3 results
PromotionQ1/Q2 zero benign hits over baseline windowPromote to Custom IOA (Detect → Block)
12

Hardening — Tiered

Immediate (this week — no compatibility risk)
  • Enable ASR "Block executable content from email client and webmail" (GUID BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550) and "Block JS/VBScript from launching downloaded executable content" (D3E037E1-3EB8-44C8-A917-57927947596D). MITRE M1042. Kills the LNK→PowerShell→download path at the source.
  • Block .lnk and double-extension *.png.lnk attachments / downloads at the mail gateway and via web filtering. MITRE M1021 / M1049.
  • Enable Defender Tamper Protection so Add-MpPreference -ExclusionProcess cannot silently whitelist the payload. MITRE M1054.
  • Enforce Mark-of-the-Web + SmartScreen on downloaded archives so the ZIP/LNK trips a warning. MITRE M1017.
Near term (1–4 weeks — pilot on a ring first)
  • WDAC / AppLocker: deny user-writable execution of node.exe from %LOCALAPPDATA% and block unsigned EXEs under C:\ProgramData\. MITRE M1038. Front-desk images rarely need a user-path Node runtime.
  • PowerShell Script Block Logging (4104) + Constrained Language Mode on reception/reservations images. MITRE M1042 / M1049.
  • Mail auth-laundering rule: flag/quarantine inbound *.calendly.com senders with "Booking Manager (via Calendly)" display names linking through share.google redirects, since SPF/DKIM/DMARC pass. MITRE M1054.
Strategic (1–3 months — architectural)
  • Application allowlisting (WDAC enforced mode) on the hospitality fleet — front-desk endpoints run a fixed app set and are an ideal allowlisting candidate. MITRE M1038.
  • Egress filtering / proxy enforcement blocking direct outbound on non-standard ports (8443/8445/8453/5555/56001-56003) from workstation segments. MITRE M1037.
  • Phishing-resistant MFA + conditional access for reception/reservations identities to limit post-compromise lateral value. MITRE M1032.
13

Deployable Playbooks

1 · Enable the two key ASR rules (Defender, Block mode)

Add-MpPreference -AttackSurfaceReductionRules_Ids BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 -AttackSurfaceReductionRules_Actions Enabled
Add-MpPreference -AttackSurfaceReductionRules_Ids D3E037E1-3EB8-44C8-A917-57927947596D -AttackSurfaceReductionRules_Actions Enabled
# Verify:
(Get-MpPreference).AttackSurfaceReductionRules_Ids
(Get-MpPreference).AttackSurfaceReductionRules_Actions

2 · Enforce Tamper Protection + Script Block Logging (GPO/registry)

# Tamper Protection (managed via Intune/MDE; registry readout to verify):
Get-MpComputerStatus | Select-Object IsTamperProtected
# PowerShell Script Block Logging:
$rk = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
New-Item -Path $rk -Force | Out-Null
Set-ItemProperty -Path $rk -Name EnableScriptBlockLogging -Value 1 -Type DWord
# Verify:
Get-ItemProperty -Path $rk -Name EnableScriptBlockLogging

3 · WDAC/AppLocker — deny node.exe from user AppData (AppLocker EXE rule, deny)

# Audit first, then enforce. Deny rule path condition (AppLocker):
#   %LOCALAPPDATA%\Nodejs\*    and    %OSDRIVE%\ProgramData\*\*.exe
# Set the AppLocker EXE collection to Enabled and add a DENY rule for the paths above.
# Spot-check current effective mode:
Get-AppLockerPolicy -Effective -Xml | Select-String "Exe"

4 · Post-deploy CQL spot-check (behavior gone)

// Confirm no node.exe launching from AppData\Local\Nodejs after enforcement
#event_simpleName=ProcessRollup2
| ImageFileName=/\\node\.exe$/i
| CommandLine=/AppData\\Local\\Nodejs\\/i
| groupBy([ComputerName], function=count())
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateFalcon network-contain any host hit by Q1/Q8. Block Wave-1 C2 IPs/domains at egress. Disable involved reception account sessions.SOC / IRQ1, Q8 detections; host AID
EradicateRemove AppData\Local\Nodejs\*.js + dropped Node runtime; delete ProgramData\<rand>\*.exe; remove Run/RunOnce values; remove any Add-MpPreference exclusion; delete staged %TEMP%\*.ps1.IR / EndpointQ3, Q4, Q5 results
RecoverRe-enable Defender exclusions baseline + Tamper Protection; rotate credentials for the affected reception identities; restore from known-good if persistence depth unclear.Endpoint / IAMClean re-scan; Q1 returns zero
LessonsPush the mail auth-laundering rule fleet-wide; brief front-desk staff on photo-ZIP / Calendly lure; deploy ASR + WDAC tiers from S12.SecEngCoverage map closed
15

Detection Coverage Map

TechniqueBehaviorCQLIOACoverage
T1059.007node.exe implant launch from AppDataQ1YesGood
T1059.001 / T1204.002LNK→PowerShell→iwr deliveryQ2YesGood
T1105 / T1059.001.ps1 dropped to %TEMP%Q3Partial
T1547.001Run / RunOnce persistenceQ4YesGood
T1562.001Defender exclusion on TEMP EXEQ5YesGood
T1027.004csc.exe→cvtres.exe compile (Wave 2)Q6Partial
T1571 / T1016Non-standard-port C2 + ip-api geoQ7Partial
multipleAtomic hash / IP / domain IOCsQ8Good
T1566.002 / T1199Phishing via Calendly/Google-share launderingGap

Known gap: the initial-access / auth-laundering stage (T1566.002, T1199) is not covered by Falcon EDR — it lives in mail-gateway / M365 telemetry. Cover it with the Native Audit-Log Hunts (S7) and the mail rule in S12, not CQL. Validation gates (S11) must pass — confirm telemetry, baseline Q3/Q4/Q6/Q7, and promote Q1/Q2 only after a clean baseline window.

16

Hunt Summary Ticket

TITLE:      TonRAT / Photo-ZIP Hospitality Campaign — Node.js implant hunt
SEVERITY:   HIGH (active in-the-wild; vendor-attributed; not yet actor-named)
SCOPE:      Windows endpoints — hotel/hospitality front-desk, reception, reservations
HYPOTHESIS: A photo-ZIP/LNK lure ran PowerShell -ep bypass, dropped a Node.js runtime to
            AppData\Local\Nodejs, and launched the TonRAT implant with TON-blockchain C2.
QUERIES:    Q1 node.exe@AppData (primary) · Q2 LNK->PS->iwr · Q3 ps1@TEMP · Q4 Run/RunOnce ·
            Q5 MpPreference exclusion · Q6 csc->cvtres · Q7 non-std-port C2 · Q8 atomic IOCs
DO FIRST:   Run Q1 and Q8 across all front-desk host groups (7d). Triage hits with Q2 ancestry.
FINDINGS:   <fill: hosts / users / C2 reached / persistence present>
GAPS:       Initial-access auth-laundering (T1566.002/T1199) not in EDR — see Native Hunts (S7).
ACTIONS:    Isolate hits, eradicate per S14, deploy ASR+Tamper Protection (S12 Immediate).
OWNER:      HuntPack
VERSION:    v0.1 · 2026-06-27
17

Changelog

v0.32026-07-24CQL correctness pass. All table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.
v0.22026-06-29CQL syntax review (crowdstrike-logscale-v3): removed invalid FileCreateInfo (Q3); replaced regex-on-numeric RemotePort with numeric alternation (Q7).
v0.12026-06-27Initial HuntPack — 8 CQL hunts, 4 Custom IOA recs, tiered hardening + playbooks, containment runbook. All IOCs traced to the Microsoft (2026-06-25) primary source; no fabricated indicators. Draft.
18

References

TierSourceUsed ForAccess Date
1 · PrimaryMicrosoft Security Blog — Photo-ZIP campaign delivers Node.js implant (2026-06-25)Full kill chain, TonRAT, TON-blockchain C2, all IOCs, persistence, auth-laundering, lures, MITRE2026-06-27
2 · CorroboratingThe Hacker News — Microsoft warns of Photo-ZIP phishingIndependent corroboration of targeting, implant, laundering chain2026-06-27
RefMITRE ATT&CKTechnique IDs & mitigations (M1038/M1042/M1037/M1054)2026-06-27