# =============================================================================
# ThreatHunter.ai Detection Pack v3
# Stryker / Handala / MuddyWater / MOIS — Unified
# Author: James McMurry, ThreatHunter.ai
# Version: 3.0
# Date: 2026-04-16
# Coverage: Full kill chain from MuddyWater pre-positioning through
#           Handala detonation, including the Intune MDM wipe vector
#           and the historical wiper toolchain.
# =============================================================================
#
# 25 detection rules. Sigma format where applicable; KQL and SPL provided
# as inline queries for rules that target cloud-only telemetry (Entra ID,
# Intune audit logs, Defender tables).
#
# Deploy all rules as scheduled analytics with a 24-hour evaluation window.
# If any one fires, assume the second team is already inside.
# =============================================================================

---
# ---------------------------------------------------------------------------
# RULE 1 — Intune Bulk Destructive Action Threshold
# The Stryker kill shot: 200K devices wiped via Intune in five hours.
# Fires when 5+ Wipe/Retire/Delete from one identity in 15 minutes.
# ---------------------------------------------------------------------------
title: Intune Bulk Destructive Action Threshold
id: th-v3-001
status: stable
description: >
  Detects burst of 5 or more Intune Wipe, Retire, or Delete device actions
  from a single identity within a 15-minute window. This is the exact pattern
  used in the March 11, 2026 Stryker attack.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://www.threathunter.ai/blog/iran-handala-stryker-detection-pack-v2/
tags:
  - attack.impact
  - attack.t1485
  - attack.t1072
level: critical
logsource:
  product: azure
  service: auditlogs
detection:
  note: >
    This rule targets Microsoft Sentinel / Defender XDR. No native Sigma
    log source exists for Intune audit logs. Deploy the KQL below as a
    Sentinel Scheduled Analytics Rule.
kql: |
  AuditLogs
  | where LoggedByService == "Intune"
  | where OperationName in ("Wipe", "Retire", "Delete device")
  | summarize DeviceCount = dcount(TargetResources[0].displayName),
              Actions = make_set(OperationName)
              by InitiatedBy = tostring(InitiatedBy.user.userPrincipalName),
                 bin(TimeGenerated, 15m)
  | where DeviceCount >= 5
tuning: >
  Lower threshold to 3 for orgs with fewer than 500 enrolled devices.

---
# ---------------------------------------------------------------------------
# RULE 2 — Intune Destructive Action Outside Business Hours
# Stryker wipe fired at 03:30 EDT.
# ---------------------------------------------------------------------------
title: Intune Destructive Action Outside Business Hours
id: th-v3-002
status: stable
description: >
  Detects Intune Wipe or Retire actions occurring outside 06:00-20:00.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.impact
  - attack.t1485
level: high
logsource:
  product: azure
  service: auditlogs
kql: |
  AuditLogs
  | where LoggedByService == "Intune"
  | where OperationName in ("Wipe", "Retire")
  | extend Hour = datetime_part("Hour", TimeGenerated)
  | where Hour < 6 or Hour > 20

---
# ---------------------------------------------------------------------------
# RULE 3 — PIM Activation Without Fresh Authentication
# The gap: PIM checkbox accepts stale MFA claims on hijacked session tokens.
# ---------------------------------------------------------------------------
title: PIM Activation Without Fresh Phishing-Resistant MFA
id: th-v3-003
status: stable
description: >
  Detects activation of high-privilege Entra ID PIM roles where the backing
  sign-in did not satisfy FIDO2, Windows Hello for Business, or certificate-
  based authentication. Covers the PIM Authentication Context gap exploited
  at Stryker.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://www.threathunter.ai/blog/iran-stryker-setup-already-in-your-logs/
tags:
  - attack.privilege_escalation
  - attack.t1078
  - attack.t1621
level: critical
logsource:
  product: azure
  service: auditlogs
kql: |
  let PrivRoles = dynamic([
    "Global Administrator","Intune Administrator","Cloud Device Administrator",
    "Privileged Role Administrator","Security Administrator",
    "Exchange Administrator","Authentication Administrator"]);
  AuditLogs
  | where OperationName == "Add member to role completed (PIM activation)"
  | extend Role = tostring(TargetResources[0].displayName)
  | where Role in (PrivRoles)
  | join kind=leftouter (
      SigninLogs
      | project CorrelationId,
               AuthMethodsUsed = tostring(AuthenticationDetails),
               AuthenticationRequirement, UserPrincipalName,
               SignInTime = TimeGenerated
  ) on $left.CorrelationId == $right.CorrelationId
  | where AuthMethodsUsed !has "FIDO2"
      and AuthMethodsUsed !has "X509"
      and AuthMethodsUsed !has "WindowsHelloForBusiness"
remediation: >
  Create a named Authentication Context in Entra ID. Build a Conditional
  Access policy requiring phishing-resistant MFA bound to that context.
  Bind PIM role settings for each sensitive role to the context.

---
# ---------------------------------------------------------------------------
# RULE 4 — Stale Session Token on Privileged Operation
# MFA claim older than 8 hours backing a destructive action.
# ---------------------------------------------------------------------------
title: Stale Session Token on Privileged Operation
id: th-v3-004
status: stable
description: >
  Flags privileged operations (Intune wipe, PIM activation, app consent)
  where the backing MFA claim was satisfied more than 8 hours prior.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.privilege_escalation
  - attack.t1078
  - attack.t1550
level: critical
logsource:
  product: azure
  service: auditlogs
kql: |
  let PrivOps = dynamic([
    "Wipe","Retire",
    "Add member to role completed (PIM activation)",
    "Update application","Consent to application"]);
  AuditLogs
  | where OperationName in (PrivOps)
  | join kind=inner (
      SigninLogs
      | extend MfaTime = TimeGenerated
      | project MfaTime, CorrelationId, UserPrincipalName
  ) on CorrelationId
  | where datetime_diff("hour", TimeGenerated, MfaTime) >= 8

---
# ---------------------------------------------------------------------------
# RULE 5 — Sign-In to Admin Role from Iran or Starlink ASN
# ---------------------------------------------------------------------------
title: Admin Sign-In from Iranian or Starlink ASN
id: th-v3-005
status: stable
description: >
  Detects sign-ins to admin-facing Microsoft portals from Iranian ASNs or
  SpaceX Starlink (AS14593), both observed in the pre-Stryker activity.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.initial_access
  - attack.t1078
level: high
logsource:
  product: azure
  service: signinlogs
kql: |
  let RiskyASNs = dynamic([
    "AS14593","AS57724","AS44244","AS58224","AS48159",
    "AS31549","AS50810","AS12880"]);
  SigninLogs
  | where tostring(AutonomousSystemNumber) has_any (RiskyASNs)
  | where AppDisplayName has_any (
      "Microsoft Intune","Microsoft Graph",
      "Azure Portal","Microsoft Admin Portals")

---
# ---------------------------------------------------------------------------
# RULE 6 — Rclone Exfiltration to MOIS Cloud Sinks
# ---------------------------------------------------------------------------
title: Rclone Exfiltration to MOIS Cloud Sinks
id: th-v3-006
status: experimental
description: >
  Detects Rclone execution with command-line arguments pointing to Wasabi,
  Backblaze B2, or Put.io, all confirmed MuddyWater exfil destinations.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://www.security.com/threat-intelligence/iran-cyber-threat-activity-us
tags:
  - attack.exfiltration
  - attack.t1567.002
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel_proc:
    Image|endswith: '\rclone.exe'
  sel_target:
    CommandLine|contains:
      - 'wasabisys.com'
      - 'backblazeb2.com'
      - 'b2.backblaze.com'
      - 'put.io'
      - 'wasabi:'
      - 'elvenforest'
      - 'gitempire'
  condition: sel_proc and sel_target
kql: |
  DeviceProcessEvents
  | where FileName =~ "rclone.exe"
  | where ProcessCommandLine has_any (
      "wasabisys.com","backblazeb2.com","b2.backblaze.com",
      "put.io","wasabi:","elvenforest","gitempire")
spl: |
  index=* process_name=rclone.exe
    (CommandLine="*wasabisys*" OR CommandLine="*backblazeb2*"
     OR CommandLine="*put.io*" OR CommandLine="*wasabi:*"
     OR CommandLine="*elvenforest*" OR CommandLine="*gitempire*")
  | stats count by dest, user, CommandLine

---
# ---------------------------------------------------------------------------
# RULE 7 — Dindoor Backdoor via Deno Runtime
# Deno has no business in most enterprise environments.
# ---------------------------------------------------------------------------
title: Dindoor Backdoor via Deno Runtime
id: th-v3-007
status: experimental
description: >
  Detects execution of the Deno JavaScript/TypeScript runtime with permissive
  flags, or known Dindoor sample hashes. MuddyWater's Dindoor backdoor runs
  exclusively on Deno. If Deno is not expected in your environment, any
  execution is worth investigating.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://thehackernews.com/2026/03/iran-linked-muddywater-hackers-target.html
tags:
  - attack.execution
  - attack.t1059.007
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel_deno:
    Image|endswith: '\deno.exe'
  sel_args:
    CommandLine|contains:
      - '--allow-net'
      - '--allow-run'
      - '--allow-read'
      - '--allow-write'
  sel_hash:
    Hashes|contains:
      - 'c7cf1575336e78946f4fe4b0e7416b6ebe6813a1a040c54fb6ad82e72673478e'
      - '0f9cf1cf8d641562053ce533aaa413754db88e60404cab6bbaa11f2b2491d542'
      - '1d984d4b2b508b56a77c9a567fb7a50c858e672d56e8cf7677a1fca5c98c95d1'
      - '2a00705cfd3c15cf8913e9eb4e23968efd06f1feceaef9987d26c5518887d043'
      - '2a09bbb3d1ddb729ea7591f197b5955453aa3769c6fb98a5ef60c6e4b7df23a5'
      - '42a5db2a020155b2adb77c00cbe6c6ad27c2285d8c6114679d9d34137e870b3f'
      - '7467f326677a4a2c8576e71a832e297e794ea00e9b67c4fcbe78b5aec697cec4'
      - '7c30c16e7a311dc0cdb1cdfd9ea6e502f44c027328dbe7d960b9bcd85ccf5eef'
      - 'b0af82de672d81f3c2f153977923b3884a8a9e7045b182c2379b19a1996931a0'
      - 'bd8203ab88983bc081545ff325f39e9c5cd5eb6a99d04ae2a6cf862535c9829a'
  condition: (sel_deno and sel_args) or sel_hash
kql: |
  DeviceProcessEvents
  | where FileName =~ "deno.exe"
      or ProcessCommandLine has_any (
          "--allow-net","--allow-run","--allow-read","--allow-write")
  | where InitiatingProcessFileName != "npm.exe"
spl: |
  index=* (process_name="deno.exe"
    OR (CommandLine="*--allow-net*" AND CommandLine="*--allow-run*"))
  | stats count by dest, user, process_name, CommandLine

---
# ---------------------------------------------------------------------------
# RULE 8 — Fakeset Python Backdoor Hash Match
# ---------------------------------------------------------------------------
title: Fakeset Python Backdoor Hash Hit
id: th-v3-008
status: stable
description: >
  Hash-based detection for MuddyWater's Fakeset Python backdoor.
  Signed with Amy Cherne and Donald Gay certificates.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.execution
  - attack.t1059.006
level: critical
logsource:
  category: file_event
  product: windows
detection:
  sel:
    Hashes|contains:
      - '077ab28d66abdafad9f5411e18d26e87fe43da1410ee8fe846bd721ab0cb52de'
      - '15061036c702ad92b56b35e42cf5dc334597e7311e98d2fdd3815a69ac3b1d84'
      - '2b7d8a519f44d3105e9fde2770c75efb933994c658855dca7d48c8b4897f81e6'
      - '4aef998e3b3f6ca21c78ed71732c9d2bdcc8a4e0284f51d7462c79d446fbc7be'
      - '64263640a6fdeb2388bca2e9094a17065308cf8dcb0032454c0a71d9b78327eb'
      - '64cf334716f15da1db7981fad6c81a640d94aa1d65391ef879f4b7b6edf6e7f1'
      - '74db1f653da6de134bdc526412a517a30b6856de9c3e5d0c742cb5fe9959ad0d'
      - '94f05495eb1b2ebe592481e01d3900615040aa02bd1807b705a50e45d7c53444'
      - 'a4bd1371fe644d7e6898045cc8e7b5e1562bdfd0e4871d46034e29a22dec6377'
      - 'a5d4d6be3bfe0cba23fe6b44984b5fc9c7c7e10030be96120bb30da0f2545d4c'
      - 'ddceade244c636435f2444cd4c4d3dc161981f3af1f622c03442747ecef50888'
  condition: sel

---
# ---------------------------------------------------------------------------
# RULE 9 — Stagecomp / Darkcomp Hash Match
# Legacy MuddyWater loaders. Still active in 2026.
# ---------------------------------------------------------------------------
title: MuddyWater Stagecomp or Darkcomp Loader
id: th-v3-009
status: stable
description: >
  Hash-based detection for MuddyWater legacy loaders Stagecomp and Darkcomp.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.execution
  - attack.t1059
level: critical
logsource:
  category: file_event
  product: windows
detection:
  sel:
    Hashes|contains:
      - '24857fe82f454719cd18bcbe19b0cfa5387bee1022008b7f5f3a8be9f05e4d14'
      - 'a92d28f1d32e3a9ab7c3691f8bfca8f7586bb0666adbba47eab3e1a8faf7ecc0'
      - '3df9dcc45d2a3b1f639e40d47eceeafb229f6d9e7f0adcd8f1731af1563ffb90'
      - '1319d474d19eb386841732c728acf0c5fe64aa135101c6ceee1bd0369ecf97b6'
  condition: sel

---
# ---------------------------------------------------------------------------
# RULE 10 — Abused Code-Signing Certificate Subjects
# ---------------------------------------------------------------------------
title: Binary Signed by MOIS-Abused Certificate Subjects
id: th-v3-010
status: experimental
description: >
  Detects process creation from binaries signed under Amy Cherne or Donald Gay
  certificate subjects, both abused by MuddyWater for Dindoor and Fakeset.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.defense_evasion
  - attack.t1574
  - attack.t1036
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel:
    SignatureSubject|contains:
      - 'Amy Cherne'
      - 'Donald Gay'
  condition: sel
kql: |
  DeviceFileCertificateInfo
  | where Signer has_any ("Amy Cherne","Donald Gay")
  | join kind=inner DeviceFileEvents on SHA256

---
# ---------------------------------------------------------------------------
# RULE 11 — Handala Wiper Historical Toolchain Hash Match
# Not used at Stryker, still active against Israeli/ME targets.
# ---------------------------------------------------------------------------
title: Handala Wiper Historical Toolchain
id: th-v3-011
status: stable
description: >
  Covers NSIS dropper, phishing PDF, OpenFileFinder.dll, BYOVD driver
  sample, and the compiled wiper from the traditional Handala attack chain.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://www.splunk.com/en_us/blog/security/handalas-wiper-threat-analysis-and-detections.html
tags:
  - attack.impact
  - attack.t1485
level: critical
logsource:
  category: file_event
  product: windows
detection:
  sel_sha256:
    Hashes|contains:
      - '1ab1586975779b7d1ce09315b1312b939a194de6df7c5e92aea4f963835f7b08'
      - '96dec6e07229201a02f538310815c695cf6147c548ff1c6a0def2fe38f3dcbc8'
      - '19001dd441e50233d7f0addb4fcd405a70ac3d5e310ff20b331d6f1a29c634f0'
      - '8316065c4536384611cbe7b6ba6a5f12f10db09949e66cb608c92ae8b69e4d67'
      - '9e519211947c63d9bf6f4a51bc161f5b9ace596c2935a8eedfce4057f747b961'
  sel_md5:
    Hashes|contains:
      - 'e035c858c1969cffc1a4978b86e90a30'
  sel_sha1:
    Hashes|contains:
      - 'b9930eda0091790c563226549e734a903e1baf7c'
  condition: sel_sha256 or sel_md5 or sel_sha1

---
# ---------------------------------------------------------------------------
# RULE 12 — Masquerading Wiper Filenames in %TEMP%
# ---------------------------------------------------------------------------
title: Handala Masquerading Filenames in TEMP
id: th-v3-012
status: experimental
description: >
  Detects Setup_Security.exe or Update_Patch.exe dropped in TEMP with null
  or spoofed digital signatures.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.defense_evasion
  - attack.t1036
level: high
logsource:
  category: file_event
  product: windows
detection:
  sel:
    TargetFilename|contains:
      - '\Temp\Setup_Security.exe'
      - '\Temp\Update_Patch.exe'
  filt:
    Signed: 'true'
    SignatureStatus: 'Valid'
  condition: sel and not filt

---
# ---------------------------------------------------------------------------
# RULE 13 — BYOVD ListOpenedFileDrv Load
# ---------------------------------------------------------------------------
title: Vulnerable Driver ListOpenedFileDrv Loaded
id: th-v3-013
status: stable
description: >
  Detects load of the vulnerable ListOpenedFileDrv_32.sys driver used by
  Handala wiper for privileged file operations.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - https://www.splunk.com/en_us/blog/security/handalas-wiper-threat-analysis-and-detections.html
tags:
  - attack.privilege_escalation
  - attack.t1068
level: critical
logsource:
  category: driver_load
  product: windows
detection:
  sel_name:
    ImageLoaded|endswith: '\ListOpenedFileDrv_32.sys'
  sel_pdb:
    ImageLoaded|contains: 'openfilefinder_src_vc8'
  condition: sel_name or sel_pdb

---
# ---------------------------------------------------------------------------
# RULE 14 — Regasm.exe Injection and Network Connect
# Regasm talking to the internet is almost never legitimate.
# ---------------------------------------------------------------------------
title: Regasm.exe External Network Connection
id: th-v3-014
status: stable
description: >
  Detects regasm.exe making outbound connections to non-RFC1918 addresses.
  Handala wiper injects payload into regasm.exe which then beacons to C2.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.defense_evasion
  - attack.t1218.009
level: high
logsource:
  category: network_connection
  product: windows
detection:
  sel:
    Image|endswith: '\regasm.exe'
  filt_private:
    DestinationIp|startswith:
      - '10.'
      - '172.16.'
      - '172.17.'
      - '172.18.'
      - '172.19.'
      - '172.20.'
      - '172.21.'
      - '172.22.'
      - '172.23.'
      - '172.24.'
      - '172.25.'
      - '172.26.'
      - '172.27.'
      - '172.28.'
      - '172.29.'
      - '172.30.'
      - '172.31.'
      - '192.168.'
  condition: sel and not filt_private
kql: |
  DeviceNetworkEvents
  | where InitiatingProcessFileName =~ "regasm.exe"
  | where not(ipv4_is_private(RemoteIP))
spl: |
  `sysmon` EventID=3 process_name=regasm.exe
    dest_ip!=10.0.0.0/8 dest_ip!=172.16.0.0/12 dest_ip!=192.168.0.0/16
  | stats count by user, dest_ip, process_name, ComputerName

---
# ---------------------------------------------------------------------------
# RULE 15 — AutoIt3 and .a3x Dropper
# NSIS-packaged Handala dropper.
# ---------------------------------------------------------------------------
title: AutoIt3 Execution with Compiled Script
id: th-v3-015
status: experimental
description: >
  Detects AutoIt3.exe execution or .a3x compiled script loading, used in the
  Handala NSIS dropper package.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.execution
  - attack.t1059
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel_proc:
    Image|endswith: '\autoit3.exe'
  sel_script:
    CommandLine|endswith: '.a3x'
  condition: sel_proc or sel_script
kql: |
  DeviceProcessEvents
  | where FileName in~ ("autoit3.exe")
      or ProcessCommandLine has ".a3x"
spl: |
  | tstats `security_content_summariesonly` count min(_time) as first max(_time) as last
    from datamodel=Endpoint.Processes
    where Processes.process_name IN ("autoit3.exe","autoit*.exe")
       OR Processes.original_file_name IN ("autoit3.exe","autoit*.exe")
    by Processes.dest Processes.user Processes.process_name Processes.process

---
# ---------------------------------------------------------------------------
# RULE 16 — Mass File Deletion (Wiper Signature)
# 100+ deletions from a single process in 5 minutes.
# ---------------------------------------------------------------------------
title: Mass File Deletion Wiper Behavior
id: th-v3-016
status: stable
description: >
  Detects 100 or more file deletions from a single process within 5 minutes.
  Classic wiper behavior observed in Handala operations.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.impact
  - attack.t1485
level: critical
logsource:
  category: file_delete
  product: windows
detection:
  note: >
    Threshold-based rule. Deploy as KQL or SPL scheduled query.
kql: |
  DeviceFileEvents
  | where ActionType == "FileDeleted"
  | summarize Deletions = count()
      by InitiatingProcessFileName, DeviceName, bin(Timestamp, 5m)
  | where Deletions >= 100
spl: |
  `sysmon` EventCode IN ("23","26")
    TargetFilename IN ("*.cmd","*.db","*.doc","*.zip","*.xlsx",
                        "*.pdf","*.pst","*.mdb","*.bak")
  | stats count as deletions by user, dest, process_name
  | where deletions >= 100

---
# ---------------------------------------------------------------------------
# RULE 17 — vssadmin Shadow Copy Wipe
# Standard inhibit-recovery before MBR overwrite.
# ---------------------------------------------------------------------------
title: VSS Shadow Deletion
id: th-v3-017
status: stable
description: >
  Detects vssadmin.exe deleting shadow copies with the /quiet flag.
  Handala runs this before destructive wipe operations.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.impact
  - attack.t1490
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel:
    Image|endswith: '\vssadmin.exe'
    CommandLine|contains|all:
      - 'delete'
      - 'shadows'
      - '/quiet'
  condition: sel
kql: |
  DeviceProcessEvents
  | where FileName =~ "vssadmin.exe"
  | where ProcessCommandLine has "delete" and ProcessCommandLine has "shadows"

---
# ---------------------------------------------------------------------------
# RULE 18 — NetBird Service Install
# MuddyWater deploys NetBird for stealth tunneling on servers.
# ---------------------------------------------------------------------------
title: NetBird Tunneling Service Installed
id: th-v3-018
status: experimental
description: >
  Detects NetBird installation or tunnel setup via service install or
  setup-key arguments. MuddyWater uses NetBird for post-compromise C2.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.command_and_control
  - attack.t1219
level: medium
logsource:
  category: process_creation
  product: windows
detection:
  sel:
    Image|endswith: '\netbird.exe'
    CommandLine|contains:
      - 'service install'
      - 'up --setup-key'
  condition: sel

---
# ---------------------------------------------------------------------------
# RULE 19 — VeraCrypt Silent Deployment
# Destructive encryption via legitimate tool.
# ---------------------------------------------------------------------------
title: VeraCrypt Silent Deployment
id: th-v3-019
status: experimental
description: >
  Detects VeraCrypt or VeraCryptFormat pushed silently across endpoints.
  Used by Handala for destructive encryption in non-Intune operations.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.impact
  - attack.t1486
level: high
logsource:
  category: process_creation
  product: windows
detection:
  sel:
    Image|endswith:
      - '\VeraCrypt.exe'
      - '\VeraCryptFormat.exe'
    CommandLine|contains:
      - '/create'
      - '/quick'
      - '/silent'
  condition: sel

---
# ---------------------------------------------------------------------------
# RULE 20 — Neo-reGeorg ASPX Webshell Path
# Standard MOIS persistence on Exchange/IIS.
# ---------------------------------------------------------------------------
title: Neo-reGeorg ASPX Webshell Path
id: th-v3-020
status: experimental
description: >
  Detects HTTP requests to the aspnet_client path used by MOIS for
  Neo-reGeorg ASPX tunnel webshells. Confirmed on Portuguese Immigration
  Service Exchange server.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.persistence
  - attack.t1505.003
level: high
logsource:
  category: webserver
detection:
  sel:
    cs-uri-stem|contains: '/aspnet_client/system_web/4_0_30319/'
    cs-uri-stem|endswith: '.aspx'
  condition: sel
kql: |
  W3CIISLog
  | where csUriStem has "/aspnet_client/system_web/4_0_30319/"
      and csUriStem endswith ".aspx"

---
# ---------------------------------------------------------------------------
# RULE 21 — FortiOS CVE-2024-55591 super_admin Creation
# Modified POC_ZZ_1.py creates rogue admin accounts with predictable names.
# ---------------------------------------------------------------------------
title: FortiOS Rogue super_admin Account Creation
id: th-v3-021
status: experimental
description: >
  Detects creation of super_admin accounts with names FortiWiFi, FortiSetup,
  or FortiAdmin on FortiOS devices. Pattern matches the modified POC_ZZ_1.py
  exploit for CVE-2024-55591 found on the sdrhi server.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.initial_access
  - attack.t1190
level: critical
logsource:
  product: fortios
detection:
  sel:
    event_type: 'admin-login'
    action: 'create-admin'
    user|contains:
      - 'FortiWiFi'
      - 'FortiSetup'
      - 'FortiAdmin'
  condition: sel

---
# ---------------------------------------------------------------------------
# RULE 22 — DNS Hook Exfiltration
# MOIS uses dnshook.site for payload callbacks via nslookup.
# ---------------------------------------------------------------------------
title: DNS Exfiltration via dnshook.site
id: th-v3-022
status: stable
description: >
  Detects DNS queries to dnshook.site, used by MOIS actors for DNS-based
  data exfiltration and payload callback via nslookup.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.exfiltration
  - attack.t1071.004
level: high
logsource:
  category: dns_query
  product: windows
detection:
  sel:
    QueryName|contains: 'dnshook.site'
  condition: sel
kql: |
  DeviceEvents
  | where ActionType == "DnsQueryResponse"
  | where RemoteUrl has "dnshook.site"
spl: |
  `sysmon` EventCode=22 QueryName IN ("*dnshook.site")
  | stats count by ComputerName, QueryName

---
# ---------------------------------------------------------------------------
# RULE 23 — Telegram C2 Hardcoded Token Beacon
# FBI FLASH confirmed Telegram as Handala/MOIS C2 channel.
# ---------------------------------------------------------------------------
title: Handala Telegram Bot C2 Contact
id: th-v3-023
status: stable
description: >
  Detects outbound HTTP to api.telegram.org containing the Handala bot token
  (6428401585) or chat ID (6932028002) from FBI FLASH FBI-20260320-001.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
references:
  - FBI FLASH FBI-20260320-001
tags:
  - attack.command_and_control
  - attack.t1071.001
level: critical
logsource:
  category: proxy
detection:
  sel_url:
    c-uri|contains: 'api.telegram.org'
  sel_token:
    c-uri|contains:
      - '6428401585'
      - '6932028002'
  condition: sel_url and sel_token
kql: |
  DeviceNetworkEvents
  | where RemoteUrl has "api.telegram.org"
      and (RemoteUrl has "6428401585" or RemoteUrl has "6932028002")

---
# ---------------------------------------------------------------------------
# RULE 24 — Rapid IP Lookup Reconnaissance
# Handala checks outbound IP via public services before beaconing.
# ---------------------------------------------------------------------------
title: Rapid IP Lookup Reconnaissance
id: th-v3-024
status: experimental
description: >
  Detects DNS queries to multiple public IP lookup services in quick
  succession. Handala wiper samples perform this recon before C2 beacon.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.discovery
  - attack.t1016
level: medium
logsource:
  category: dns_query
  product: windows
detection:
  sel:
    QueryName|contains:
      - 'icanhazip.com'
      - 'ipinfo.io'
      - 'checkip.'
      - 'ipify.org'
      - 'wtfismyip.com'
  condition: sel
  note: >
    Threshold logic must be applied at the SIEM layer. Alert when 2+
    unique services are queried or 3+ total hits from one host.
kql: |
  DeviceEvents
  | where ActionType == "DnsQueryResponse"
  | where RemoteUrl has_any (
      "icanhazip.com","ipinfo.io","checkip.","ipify.org","wtfismyip.com")
  | summarize Services = dcount(RemoteUrl), Hits = count() by DeviceName
  | where Services >= 2 or Hits >= 3
spl: |
  `sysmon` EventCode=22
    QueryName IN ("*icanhazip.com","*ipinfo.io","*checkip.*",
                   "*ipify.org","*wtfismyip.com")
  | stats dc(QueryName) as services, count as hits by ComputerName
  | where services >= 2 or hits >= 3

---
# ---------------------------------------------------------------------------
# RULE 25 — MOIS Infrastructure IP Contact
# Direct contact with known MOIS operational IPs. Any hit is a bad day.
# ---------------------------------------------------------------------------
title: MOIS Infrastructure IP Contact
id: th-v3-025
status: stable
description: >
  Detects network connections to or from confirmed MOIS operational IPs
  including the sdrhi cluster and historical Handala C2.
author: James McMurry, ThreatHunter.ai
date: 2026/04/16
tags:
  - attack.command_and_control
  - attack.t1071
level: critical
logsource:
  category: network_connection
  product: windows
detection:
  sel:
    DestinationIp:
      - '157.20.182.49'
      - '162.0.230.185'
      - '194.11.246.101'
      - '18.223.24.218'
      - '82.25.35.25'
      - '31.57.35.223'
      - '107.189.19.52'
      - '146.185.219.235'
  condition: sel
kql: |
  let MoisIPs = dynamic([
    "157.20.182.49","162.0.230.185","194.11.246.101","18.223.24.218",
    "82.25.35.25","31.57.35.223","107.189.19.52","146.185.219.235"]);
  union DeviceNetworkEvents, CommonSecurityLog
  | where RemoteIP in (MoisIPs) or DestinationIP in (MoisIPs)
spl: |
  index=* (dest_ip IN ("157.20.182.49","162.0.230.185","194.11.246.101",
    "18.223.24.218","82.25.35.25","31.57.35.223","107.189.19.52",
    "146.185.219.235")
    OR src_ip IN ("157.20.182.49","162.0.230.185","194.11.246.101",
    "18.223.24.218","82.25.35.25","31.57.35.223","107.189.19.52",
    "146.185.219.235"))
  | stats count by src_ip, dest_ip, sourcetype

# =============================================================================
# CONFIGURATION HARDENING
# Detection without prevention loses this one.
# =============================================================================

---
title: HARDENING — Close the PIM Authentication Context Gap
id: th-v3-hardening-001
type: configuration
steps:
  - description: Create named Authentication Context in Entra ID
    example: "c1:PrivElevation"
  - description: >
      Build Conditional Access policy scoped to that context requiring
      phishing-resistant MFA (FIDO2, Windows Hello for Business, or
      certificate-based auth). Not the checkbox. A real challenge.
  - description: >
      Open PIM role settings for Global Administrator, Intune Administrator,
      Cloud Device Administrator, Privileged Role Administrator, Security
      Administrator, Exchange Administrator, and Authentication Administrator.
      Bind each to the Authentication Context.
  - description: >
      Apply secondary Conditional Access policy directly to the Global
      Administrator directory role forcing phishing-resistant MFA on every
      session, not just activation.

---
title: HARDENING — Enable Intune Multi-Admin Approval
id: th-v3-hardening-002
type: configuration
steps:
  - description: >
      Intune admin center > Tenant administration > Multi Admin Approval.
      Create an Access Policy covering Wipe, Retire, Delete.
  - description: >
      Designate an approver group. No single admin executes destructive
      device actions solo.
  - description: >
      Create second CA Authentication Context (Intune Bulk Destructive Action),
      require FIDO2 on that context, scope to the approver group when they
      access the Intune admin center.

---
title: HARDENING — Break the Stale Session Pattern
id: th-v3-hardening-003
type: configuration
steps:
  - description: Global Admin sign-in frequency 4 hours max (Conditional Access).
  - description: Global Admin session lifetime set to non-persistent.
  - description: Revoke tokens on any Global Admin untouched in 30 days.
  - description: Remove standing access. PIM eligible only.

---
title: HARDENING — Reduce MDM Blast Radius
id: th-v3-hardening-004
type: configuration
steps:
  - description: >
      Scope Intune device action permissions to role assignments,
      not the tenant root.
  - description: Limit Wipe/Retire to a dedicated role group reviewed quarterly.
  - description: >
      Enable device limit on enrollment to prevent BYOD from inheriting
      corporate MDM destructive power.

---
title: HISTORICAL HUNTS — Run These This Week
id: th-v3-hunts-001
type: hunt
queries:
  - name: Global Admin PIM activations without strong MFA (90 days)
    target: SigninLogs + AuditLogs
    filter: >
      authenticationRequirement == singleFactorAuthentication
      or MFA claim older than 4 hours
  - name: Intune Wipe/Retire counts by initiator (90 days)
    target: Intune AuditLog
    filter: Group by InitiatedBy, count Wipe and Retire
  - name: Rclone to MOIS exfil sinks (180 days)
    target: DeviceProcessEvents / Endpoint.Processes
    filter: >
      destination contains wasabisys.com, backblazeb2.com, or put.io
  - name: DNS to MOIS C2 domains (180 days)
    target: DNS logs
    filter: >
      dnshook.site, uppdatefile.com, serialmenot.com, moonzonet.com
  - name: ListOpenedFileDrv_32.sys driver load (all time)
    target: DeviceEvents / driver_load
    filter: ImageLoaded endswith ListOpenedFileDrv_32.sys
  - name: Admin sign-ins from Iranian ASNs or AS14593 (180 days)
    target: SigninLogs
    filter: AutonomousSystemNumber in RiskyASNs touching admin roles

# =============================================================================
# COMPANION FILES
# detection-pack-v3-iocs.csv — 70+ machine-readable indicators
# =============================================================================
