Blinder Tunnel Campaign (CL-STA-1178)

Iranian state-aligned espionage against Iraqi critical infrastructure · Trojanized Visual Studio coding test · AppDomainManager hijack of a renamed RuntimeBroker.exe · ShelbyLoader V2, ShelbyC2 V2, PsProxy, Blackwood · GitHub API C2
Threat
CL-STA-1178 / Blinder Tunnel campaign (Unit 42 names)
Severity
HIGH targeted nation-state espionage
Type
APT RAT, loader, living-off-the-cloud C2, tunneling
Initial Access
Recruiter lure impersonating Dubai Airports IT; weaponized Visual Studio project
Version
v0.1 · 2026-10-07
Author
HuntPack
Confidence
HIGH behavior (primary vendor, corroborated pattern); MEDIUM IOCs (single source)
01

Executive Summary

Attacker objective: long-term espionage access to people inside Middle Eastern telecommunications, aviation and critical-infrastructure organizations. Palo Alto Networks Unit 42 tracks the actor as CL-STA-1178, assessed with high confidence as Iranian state-aligned, and the March 2026 operation against Iraqi critical infrastructure as the Blinder Tunnel campaign. Infrastructure staging was observed as early as November 2025. Unit 42 published the findings on 2026-10-06 and reports that GitHub has taken down the malicious infrastructure it identified.

The victim is a software engineer, not a server. The lure impersonates the Dubai Airports IT department, walks the target through a fake careers portal, then hands over a Visual Studio coding challenge (DubaiAirport_Carrers_IT_Test.zip) with a planted bug to fix. Opening the project is enough: a weaponized .csproj overrides the GetFrameworkPaths target that Visual Studio runs during its background design-time build, so code runs before anything is compiled. That launches a signed Visual Studio host binary renamed RuntimeBroker.exe, whose RuntimeBroker.exe.config performs AppDomainManager hijacking and turns off .NET event tracing with <etwEnable enabled="false"/>. The host then sideloads RuntimeBroker.dll (ShelbyLoader V2), which decrypts RuntimeBrokerApi.dll (ShelbyC2 V2) in memory.

Command and control runs entirely through the GitHub API with a hard-coded personal access token, with a fallback that searches GitHub Issues for AES-256-CBC ciphertext hidden in HTML comments. PowerShell commands execute through PsProxy.dll inside the implant process, so powershell.exe never starts. Blackwood wraps the open-source Chisel tool to open a reverse SOCKS proxy to 91.107.156[.]29.

Defender angle: the durable signals are process lineage and paths, not indicators. A RuntimeBroker.exe outside System32, anything running from %LOCALAPPDATA%\Microsoft\RuntimeBrokers, a vshost32.exe outside Program Files, and the MicrosoftRuntime Run value are near-zero false positive and survive every hash and IP rotation. The hardest parts are blind to a host sensor: the ETW-disabling config file content, the in-process PowerShell engine, and the memory-resident RAT. The Coverage Map flags each as a gap rather than hiding it.

Attribution and scope: this pack names only what the saved sources name. Unit 42 reports low-confidence tradecraft overlaps with Screening Serpens and Agent Serpens and explicitly states none is strong enough to attribute CL-STA-1178 to either group, so this pack does not. Dubai Airports was impersonated, not compromised; Unit 42 is not aware of any breach of its systems. The Google Drive and Google Workspace lookalike domains are attacker-registered; Google reports its own systems were not compromised.

Defender priority: run Q1, Q2 and Q5 across 30 days on developer endpoints first (near-zero FP). Then sweep developer source and download folders for .csproj files that define a GetFrameworkPaths target (section 7, N1). Turn on the Visual Studio "Always require a trust decision" setting for anyone who opens third-party projects (section 12, I1).

02

Source Review & Web Hunter Notes

TierSourceKey findingCarry forward
1Unit 42: Blinder Tunnel Campaign Targets Iraqi Infrastructure (2026-10-06)Primary source. Full infection chain, tool set, GitHub C2 design, IOC table, attribution reasoning, appendices A to C.Yes. Source of every atomic IOC and every campaign-specific behavior. Single vendor, so all indicators ship detect.
1Elastic Security Labs: The Shelby Strategy (2025-03-26)Documents the earlier ShelbyLoader and ShelbyC2 generation (Iraqi telecom, GitHub C2, Run-key persistence, reflective load of the backdoor, side-load through a benign .NET host).Partial. Independent corroboration of the behavior (GitHub API C2, Run-key persistence, .NET sideload, in-memory load). Its file names and indicators are the older generation and are not carried.
1Unit 42: Tracking Iranian APT Screening Serpens 2026 Espionage CampaignsExplains AppDomainManager hijacking via a legitimate config file: probing privatePath, etwEnable false, publisherPolicy apply no, requiredRuntime safemode.Partial. Technique mechanics and the config elements to sweep for. Actor attribution not transferred.
1MITRE ATT&CK technique pages: T1574.014, T1127.001, T1685, T1102, T1547.001, T1036.005, T1572, T1059.001, T1090, T1204.002, T1497, T1620, T1027, T1071.001Technique definitions, platform scope and mitigation M-codes used for the mapping and hardening tiers.Yes. Authority for technique IDs and M-codes.
1Microsoft Learn: Visual Studio trust settingsVisual Studio can require a trust decision before opening untrusted content; content is untrusted until added to Trusted Locations.Yes. Vendor authority for hardening control I1.
1Microsoft Learn: Attack surface reduction rules referenceRule GUID 01443614-cd74-433a-b99e-2ecdc07bfc25, audit mode guidance, PowerShell configuration support.Yes. Vendor authority for hardening control I2.

Web Hunter decisions and discrepancies

  • Delivery channel is not stated. Unit 42 says the attackers approached the target with a job offer and later "sent" the project archive. It does not say the archive arrived by email. This pack therefore says "recruitment lure" and does not claim spear-phishing email.
  • Two different IPs carry the Iran link. 87.248.129[.]239 is the address on the Iranian ISP TOSE'EH ERTEBATAT NOVIN ARIA and the older Blackwood server. 91.107.156[.]29, the current tunneling endpoint, is Hetzner in Germany; Unit 42 only suspects it was bought from an Iranian reseller based on Persian-language passive DNS.
  • Page date oddity. The article shows "Published October 6, 2026" and a footer reading "Updated 1 October, 2026". The update stamp precedes the publication date. The pack uses 2026-10-06 and treats the content as unverified for later edits.
  • Perishable infrastructure. GitHub removed the infrastructure Unit 42 identified, so the GitHub account indicators are historical. The behavior (GitHub API from a masqueraded .NET host) is the durable signal.
  • Related-cluster indicators excluded. The Elastic report's file names and accounts, and the Screening Serpens indicators, belong to adjacent reporting and are not shipped. Only Unit 42's Blinder Tunnel indicator table is used.
  • Unit 42 hashes cover non-PE files. The project file, config and archive hashes are valid for IOC Management but cannot appear in a PE write event, so only the three DLL hashes go into the hash query.
  • No injected instructions. Every fetched page was scanned for text addressed to an agent or asking for commands, extra fetches or changed output paths. None was found.
03

Hunt Brief & Attack Chain

Hypotheses (ordered by fidelity)

IDHypothesisMITREFalcon eventsConfidence
H1A process named RuntimeBroker.exe is running from a path other than System32, or any image runs from the RuntimeBrokers staging folder.T1036.005, T1574.014ProcessRollup2HIGH
H2A Visual Studio hosting binary (vshost32.exe) runs outside Program Files beside a .exe.config, sideloading a tunneling loader.T1574.014, T1574.001ProcessRollup2MEDIUM
H3MSBuild or devenv launched a user-profile binary during a project open (weaponized design-time build).T1127.001, T1204.002ProcessRollup2MEDIUM
H4The MicrosoftRuntime Run value points at the RuntimeBrokers folder.T1547.001AsepValueUpdate, RegGenericValueUpdateHIGH
H5Campaign DLLs, the lure archive or staging-folder files were written to disk.T1204.002, T1574.001NewExecutableWritten, PeFileWritten, ZipFileWrittenHIGH
H6A masqueraded host process resolves or connects to the GitHub API, and a rare process stacks out among api.github.com clients.T1102, T1071.001DnsRequest, NetworkConnectIP4MEDIUM
H7The Chisel tunnel or staging infrastructure is contacted (published IPs, phishing domains).T1572, T1090, T1071.001NetworkConnectIP4, DnsRequestHIGH
H8The implant spawns a child process from the masqueraded host.T1059.001ProcessRollup2MEDIUM

Attack chain

StepBehaviorTelemetryQuery
1 LureRecruiter persona for Dubai Airports IT; Inno Setup careers portal decoy (no network or backend activity), then the coding-challenge archive with a planted bugFile write of the archive (ZipFileWritten)Q6
2 Stage oneProject opened in Visual Studio; design-time build runs the overridden GetFrameworkPaths target; creates %LOCALAPPDATA%\Microsoft\RuntimeBrokers, copies Resources binaries, launches RuntimeBroker.exeProcessRollup2 (MSBuild or devenv parent)Q2, Q4
3 Stage twoRenamed signed vshost.exe reads RuntimeBroker.exe.config: custom AppDomainManager runs before Main, etwEnable falseProcess path (visible); config content (not visible to CQL)Q1, N1 (native)
4 Stage threeDLL search-order sideload of RuntimeBroker.dll (ShelbyLoader V2): anti-VM checks, requires parent explorer.exe, 120 s persistence timer, 63 s beaconPeFileWritten, AsepValueUpdate, DnsRequestQ5, Q6, Q7, Q11
5 C2GitHub contents API with hard-coded PAT: upload fingerprint to /{machineId}/Lic.txt, poll /{machineId}/Inf.txt. On 401 or revoked token, GitHub Issues Search API dead-drop with AES-256-CBC text in HTML commentsDnsRequest (host only; path is TLS-hidden)Q10, Q11, N3
6 RATRuntimeBrokerApi.dll (ShelbyC2 V2), AES-CBC encrypted on disk, loaded reflectively; runs commands through PsProxy.dll without powershell.exeIn-memory onlyGAP
7 PivotBlackwood loader in vshost32.exe decrypts an 8.4 MB embedded Chisel DLL, reads Blackwood.dll.conf, opens a reverse SOCKS proxy to 91.107.156[.]29NetworkConnectIP4Q8, Q11
8 Parallel opSame infrastructure hosted Google Drive lookalike phishing against an Israeli entity (May to June 2026)DnsRequestQ9

Timeline (per Unit 42)

  • 2025-11-18: first test of GitHub comment dead-drop resolution; staging begins.
  • Late 2026-03: recruitment lure launched against an individual in Iraq's critical infrastructure sector.
  • 2026-04: coding-challenge archive submitted to VirusTotal from Iraq; 2026-04-24 mock operational dashboard in a GitHub issue.
  • 2026-05-01: public repository with the Blackwood archive created; May to June: Israeli credential-harvesting operation on the shared server.

Hunt hint: on a confirmed host the GitHub repository paths are /{machineId}/Lic.txt and /{machineId}/Inf.txt, where machineId is the first 16 lowercase hex characters of a SHA-256 over a fixed string and a machine fingerprint. A TLS-inspecting proxy can match those path shapes against api.github.com.

04

Consolidated IOC Table

Every atomic indicator below comes from the Unit 42 indicator table and appears in saved snapshot 01-unit42-blinder-tunnel.txt. All are single-sourced, so all ship as detect; none is set to prevent. Confidence is MEDIUM because there is no second vendor listing for these specific values.

TypeValueConfidenceActionContextExpiry
SHA-2566e7d9b33f1e72ea1ede71373a604ecdb060dab7d42055179c1eede9ecd1fd239MEDIUMdetectDubaiAirport_Carrers_IT_Test.zip (lure archive)2027-04-07
SHA-256f5b12772db6817f7a765a6fe7565fd3d4f87edc28e42fe3ec0244a372a410fc9MEDIUMdetectFlightManager.csproj (weaponized project file)2027-04-07
SHA-25653f35e49eb9b271fd8cbcd3daacb525328dbf159a03dbd1c7adebe0363daa402MEDIUMdetectRuntimeBroker.dll (ShelbyLoader V2)2027-04-07
SHA-2563fd810a3aa0039993393741b32287c367a9a5037a41e826906440887cdd3ed13MEDIUMdetectPsProxy.dll (in-memory PowerShell engine)2027-04-07
SHA-25676273382e4252c1f60a2251141e108942494409c759358320735891762c0682eMEDIUMdetectBlackwood.dll (Chisel wrapper)2027-04-07
SHA-256d3561bd4aad003dc3e08157b0891860bb496b80cd6e44901692e08ab1d4e8260MEDIUMdetectBlackwood.dll.conf (contacts 91.107.156[.]29)2027-04-07
SHA-256f5ba1645694c62f527ed6ceda8c68a5c3dd92b4032439167e8e937e72803b4bdMEDIUMdetectBlackwood archive (contacts 65.109.214[.]145)2027-04-07
SHA-2567cc571aca6d8715d9aaad3d83e1bcd30467565d583db1dfe73697c5d00a1f875MEDIUMdetectBlackwood archive (contacts 87.248.129[.]239)2027-04-07
IPv491.107.156[.]29MEDIUMdetectChisel tunneling endpoint (Blackwood config). Hetzner, Germany; suspected Iranian reseller2027-04-07
IPv487.248.129[.]239MEDIUMdetectOlder Blackwood server. Iranian ISP TOSE'EH ERTEBATAT NOVIN ARIA; active April to June 20252027-04-07
IPv465.109.214[.]145MEDIUMdetectPhishing and Blackwood server, port 80802027-04-07
IPv438.180.136[.]127MEDIUMdetectPhishing staging server (early May 2026)2027-04-07
Domaincloud[.]g-drive[.]camMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
Domaingoogeldrive[.]camMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
Domaindrivegoogel[.]camMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
Domaingoogelmeet[.]onlineMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
Domainmeetonline[.]camMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
Domainasdfafadafg[.]onlineMEDIUMdetectGoogle Drive / Meet lookalike used in the parallel credential-harvesting operation2027-04-07
RegistryHKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\MicrosoftRuntimeHIGHhuntShelbyLoader V2 persistence; points to %LOCALAPPDATA%\Microsoft\RuntimeBrokers\RuntimeBroker.exe. Behavioral (Q5)n/a
Path%LOCALAPPDATA%\Microsoft\RuntimeBrokers\HIGHhuntStaging folder created by the weaponized .csproj (Q2, Q6)n/a
File nameRuntimeBrokerApi.dllHIGHhuntShelbyC2 V2 main RAT, AES-CBC encrypted on disk. No hash published (placeholder in section 10)n/a
GitHubhxxps[:]//github[.]com/peakyblinders-tm and hxxps[:]//github[.]com/GreenBeret0LOWenrichC2 accounts; infrastructure taken down by GitHub. Also named: ArthurShelby, JohnShelllby. Historicaln/a
AttributionMusicDel[.]ir in an MP3 COMMENT fieldLOWenrichAttribution artifact in the attacker's repository README audio. Not a network blockn/a
05

Affected Surface & Telemetry Matrix

SurfaceRequired telemetryPriorityGap risk
Developer workstations (Windows) that open third-party Visual Studio projectsProcess creation with parent and path, registry autostart, file write, DNS and network with process contextCRITICALConfig file content and in-process .NET execution are not visible
Any Windows endpoint of a targeted sector user (telecom, aviation, critical infrastructure)Same as above, plus DNS for lookalike domainsHIGHDelivery channel is unreported
Egress proxy / secure web gatewayURL path logging with TLS inspection for api.github.comMEDIUMWithout inspection the repository path is invisible
Visual Studio installationsTrust settings state, project-open auditMEDIUMNo native Falcon event for a project open
Identity plane (Google Workspace lookalike phishing)Sign-in logs for credential reuseMEDIUMOut of scope for endpoint CQL
Linux / macOS / cloud workloadsNone requiredLOWChain is Windows and .NET specific; no non-Windows behavior in the sources
06

ATT&CK Mapping

TacticTechniqueNameObserved behaviorQueryMitigations
ExecutionT1204.002User Execution: Malicious FileCoding-challenge archive opened as a job assessmentQ6M1040, M1038, M1017
Defense Evasion / ExecutionT1127.001Trusted Developer Utilities Proxy Execution: MSBuildDesign-time build runs the overridden GetFrameworkPaths targetQ2, Q4M1042, M1038
Persistence / Defense EvasionT1574.014Hijack Execution Flow: AppDomainManagerRuntimeBroker.exe.config swaps in a custom AppDomainManagerQ1, Q3 (config: N1)M1022
Persistence / Defense EvasionT1574.001Hijack Execution Flow: DLLRuntimeBroker.dll and Blackwood.dll sideloaded by renamed signed hostsQ3, Q6, Q7See T1574.014 page
Defense EvasionT1685Disable or Modify Tools<etwEnable enabled="false"/> in the host config disables .NET event tracingN1 (native only)M1047, M1022, M1054
Defense EvasionT1036.005Masquerading: Match Legitimate Resource Name or Locationvshost.exe renamed RuntimeBroker.exe; folder named RuntimeBrokersQ1, Q2, Q12M1045, M1038, M1022
Defense EvasionT1027Obfuscated Files or InformationObfuscar obfuscation; AES-encrypted payload filesNone (static)M1049, M1047, M1040
Defense EvasionT1497Virtualization/Sandbox EvasionWMI, process, registry and file checks; CPU, RAM and disk checks; parent must be explorer.exeNoneNot listed
Defense EvasionT1620Reflective Code LoadingRuntimeBrokerApi.dll decrypted and loaded as a raw .NET assemblyNone (in-memory)Not listed
PersistenceT1547.001Boot or Logon Autostart: Registry Run KeysHKCU Run value MicrosoftRuntimeQ5None preventive per MITRE
ExecutionT1059.001Command and Scripting Interpreter: PowerShellPsProxy.dll custom runspace, no powershell.exeQ12 (consequences only)M1049, M1045, M1042, M1038, M1026
Command and ControlT1102.001 / T1102.002Web Service: Dead Drop Resolver / Bidirectional CommunicationGitHub repo tasking; Issues Search API fallbackQ10, Q11M1031, M1021
Command and ControlT1071.001Application Layer Protocol: Web ProtocolsHTTPS to the GitHub APIQ10, Q11M1037, M1031
Command and ControlT1572Protocol TunnelingChisel tunnel over HTTPQ8, Q11M1037, M1031
Command and ControlT1090ProxyReverse SOCKS proxy (R:0.0.0.0:10999:socks)Q8, Q11M1037, M1031, M1020

T1685 is the current MITRE identifier for Disable or Modify Tools (the page for the former T1562.006 redirects to it). Technique IDs were taken from the saved MITRE snapshots, not from memory.

07

Native Audit-Log Hunts

Hunts that do not need CQL. Several are the only way to see the stages the Falcon sensor cannot.

N1 · Filesystem sweep for the weaponized project and the ETW-disabling config

Run on developer endpoints and any share holding downloaded projects. Read-only. Legitimate projects do not define a target called GetFrameworkPaths (Microsoft's own targets files do), and a .exe.config that disables ETW is rare.

$roots = @("$env:USERPROFILE", 'C:\src', 'D:\src')   # adjust to your developer paths
# 1) Project files that override the design-time GetFrameworkPaths target
Get-ChildItem -Path $roots -Recurse -File -Include *.csproj,*.vbproj,*.targets,*.props -ErrorAction SilentlyContinue |
  Select-String -Pattern '<Target\s+Name\s*=\s*"GetFrameworkPaths"' |
  Select-Object Path, LineNumber, Line

# 2) Config files that disable ETW or force local assembly probing
Get-ChildItem -Path $roots -Recurse -File -Include *.exe.config -ErrorAction SilentlyContinue |
  Select-String -Pattern 'etwEnable\s+enabled\s*=\s*"false"|probing\s+privatePath|publisherPolicy\s+apply\s*=\s*"no"|appDomainManager' |
  Select-Object Path, LineNumber, Line

N2 · Sysmon cross-reference (if deployed)

  • Event ID 1 (process create): image RuntimeBroker.exe outside System32; parent MSBuild.exe or devenv.exe with an AppData\Local image.
  • Event ID 11 (file create): *.exe.config created beside an executable in a user-writable folder; any file under \Microsoft\RuntimeBrokers\.
  • Event ID 13 (registry value set): ...\CurrentVersion\Run\MicrosoftRuntime.
  • Event ID 7 (image load): System.Management.Automation.dll loaded by an image that is not powershell.exe, pwsh.exe or an approved host. This is the best native signal for PsProxy.dll. Validate in your environment; if the config disables ETW, confirm which of your sensors still see the load.

N3 · Proxy or TLS-inspection hunt for the GitHub C2 path shapes

Where the egress proxy decrypts traffic, search for requests to api.github.com whose path matches /repos/<owner>/<repo>/contents/<16 hex characters>/Lic.txt or .../Inf.txt, and for the repository peakyblinders-tm/myLic. Also look for a fixed 63-second request cadence from one client to api.github.com, and a one-hour silence after HTTP 403 responses (the loader's rate-limit sleep). The Issues Search fallback uses the same host; its exact path is not quoted in the source, so treat a search-API pattern as an inference to validate.

N4 · PowerShell host-application hunt

PsProxy.dll runs a custom runspace inside the implant process. In the PowerShell event logs, look for engine start events and script block events (4104) whose host application or process is not powershell.exe or pwsh.exe. This depends on logging being enabled (playbook P5) and on the logging pipeline surviving the ETW change; validate on a test host before relying on it.

N5 · Defender audit telemetry for the ASR rule

After enabling the untrusted-executable ASR rule in audit mode (P3), search Defender advanced hunting for the action types AsrUntrustedExecutableAudited and AsrUntrustedExecutableBlocked originating from the RuntimeBrokers folder. Expect developer-build noise.

N6 · Visual Studio trust audit

On developer endpoints, open Tools > Options > Environment > Security > Trust and record whether "Always require a trust decision" is set and which Trusted Locations exist. Broad entries such as a whole user profile or Downloads folder defeat the control.

08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first: every "Open in Falcon" button below uses this selection.

Events and fields used here were checked against the crowdstrike-logscale-v3 references. Queries marked "validate in tenant" depend on registry or DNS process-context fields that vary by sensor version: run each event filter alone with count() over 24 hours first (gate G1).

Q1 · RuntimeBroker.exe executing from outside System32
CONF HIGHFP LOWCOST LOW

Looks for: a process named RuntimeBroker.exe whose image path is anything other than \Windows\System32\. Unit 42 reports that the loader host is a legitimate signed Visual Studio hosting binary (vshost.exe) renamed to RuntimeBroker.exe and run from %LOCALAPPDATA%\Microsoft\RuntimeBrokers. The genuine binary lives only in System32, so any other path is the masquerade. FP: none expected.

// HUNT: RuntimeBroker.exe running from outside System32 (renamed vshost host used for the AppDomainManager hijack)
// MITRE: T1036.005, T1574.014
// CONF: high | FP: low | COST: low | REQUIRES: ProcessRollup2 with ImageFileName
// SOURCE: Unit 42 Blinder Tunnel (vshost.exe renamed RuntimeBroker.exe, launched from the user's local app data)
// FALSE POSITIVES: none expected; the genuine RuntimeBroker.exe is only ever in System32
// LOOKBACK: 30d
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| FileName=/^RuntimeBroker\.exe$/i
| ImageFileName!=/\\Windows\\System32\\RuntimeBroker\.exe$/i
| table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData, aid], limit=200)
Q2 · Any executable launched from the RuntimeBrokers staging folder
CONF HIGHFP LOWCOST LOW

Looks for: any process image under %LOCALAPPDATA%\Microsoft\RuntimeBrokers\. The malicious .csproj creates this folder, copies the binaries from the project's Resources folder into it and launches the payload. The path does not exist on a clean Windows build. FP: none expected.

// HUNT: process image launched from the AppData\Local\Microsoft\RuntimeBrokers staging folder
// MITRE: T1127.001, T1036.005
// CONF: high | FP: low | COST: low | REQUIRES: ProcessRollup2 with ImageFileName
// SOURCE: Unit 42 Blinder Tunnel (stage one creates %LOCALAPPDATA%\Microsoft\RuntimeBrokers and launches RuntimeBroker.exe from it)
// FALSE POSITIVES: none expected; this folder name is not created by Windows
// LOOKBACK: 30d
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| ImageFileName=/\\AppData\\Local\\Microsoft\\RuntimeBrokers\\/i
| table([@timestamp, ComputerName, UserName, FileName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData, aid], limit=200)
Q3 · vshost / vshost32 host binary outside Program Files
CONF MEDIUMFP MEDIUMCOST LOW

Looks for: vshost.exe, vshost32.exe or *.vshost.exe running from a path that is not under Program Files. Unit 42 reports a legitimate Microsoft-signed vshost32.exe shipped beside Blackwood.dll and a vshost32.exe.config so the .NET runtime sideloads the tunneling loader, and a renamed vshost.exe for ShelbyLoader V2. FP: developers debugging older .NET projects run app.vshost.exe from bin\Debug.

// HUNT: Visual Studio hosting binary (vshost / vshost32) running outside Program Files
// MITRE: T1574.014, T1574.001
// CONF: medium | FP: medium | COST: low | REQUIRES: ProcessRollup2 with ImageFileName
// SOURCE: Unit 42 Blinder Tunnel (vshost32.exe + vshost32.exe.config sideload Blackwood.dll)
// FALSE POSITIVES: developers debugging legacy .NET projects (project output vshost.exe under bin\Debug)
// TUNING: exclude ImageFileName under known developer source roots on assets in your developer group only, for example ImageFileName!=/\\source\\repos\\/i; keep the query unfiltered on non-developer endpoints, where any hit is high value
// LOOKBACK: 30d
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| FileName=/vshost(32)?\.exe$/i
| ImageFileName!=/\\Program Files( \(x86\))?\\/i
| table([@timestamp, ComputerName, UserName, FileName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData, aid], limit=200)
Q4 · Design-time build abuse: MSBuild or devenv launching a user-profile binary
CONF MEDIUMFP MEDIUMCOST LOW

Looks for: a child of MSBuild.exe or devenv.exe whose image sits in the user's local app data (outside the Visual Studio, dotnet, NuGet, Temp and Programs folders), or whose command line references the RuntimeBrokers folder. This is the process-level shadow of the weaponized GetFrameworkPaths target. The .csproj parse itself is invisible to the sensor. FP: build steps that run helper tools installed per-user.

// HUNT: MSBuild / devenv spawning a user-profile binary (weaponized .csproj design-time build)
// MITRE: T1127.001, T1204.002
// CONF: medium | FP: medium | COST: low | REQUIRES: ProcessRollup2 with ParentBaseFileName
// SOURCE: Unit 42 Blinder Tunnel (custom GetFrameworkPaths target copies binaries and launches the payload at project load)
// FALSE POSITIVES: build steps that execute per-user tooling from AppData\Local (code generators, local test runners)
// TUNING: after a 30-day baseline, add the specific tool folders you see recurring to the ImageFileName exclusion; keep the CommandLine RuntimeBrokers branch, which has no benign explanation
// LOOKBACK: 30d
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| ParentBaseFileName=/^(MSBuild|devenv)\.exe$/i
| (ImageFileName=/\\AppData\\Local\\/i or CommandLine=/\\Microsoft\\RuntimeBrokers/i)
| ImageFileName!=/\\AppData\\Local\\(Microsoft\\VisualStudio|Microsoft\\dotnet|Microsoft\\NuGet|Temp|Programs)\\/i
| table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, ImageFileName, CommandLine, aid], limit=200)
Q5 · Run-key persistence value MicrosoftRuntime
CONF HIGHFP LOWCOST LOW

Looks for: an autostart registry write whose value name is MicrosoftRuntime or whose data points into the RuntimeBrokers folder. ShelbyLoader V2 creates the value under the current-user Run key roughly 120 seconds after start and re-checks it, pointing at %LOCALAPPDATA%\Microsoft\RuntimeBrokers\RuntimeBroker.exe. FP: none expected.

// HUNT: HKCU Run value MicrosoftRuntime pointing at the RuntimeBrokers folder (ShelbyLoader V2 persistence)
// MITRE: T1547.001
// CONF: high | FP: low | COST: low | REQUIRES: AsepValueUpdate / RegGenericValueUpdate registry telemetry (validate in tenant)
// SOURCE: Unit 42 Blinder Tunnel (MicrosoftRuntime value, 120-second persistence timer)
// FALSE POSITIVES: none expected
// LOOKBACK: 30d
#event_simpleName=/^(AsepValueUpdate|RegGenericValueUpdate)$/
| (RegValueName=/^MicrosoftRuntime$/i or RegStringValue=/\\Microsoft\\RuntimeBrokers\\/i)
| table([@timestamp, ComputerName, UserName, RegObjectName, RegValueName, RegStringValue, aid], limit=200)
Q6 · Campaign file-name sweep: lure archive and sideloaded DLLs written to disk
CONF HIGHFP LOWCOST MEDIUM

Looks for: file-write events for RuntimeBroker.dll, RuntimeBrokerApi.dll, PsProxy.dll, Blackwood.dll, the lure archive DubaiAirport_Carrers_IT_Test.zip (note the report's misspelling), or any file written into the RuntimeBrokers folder. A genuine Windows build has no RuntimeBroker.dll. FP: none expected. Limit: the AES-encrypted RuntimeBrokerApi.dll on disk is not a valid PE, so a PE-write event may never fire for it.

// HUNT: file-name sweep for the lure archive, loader DLLs and staging-folder writes
// MITRE: T1204.002, T1574.001
// CONF: high | FP: low | COST: medium | REQUIRES: NewExecutableWritten / PeFileWritten / ZipFileWritten (validate ZipFileWritten fields in tenant)
// SOURCE: Unit 42 Blinder Tunnel (archive name, RuntimeBroker.dll, RuntimeBrokerApi.dll, PsProxy.dll, Blackwood.dll)
// FALSE POSITIVES: none expected; file names are distinctive
// LOOKBACK: 90d
#event_simpleName=/^(NewExecutableWritten|PeFileWritten|ZipFileWritten)$/
| TargetFileName=/(\\(RuntimeBroker|RuntimeBrokerApi|PsProxy|Blackwood)\.dll|DubaiAirport_Carrers_IT_Test\.zip|\\Microsoft\\RuntimeBrokers\\[^\\]+)$/i
| table([@timestamp, ComputerName, UserName, TargetFileName, SHA256HashData, ContextBaseFileName, aid], limit=200)
Q7 · Hash sweep: ShelbyLoader V2, PsProxy and Blackwood DLLs
CONF HIGHFP LOWCOST LOW

Looks for: the three published PE hashes (RuntimeBroker.dll, PsProxy.dll, Blackwood.dll) in file-write and process events. Hashes are single-sourced to Unit 42 and rotate with every rebuild, so this is a retrospective sweep, not a durable control. Non-PE hashes (archive, project file, config) go to Falcon IOC Management instead (section 10). FP: none expected.

// HUNT: published SHA-256 sweep for the three DLLs in the Unit 42 indicator list
// MITRE: T1574.001, T1572
// CONF: high | FP: low | COST: low | REQUIRES: SHA256HashData on file-write events
// SOURCE: Unit 42 Blinder Tunnel indicator table (single source, ship as detect)
// FALSE POSITIVES: none expected
// NOTE: absence of hits is NOT evidence of absence; rebuilt samples will carry new hashes
// LOOKBACK: 90d
#event_simpleName=/^(NewExecutableWritten|PeFileWritten|ProcessRollup2)$/
| in(field=SHA256HashData, values=["53f35e49eb9b271fd8cbcd3daacb525328dbf159a03dbd1c7adebe0363daa402", "3fd810a3aa0039993393741b32287c367a9a5037a41e826906440887cdd3ed13", "76273382e4252c1f60a2251141e108942494409c759358320735891762c0682e"])
| table([@timestamp, ComputerName, UserName, FileName, TargetFileName, SHA256HashData, aid], limit=200)
Q8 · Outbound connection to published tunneling and staging IPs
CONF HIGHFP LOWCOST LOW

Looks for: any IPv4 connection to the four addresses Unit 42 lists. 91.107.156[.]29 is the Chisel tunneling endpoint decrypted from the Blackwood configuration, 87.248.129[.]239 is the older Blackwood server on an Iranian ISP, 65.109.214[.]145 hosted both tunneling and phishing, and 38.180.136[.]127 was the phishing staging server. FP: none expected, but these are perishable.

// HUNT: IPv4 connections to the four Unit 42 published infrastructure addresses
// MITRE: T1572, T1090
// CONF: high | FP: low | COST: low | REQUIRES: NetworkConnectIP4
// SOURCE: Unit 42 Blinder Tunnel (single source, ship as detect)
// FALSE POSITIVES: none expected; hosting IPs are reassigned over time, so re-check the date of any old hit
// NOTE: absence of hits is NOT evidence of absence
// LOOKBACK: 90d
#event_simpleName=NetworkConnectIP4
| in(field=RemoteAddressIP4, values=["91.107.156.29", "87.248.129.239", "65.109.214.145", "38.180.136.127"])
| table([@timestamp, ComputerName, UserName, ContextBaseFileName, RemoteAddressIP4, RemotePort, aid], limit=200)
Q9 · DNS lookups for the six published phishing and staging domains
CONF HIGHFP LOWCOST MEDIUM

Looks for: DNS resolution of the Google-lookalike domains Unit 42 ties to the parallel credential-harvesting operation against an Israeli entity, which shared the 65.109.214[.]145 server with the tunneling infrastructure. FP: none expected. Exact names only: the report lists cloud[.]g-drive[.]cam as a subdomain, so the parent is not matched.

// HUNT: DNS resolution of the six published phishing / staging domains
// MITRE: T1071.001
// CONF: high | FP: low | COST: medium | REQUIRES: DnsRequest
// SOURCE: Unit 42 Blinder Tunnel, Appendix B (single source, ship as detect)
// FALSE POSITIVES: none expected
// NOTE: absence of hits is NOT evidence of absence
// LOOKBACK: 90d
#event_simpleName=/^(DnsRequest|SuspiciousDnsRequest)$/
| DomainName=/(^|\.)(cloud\.g-drive\.cam|googeldrive\.cam|drivegoogel\.cam|googelmeet\.online|meetonline\.cam|asdfafadafg\.online)$/i
| table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName, aid], limit=500)
Q10 · Stack api.github.com lookups by process to expose non-developer clients
CONF MEDIUMFP HIGHCOST MEDIUM

Looks for: which processes resolve api.github.com, excluding the common developer and browser clients, ranked by how few hosts do it. Both the primary C2 (repository contents API with a hard-coded token) and the fallback (GitHub Issues Search API) use this host, so the loader's process name surfaces as a rare entry. This is a stacking hunt, not an alert. FP: high on developer estates (build agents, IDE plugins, package tooling).

// HUNT: rare processes resolving api.github.com (living-off-the-cloud C2, primary and Issues Search fallback)
// MITRE: T1102.001, T1102.002, T1071.001
// CONF: medium | FP: high | COST: medium | REQUIRES: DnsRequest with ContextBaseFileName (validate in tenant)
// SOURCE: Unit 42 Blinder Tunnel (hard-coded PAT to GitHub API; Issues Search API dead-drop fallback)
// FALSE POSITIVES: developer tooling, CI agents, IDEs and chat clients that call the GitHub API
// TUNING: extend the exclusion list with the clients you see on more than a handful of hosts after a 30-day baseline; review the lowest Hosts values first; escalate any hit whose process is RuntimeBroker.exe, vshost32.exe or MSBuild.exe
// LOOKBACK: 30d
#event_simpleName=DnsRequest
| DomainName=/^api\.github\.com$/i
| ContextBaseFileName!=/^(git|git-remote-https|gh|code|devenv|msedge|chrome|firefox|brave|GitHubDesktop|node|python|pythonw|dotnet|java|Teams|ms-teams|slack|Postman|powershell|pwsh)\.exe$/i
| groupBy([ContextBaseFileName], function=[count(as=Lookups), count(aid, distinct=true, as=Hosts)], limit=200)
| sort(Hosts, order=asc, limit=100)
Q11 · RuntimeBroker.exe or vshost32.exe making DNS or network connections
CONF HIGHFP MEDIUMCOST LOW

Looks for: DNS lookups or IPv4 connections whose initiating process is RuntimeBroker.exe or vshost32.exe. ShelbyLoader V2 beacons to the GitHub API every 63 seconds from inside the renamed host, and the Blackwood loader runs inside vshost32.exe to open the reverse SOCKS tunnel. Triage by joining the host against Q1 to Q3 hits. FP: medium until baselined, because the genuine broker process can make occasional connections on some builds.

// HUNT: RuntimeBroker.exe / vshost32.exe initiating DNS or outbound connections (loader beacon and Blackwood tunnel)
// MITRE: T1102.002, T1572, T1090
// CONF: high | FP: medium | COST: low | REQUIRES: DnsRequest and NetworkConnectIP4 with ContextBaseFileName (validate in tenant)
// SOURCE: Unit 42 Blinder Tunnel (63-second GitHub API beacon; Blackwood runs in vshost32.exe)
// FALSE POSITIVES: occasional legitimate network activity from the genuine RuntimeBroker.exe
// TUNING: prioritise hosts that also hit Q1, Q2 or Q3; for the rest, baseline 30 days and exclude hosts whose RuntimeBroker.exe resolves only Microsoft-owned names
// LOOKBACK: 30d
#event_simpleName=/^(DnsRequest|NetworkConnectIP4)$/
| ContextBaseFileName=/^(RuntimeBroker|vshost32)\.exe$/i
| table([@timestamp, ComputerName, UserName, ContextBaseFileName, DomainName, RemoteAddressIP4, RemotePort, aid], limit=300)
Q12 · Child processes of RuntimeBroker.exe (post-exploitation commands)
CONF MEDIUMFP MEDIUMCOST LOW

Looks for: any process whose parent is RuntimeBroker.exe. ShelbyC2 V2 normally runs commands through PsProxy.dll inside its own process and spawns nothing, so this catches the cases where the operator drops to a shell or runs a native tool, and it also surfaces a masqueraded parent. FP: medium until baselined, because the genuine broker occasionally launches helper processes.

// HUNT: child processes spawned by RuntimeBroker.exe (operator shell-outs from the masqueraded host)
// MITRE: T1059.001, T1036.005
// CONF: medium | FP: medium | COST: low | REQUIRES: ProcessRollup2 with ParentBaseFileName
// SOURCE: Unit 42 Blinder Tunnel (ShelbyC2 V2 runs commands via PsProxy.dll in-process)
// FALSE POSITIVES: helper processes launched by the genuine RuntimeBroker.exe
// TUNING: baseline 30 days and exclude the specific child FileName values that recur on more than a few hosts; treat any shell, whoami.exe, net.exe, nltest.exe or tunneling tool child as an incident
// LOOKBACK: 30d
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| ParentBaseFileName=/^RuntimeBroker\.exe$/i
| table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, ImageFileName, CommandLine, aid], limit=200)
09

CrowdStrike Custom IOA Recommendations

Three queries are clean enough to promote from hunt to Custom IOA. All three are detect only. The pack recommends no prevention action: every indicator is single-sourced to Unit 42, and a path-based block on RuntimeBroker.exe rests on one vendor's description of the masquerade.

IOA nameFromRule typePatternExclusionsAction
BlinderTunnel, RuntimeBroker Outside System32Q1Process Creation (Windows)Image filename .*\\RuntimeBroker\.exeExcluded image filename .*\\Windows\\System32\\RuntimeBroker\.exeDetect: High
BlinderTunnel, RuntimeBrokers Staging FolderQ2Process Creation (Windows)Image filename .*\\AppData\\Local\\Microsoft\\RuntimeBrokers\\.*NoneDetect: High
BlinderTunnel, Child of RuntimeBrokerQ12Process Creation (Windows)Parent image filename .*\\RuntimeBroker\.exeBaseline-driven; none until baselinedDetect: Medium

Pattern syntax follows the Custom IOA regular-expression fields. Confirm the exact escaping in your console before saving, then create each rule in Monitor on a pilot prevention policy for one business week. The hash, IP and domain indicators belong in IOC Management (section 10), not in IOAs.

Not recommended as IOAs: Q3, Q4 and Q10 (developer noise), Q5 (registry telemetry coverage varies), Q6 to Q9 (indicator sweeps).

10

Machine-Readable IOC Appendix

Blocks tuned to this campaign. The CSV is the only block that feeds the provenance gate: every row traces to a saved Unit 42 snapshot, and the one unpublished hash is a labelled placeholder.

Falcon IOC Management CSVbulk import, detect only
type,value,action,severity,expiration,description,tags
sha256,6e7d9b33f1e72ea1ede71373a604ecdb060dab7d42055179c1eede9ecd1fd239,detect,high,2027-04-07,Lure archive DubaiAirport_Carrers_IT_Test.zip,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,f5b12772db6817f7a765a6fe7565fd3d4f87edc28e42fe3ec0244a372a410fc9,detect,high,2027-04-07,Weaponized FlightManager.csproj,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,53f35e49eb9b271fd8cbcd3daacb525328dbf159a03dbd1c7adebe0363daa402,detect,high,2027-04-07,ShelbyLoader V2 RuntimeBroker.dll,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,3fd810a3aa0039993393741b32287c367a9a5037a41e826906440887cdd3ed13,detect,high,2027-04-07,PsProxy.dll in-memory PowerShell engine,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,76273382e4252c1f60a2251141e108942494409c759358320735891762c0682e,detect,high,2027-04-07,Blackwood.dll Chisel wrapper,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,d3561bd4aad003dc3e08157b0891860bb496b80cd6e44901692e08ab1d4e8260,detect,high,2027-04-07,Blackwood.dll.conf contacting 91.107.156.29,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,f5ba1645694c62f527ed6ceda8c68a5c3dd92b4032439167e8e937e72803b4bd,detect,high,2027-04-07,Blackwood archive contacting 65.109.214.145,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,7cc571aca6d8715d9aaad3d83e1bcd30467565d583db1dfe73697c5d00a1f875,detect,high,2027-04-07,Blackwood archive contacting 87.248.129.239,campaign:BlinderTunnel;actor:CL-STA-1178
sha256,REPLACE_WITH_SHELBYC2V2_RUNTIMEBROKERAPI_SHA256,detect,high,2027-04-07,ShelbyC2 V2 RuntimeBrokerApi.dll - NO HASH PUBLISHED,campaign:BlinderTunnel;actor:CL-STA-1178
ipv4,91.107.156.29,detect,high,2027-04-07,Chisel tunneling endpoint (Blackwood config),campaign:BlinderTunnel;actor:CL-STA-1178
ipv4,87.248.129.239,detect,high,2027-04-07,Older Blackwood server,campaign:BlinderTunnel;actor:CL-STA-1178
ipv4,65.109.214.145,detect,high,2027-04-07,Phishing and Blackwood server,campaign:BlinderTunnel;actor:CL-STA-1178
ipv4,38.180.136.127,detect,high,2027-04-07,Phishing staging server,campaign:BlinderTunnel;actor:CL-STA-1178
domain,cloud.g-drive.cam,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
domain,googeldrive.cam,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
domain,drivegoogel.cam,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
domain,googelmeet.online,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
domain,meetonline.cam,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
domain,asdfafadafg.online,detect,high,2027-04-07,Google lookalike phishing / staging domain,campaign:BlinderTunnel;actor:CL-STA-1178
Behavioral Signaturesdurable, outlives the IOCs
Blinder Tunnel (CL-STA-1178) - behavioral signatures (survive hash and IP rotation)

B1  RuntimeBroker.exe with an image path other than \Windows\System32\
B2  Any process image under %LOCALAPPDATA%\Microsoft\RuntimeBrokers\
B3  vshost.exe / vshost32.exe outside Program Files, with a *.exe.config beside it and a non-Microsoft DLL
B4  MSBuild.exe or devenv.exe parenting a user-profile binary when a project is opened
B5  HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run value MicrosoftRuntime
B6  A .exe.config containing <etwEnable enabled="false"/> and a local probing path
B7  A project file defining a custom target named GetFrameworkPaths
B8  Non-browser, non-developer process resolving api.github.com on a 63-second cadence
B9  RuntimeBroker.dll or RuntimeBrokerApi.dll anywhere (the genuine broker ships no such DLL)
B10 powershell.exe-less PowerShell: System.Management.Automation loaded by a non-PowerShell host (native telemetry only)
Named Malware / Toolingas named by the source
Named malware and tooling (names exactly as Unit 42 uses them)

ShelbyLoader V2   RuntimeBroker.dll   C# loader: persistence, host fingerprint, GitHub C2, Issues Search fallback
ShelbyC2 V2       RuntimeBrokerApi.dll   main RAT, AES-CBC encrypted on disk, loaded reflectively
PsProxy           PsProxy.dll   in-memory PowerShell runspace host, no powershell.exe
Blackwood         Blackwood.dll (+ Blackwood.dll.conf)   loader wrapping the open-source Chisel tunneling tool
Obfuscation       Obfuscar (open-source .NET obfuscator)

GitHub accounts named in the report (historical, taken down): peakyblinders-tm, ArthurShelby, JohnShelllby, GreenBeret0
C2 repository named in the report: peakyblinders-tm/myLic ; path shapes /{machineId}/Lic.txt and /{machineId}/Inf.txt
Audit Helpersread-only PowerShell
# Read-only audit helpers (run per endpoint or through RTR / your RMM)

# A. Persistence value and staging folder, every profile
Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue | ForEach-Object {
  $d = Join-Path $_.FullName 'AppData\Local\Microsoft\RuntimeBrokers'
  if (Test-Path $d) { Get-ChildItem $d -Force | Get-FileHash -Algorithm SHA256 | Select-Object Path, Hash }
}
Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name MicrosoftRuntime -ErrorAction SilentlyContinue

# B. Visual Studio trust posture (manual): Tools > Options > Environment > Security > Trust
# C. ASR untrusted-executable rule state
(Get-MpPreference).AttackSurfaceReductionRules_Ids -contains '01443614-cd74-433a-b99e-2ecdc07bfc25'

Action policy: nothing in the CSV is set to prevent. Every value is single-sourced to Unit 42 (two-source rule), and the PE hashes will change with each rebuild. Promote to prevent only after a second independent vendor lists the same value.

11

Detection Validation Gates

Work these in order. A query that has not cleared gate 2 has no business being an alert.

GateWhat to proveHowPass criteria
G1 · Telemetry readyThe events each query depends on arrive in your tenantRun each #event_simpleName filter alone over 24h with count(). Pay particular attention to registry autostart events (Q5), DnsRequest and NetworkConnectIP4 process context via ContextBaseFileName (Q10, Q11) and ZipFileWritten (Q6).Non-zero counts and the named fields populated.
G2 · Benign baselineYou know what normal looks likeRun Q3, Q4, Q10, Q11 and Q12 across 30 days of history and classify every hit.Every recurring hit is explained and excluded, or escalated.
G3 · Positive testThe query fires on the behavior it claimsOn an isolated test host in a change window: copy a harmless signed executable to a throwaway folder named %LOCALAPPDATA%\Microsoft\RuntimeBrokers and run it (Q2); copy it as RuntimeBroker.exe outside System32 (Q1); create a test Run value named MicrosoftRuntime pointing at it (Q5). Do not use real malware.Matching queries fire.
G4 · Negative testTuning did not blind the queryRe-run G3 with the TUNING exclusions applied.Test events still fire.
G5 · PromotionSafe to alertCustom IOA in Monitor mode for one business week on a pilot policy.Zero unexplained detections.
G6 · Response readinessThe team can act on a hitTabletop the section 14 runbook with a developer-endpoint scenario.Analyst can name the credential and token rotation scope without prompting.
12

Hardening: Tiered

Controls are mapped to the technique, then to a MITRE mitigation (the why) and a vendor authority (the what and where). MITRE lists no preventive mitigation for Run-key persistence (T1547.001) because it abuses a system feature, so persistence is covered by detection (Q5) and by blocking the payload path.

Immediate (this week, low compatibility risk)
  • I1 · Require a trust decision in Visual Studio on every developer endpoint that opens third-party projects. Visual Studio treats opened content as untrusted until the folder is added to Trusted Locations. Addresses T1127.001 and T1204.002. M1054 Software Configuration. Authority: Microsoft Learn, Visual Studio trust settings. Note: the page documents the Tools > Options path; no policy key was retrieved, so rollout is per developer (playbook P1). best-practice rollout, no CIS item
  • I2 · ASR rule "Block executable files from running unless they meet a prevalence, age, or trusted list criterion" in Audit mode first. It targets exactly the unknown, freshly dropped executables this chain runs from AppData. Expect developer-build noise before moving to Block. M1038 Execution Prevention. Authority: Microsoft Learn, ASR rules reference (GUID 01443614-cd74-433a-b99e-2ecdc07bfc25; requires cloud-delivered protection). Playbook P3.
  • I3 · Audit-then-deny executables in the RuntimeBrokers staging path with an AppLocker path rule, starting in AuditOnly. The folder has no legitimate use. M1038 Execution Prevention, M1022 Restrict File and Directory Permissions. Authority: MITRE T1036.005 and T1574.014 mitigation pages; vendor product guidance for AppLocker was not retrieved for this pack. Playbook P4.
  • I4 · PowerShell script block and module logging so that custom runspaces leave a trail. M1047 Audit. Authority: MITRE T1685 mitigation page; the effect on a runspace hosted outside powershell.exe is unvalidated and must be tested (N4). Playbook P5.
  • I5 · Load the section 10 CSV into IOC Management as detect and run Q6 to Q9 retrospectively. This is detection, not prevention, and is listed here because it is free and immediate.
Near term (1 to 4 weeks, pilot first)
  • N1 · Restrict GitHub API egress to approved clients. Allow api.github.com only for sanctioned developer tools and build agents; alert on other processes and users. M1021 Restrict Web-Based Content, M1037 Filter Network Traffic. Authority: MITRE T1102 and T1071.001 mitigation pages. best-practice, no formal benchmark (process-aware allowlisting depends on your proxy or EDR).
  • N2 · DNS and URL filtering for newly registered and lookalike Google Drive and Meet domains, plus the six domains in section 10. M1021, M1031. Authority: MITRE T1102 mitigation page.
  • N3 · Open untrusted coding assessments in a disposable VM or Windows Sandbox, never on the daily-driver developer profile that holds source-control tokens. M1048 Application Isolation and Sandboxing. best-practice, no formal benchmark
  • N4 · Write-protect .NET application folders and monitor .exe.config creation beside executables in user-writable paths. M1022 Restrict File and Directory Permissions. Authority: MITRE T1574.014 mitigation text (install .NET software in write-protected locations; restrict writes to .NET search paths).
  • N5 · Remove or restrict MSBuild.exe on endpoints that do not build software. M1042 Disable or Remove Feature or Program, M1038. Authority: MITRE T1127.001 mitigation text.
Strategic (1 to 3 months)
  • S1 · Application control (WDAC or equivalent) on developer endpoints that blocks unsigned or user-writable-path execution and flags signed Microsoft binaries run from non-standard locations. M1038, M1045 Code Signing. Authority: MITRE T1036.005 mitigation page. Vendor WDAC documentation was not retrieved for this pack. best-practice, no CIS item cited
  • S2 · Developer workstation tier: separate identity, tokens and network egress for machines that hold source-control and signing credentials. M1048, M1037. best-practice, no formal benchmark
  • S3 · Recruitment-lure awareness for engineers and the telecom, aviation and infrastructure workforce: an unsolicited coding test is an execution request. M1017 User Training. Authority: MITRE T1204.002 mitigation page.
  • S4 · Phishing-resistant MFA for the Google Workspace and other cloud identities targeted by the parallel lookalike-portal operation; Google advises passkeys in the Unit 42 report. M1032 Multi-factor Authentication.
13

Deployable Playbooks

Test every playbook on a pilot ring first. P3 and P4 are audit-only by design. Each playbook lists its prerequisites, reboot requirement and rollback.

P1 · Visual Studio trust decision (I1)

# P1 · Visual Studio: require a trust decision (manual, per developer)
# Prerequisites: Visual Studio 2022 (trust settings per Microsoft Learn). Local user session. No admin needed.
# Reboot required: no (restart Visual Studio)
# Rollback: Tools > Options > Environment > Security > Trust > set "Require a trust decision" back to its prior value
#           and remove any Trusted Locations you added

1. Open Visual Studio.
2. Tools > Options > Environment > Security > Trust  (labelled "Trust Policies" in newer builds).
3. Set "Require a trust decision" to "Always require a trust decision".
4. Review "Trusted Locations". Remove entries that cover a whole user profile, Downloads, Desktop or a drive root.
   Keep only the specific source-repository folders you control.
5. Verify: open a project from a folder that is not trusted. A trust warning dialog must appear before the project loads.
   Choose Cancel for any third-party coding test.

P2 · Developer-folder sweep (N1)

# P2 · Sweep developer folders for the weaponized project and ETW-disabling configs (read-only)
# Prerequisites: PowerShell 5.1+; read access to the folders searched
# Reboot required: no
# Rollback: none required (read-only; writes only to the console and an optional CSV)

$roots = @("$env:USERPROFILE", 'C:\src', 'D:\src')
$hits = @()
$hits += Get-ChildItem -Path $roots -Recurse -File -Include *.csproj,*.vbproj,*.targets,*.props -ErrorAction SilentlyContinue |
  Select-String -Pattern '<Target\s+Name\s*=\s*"GetFrameworkPaths"' |
  ForEach-Object { [pscustomobject]@{ Finding='GetFrameworkPaths override'; Path=$_.Path; Line=$_.LineNumber } }
$hits += Get-ChildItem -Path $roots -Recurse -File -Include *.exe.config -ErrorAction SilentlyContinue |
  Select-String -Pattern 'etwEnable\s+enabled\s*=\s*"false"|probing\s+privatePath|appDomainManager' |
  ForEach-Object { [pscustomobject]@{ Finding='suspicious exe.config'; Path=$_.Path; Line=$_.LineNumber } }
$hits | Format-Table -AutoSize
$hits | Export-Csv "$env:TEMP\blinder-sweep.csv" -NoTypeInformation   # remove after review

P3 · ASR untrusted-executable rule, audit (I2)

# P3 · ASR: block executables that fail prevalence, age or trusted-list checks (AUDIT first)
# Prerequisites: Microsoft Defender Antivirus active; cloud-delivered protection enabled; local administrator
# Reboot required: no
# Rollback: Remove-MpPreference -AttackSurfaceReductionRules_Ids 01443614-cd74-433a-b99e-2ecdc07bfc25
#           (or re-run Add-MpPreference with -AttackSurfaceReductionRules_Actions Disabled)

$id = '01443614-cd74-433a-b99e-2ecdc07bfc25'
Add-MpPreference -AttackSurfaceReductionRules_Ids $id -AttackSurfaceReductionRules_Actions AuditMode

# Verify
$p = Get-MpPreference
$i = [array]::IndexOf($p.AttackSurfaceReductionRules_Ids, $id)
if ($i -ge 0) { "Rule present, action = " + $p.AttackSurfaceReductionRules_Actions[$i] }   # 2 = Audit, 1 = Block

# After 2 to 4 weeks of clean audit data on a pilot ring, change AuditMode to Enabled for non-developer rings only.

P4 · AppLocker audit-deny for the staging folder (I3)

# P4 · AppLocker: audit-deny executables in the RuntimeBrokers staging folder
# Prerequisites: Windows Enterprise/Education (AppLocker), Application Identity service able to start, local administrator.
#                AuditOnly mode logs but never blocks, so it is safe to deploy before baselining.
# Reboot required: no (start the AppIDSvc service if stopped)
# Rollback: Set-AppLockerPolicy with the previously exported policy, or:
#           Get-AppLockerPolicy -Local -Xml | Out-File before.xml  (export BEFORE merging, keep the file)

Get-AppLockerPolicy -Local -Xml | Out-File "$env:TEMP\applocker-before.xml" -Encoding utf8
$id = [guid]::NewGuid().ToString()
$xml = @"
<AppLockerPolicy Version="1">
  <RuleCollection Type="Exe" EnforcementMode="AuditOnly">
    <FilePathRule Id="$id" Name="BlinderTunnel deny RuntimeBrokers staging folder" Description="Folder is created by the weaponized csproj" UserOrGroupSid="S-1-1-0" Action="Deny">
      <Conditions><FilePathCondition Path="%OSDRIVE%\Users\*\AppData\Local\Microsoft\RuntimeBrokers\*" /></Conditions>
    </FilePathRule>
  </RuleCollection>
</AppLockerPolicy>
"@
$xml | Out-File "$env:TEMP\blinder-applocker.xml" -Encoding utf8
Set-AppLockerPolicy -XmlPolicy "$env:TEMP\blinder-applocker.xml" -Merge
Set-Service AppIDSvc -StartupType Automatic; Start-Service AppIDSvc

# Verify: launch a harmless copied exe from that folder, then check Event Viewer >
# Applications and Services Logs > Microsoft > Windows > AppLocker > EXE and DLL for an audit event.
Get-AppLockerPolicy -Effective -Xml | Select-String 'RuntimeBrokers'

P5 · PowerShell logging (I4)

# P5 · PowerShell script block and module logging
# Prerequisites: local administrator; size the PowerShell Operational log first (for example 512 MB)
# Reboot required: no
# Rollback: set both values to 0 or delete the two policy keys

$sb = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
$ml = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging'
foreach ($p in $sb, $ml) { if (-not (Test-Path $p)) { New-Item -Path $p -Force | Out-Null } }
New-ItemProperty -Path $sb -Name EnableScriptBlockLogging -PropertyType DWord -Value 1 -Force | Out-Null
New-ItemProperty -Path $ml -Name EnableModuleLogging -PropertyType DWord -Value 1 -Force | Out-Null
wevtutil sl "Microsoft-Windows-PowerShell/Operational" /ms:536870912

# Verify
Get-ItemProperty $sb, $ml | Select-Object PSPath, EnableScriptBlockLogging, EnableModuleLogging
# Then validate in a lab that a runspace hosted OUTSIDE powershell.exe still produces Event 4104 (see N4).

P6 · Evidence collection for a confirmed host

# P6 · Containment evidence collection (read-only; run BEFORE any cleanup)
# Prerequisites: local administrator or Falcon RTR session with the needed role; host already network-contained
# Reboot required: no. Do NOT reboot: the RAT and PsProxy live only in memory.
# Rollback: none required (read-only). Cleanup commands are in the section 14 runbook, not here.

$out = "$env:SystemDrive\IR-blinder"; New-Item -ItemType Directory -Path $out -Force | Out-Null
Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue | ForEach-Object {
  $d = Join-Path $_.FullName 'AppData\Local\Microsoft\RuntimeBrokers'
  if (Test-Path $d) {
    Get-ChildItem $d -Force | Get-FileHash -Algorithm SHA256 | Export-Csv "$out\hashes-$($_.Name).csv" -NoTypeInformation
    Get-ChildItem $d -Filter *.config -Force | ForEach-Object { Copy-Item $_.FullName "$out\$($_.Name).copy" }
  }
}
reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v MicrosoftRuntime > "$out\run-key.txt" 2>&1
Get-NetTCPConnection -State Established | Select-Object LocalPort, RemoteAddress, RemotePort, OwningProcess |
  Export-Csv "$out\netstat.csv" -NoTypeInformation
Get-Process | Select-Object Id, ProcessName, Path | Export-Csv "$out\processes.csv" -NoTypeInformation
14

Containment Runbook

Sequencing rule: the victim is a developer. Treat every credential, token and signing key reachable from that workstation as exposed, and start rotation in parallel with isolation. The implant keeps the GitHub PAT in the binary; assume the operator also holds whatever the user could reach.

PhaseActionsOwnerEvidence to capture
C0 · Triage
0 to 15 min
Confirm which query fired. Identify user, host and time. Check whether Q1, Q2, Q5 and Q11 also fired on the same aid. Check for the project archive via Q6.SOC L1Falcon process tree; query output; aid and ComputerName
C1 · Isolate
15 to 30 min
Network-contain the host in Falcon. Do not power off or reboot: ShelbyC2 V2 and PsProxy are memory-resident. Run P6 before cleanup. Capture memory if your tooling supports it.SOC L2Containment timestamp; P6 output; memory image
C2 · ScopeRun Q1 to Q12 across 30 to 90 days for other hosts. Pivot on the four IPs and six domains in DNS, proxy and firewall logs. Run P2 on developer shares. Ask who else received the same recruiter approach.Threat hunterList of affected hosts and users; recruiter contact details
C3 · Credentials and tokens
parallel with C1
Reset the user's passwords and revoke sessions and refresh tokens. Rotate source-control tokens, cloud keys, package-registry and signing credentials that were reachable from the host. Review recent commits and CI changes by that user for tampering.IAM / EngineeringRotation timestamps; repository audit review
C4 · EradicateAfter imaging: stop the RuntimeBroker.exe and vshost32.exe processes that run from user-writable paths; delete the MicrosoftRuntime Run value; remove %LOCALAPPDATA%\Microsoft\RuntimeBrokers and any vshost32.exe.config / Blackwood.dll.conf pair; delete the lure archive and project. Prefer a full reimage for a developer host.SOC L2 / ITRemoval log; post-clean Q1 to Q5 re-run
C5 · RecoverReimage, restore from known-good, re-enroll the sensor, restore credentials only after C3. Re-enable the host with Visual Studio trust settings applied (I1).ITReimage ticket; baseline re-check
C6 · LessonsReport any new GitHub accounts or repositories found to GitHub. Add confirmed values to IOC Management. Feed new hashes back into this pack as a v0.2 revision.Threat intelUpdated IOC list; revision ticket
15

Detection Coverage Map

TechniqueBehaviorCQLIOAHardeningCoverage
T1204.002Lure archive and careers installerQ6NoS3, N3PARTIAL archive file name only; the Inno Setup installer name and hash are not published, and the delivery channel is unreported
T1127.001Design-time build executes the overridden targetQ2, Q4No (Q2 yes)I1, N5PARTIAL the process shadow is visible; the .csproj parse and target override are not. N1 sweep covers files at rest
T1574.014 / T1036.005Renamed vshost as RuntimeBroker.exeQ1, Q2, Q3Yes (Q1, Q2)N4, S1GOOD path anomaly is near-zero FP. Q3 is noisy on legacy .NET developer machines
T1685etwEnable false in the host configNoneNoI4, N4GAP CQL has no file-content telemetry. Only the N1 filesystem sweep and Sysmon file events see the config. Confirm which of your sensors consume .NET runtime ETW, since the config is designed to blind them
T1574.001RuntimeBroker.dll / Blackwood.dll sideloadQ6, Q7NoI2, I3PARTIAL write and hash events only; no module-load query. Loads of unsigned DLLs by signed hosts are not queried because no verified module-load event is in the reference
T1547.001MicrosoftRuntime Run valueQ5NoNone preventiveGOOD depends on registry autostart telemetry (gate G1)
T1620 / T1059.001ShelbyC2 V2 in memory; PsProxy runspace; no powershell.exeQ12Yes (Q12)I4, S1GAP in-process execution is invisible to process and file queries. Q12 catches only operator shell-outs. N2 (image load) and N4 are native-only and unvalidated
T1102GitHub API C2 and Issues Search fallbackQ10, Q11NoN1, N2PARTIAL host sensor sees the DNS name and process, not the repository path or search query. Fallback is indistinguishable from primary at DNS. Needs TLS inspection (N3)
T1572 / T1090Blackwood and Chisel reverse SOCKSQ8, Q11NoN1PARTIAL IPs are perishable and single-sourced; the tunnel is inside vshost32.exe, so process-level hunting is the durable angle
T1071.001Phishing and staging domainsQ9IOC MgmtN2PARTIAL perishable; Israeli-entity phishing credential theft happens at the identity plane, not on the endpoint
T1497 / T1027Anti-VM checks and Obfuscar obfuscationNoneNoNoneGAP static and in-process behavior; no practical endpoint signal

Validation gates (summary): telemetry ready (G1), benign baseline (G2), positive test (G3), negative test (G4), Monitor-mode promotion (G5), response readiness (G6). Full table in section 11.

Honest scope: this pack detects the masquerade, the staging path, the persistence and the network consequences. It cannot see the ETW-disabling configuration content, the AppDomainManager execution itself, PsProxy running inside the implant, or the memory-resident ShelbyC2 V2. If the first hit is a Q10 or Q11 network detection, assume the earlier stages already ran.

16

Hunt Summary Ticket

TITLE:      Blinder Tunnel (CL-STA-1178): trojanized Visual Studio project, AppDomainManager hijack, GitHub API C2
SEVERITY:   High. Unit 42 reporting 2026-10-06; Iranian state-aligned actor; targeted at telecom, aviation and critical infrastructure
SCOPE:      Windows developer endpoints first; any Windows endpoint of a targeted-sector user. Priority: users who open third-party
            Visual Studio projects or recruiter-supplied coding tests.

HYPOTHESIS: A user opened a recruiter-supplied project. A weaponized .csproj ran during the design-time build, staged a renamed signed
            Visual Studio host as RuntimeBroker.exe under the user's local app data, hijacked its AppDomainManager via the .exe.config,
            sideloaded RuntimeBroker.dll (ShelbyLoader V2), persisted via a HKCU Run value, and now takes tasking over the GitHub API.

QUERIES:    Q1  RuntimeBroker.exe outside System32              CONF high | FP low  | COST low
            Q2  image from the RuntimeBrokers folder            CONF high | FP low  | COST low
            Q3  vshost / vshost32 outside Program Files         CONF med  | FP med  | COST low
            Q4  MSBuild / devenv launching user-profile binary  CONF med  | FP med  | COST low
            Q5  Run value MicrosoftRuntime                      CONF high | FP low  | COST low
            Q6  file-name sweep (archive, DLLs, folder writes)  CONF high | FP low  | COST med
            Q7  SHA-256 sweep (3 DLLs)                          CONF high | FP low  | COST low
            Q8  published IP connections                        CONF high | FP low  | COST low
            Q9  published phishing domains                      CONF high | FP low  | COST med
            Q10 api.github.com stacking by process              CONF med  | FP high | COST med
            Q11 RuntimeBroker/vshost32 network                  CONF high | FP med  | COST low
            Q12 children of RuntimeBroker.exe                   CONF med  | FP med  | COST low

DO FIRST:   1. Q1, Q2, Q5 across 30 days on developer endpoints (near-zero FP)
            2. Q11 and Q12 on any host that hit 1
            3. Q6 to Q9 retrospective sweeps (perishable)
            4. P2 filesystem sweep on developer shares
            5. Apply I1 (Visual Studio trust decision) on developer endpoints

FINDINGS:   [ ] Q1 hits: ______    [ ] Q2 hits: ______    [ ] Q5 hits: ______
            [ ] Q6 to Q9 hits: ______    [ ] Hosts with 2+ query hits in 24h (auto-escalate): ______
            [ ] Credentials and tokens requiring rotation: ______

GAPS:       - ETW-disabling config content has no CQL signal (native sweep only)
            - AppDomainManager execution, PsProxy and ShelbyC2 V2 are in-process / in-memory
            - RuntimeBrokerApi.dll hash not published (placeholder in IOC CSV)
            - GitHub repository path and Issues Search fallback invisible without TLS inspection
            - All IOCs single-sourced to Unit 42; nothing ships at prevent
            - Delivery channel of the archive is unreported

ACTIONS:    [ ] Promote Q1, Q2, Q12 to Custom IOA (Monitor mode, pilot policy, 1 week)
            [ ] Import the section 10 CSV into IOC Management (detect)
            [ ] Deploy Immediate hardening: I1 trust decision, I2 ASR audit, I3 AppLocker audit, I4 PS logging
            [ ] Confirm registry autostart and DNS process-context telemetry (gate G1)
            [ ] Re-run this pack when a second vendor publishes indicators

OWNER:      ______________________
VERSION:    v0.1 - 2026-10-07
17

Changelog

v0.1 2026-10-07 Initial draft. Built from the Unit 42 Blinder Tunnel report (2026-10-06) with the Elastic Shelby Strategy report and the Unit 42 Screening Serpens report as behavioral corroboration, and MITRE ATT&CK and Microsoft Learn pages for mapping and hardening. Twelve CQL hunt queries, 18 atomic indicators as detect-only (nothing at prevent), one labelled placeholder for the unpublished RuntimeBrokerApi.dll hash. Related-cluster indicators from the Elastic and Screening Serpens reports were deliberately excluded. Delivery channel, which the primary source does not state, is not asserted.
18

References

TierSourceUsed forAccessed
1Unit 42: Blinder Tunnel Campaign Targets Iraqi InfrastructurePrimary source: chain, tools, C2, IOCs, attribution2026-10-07
1Elastic Security Labs: The Shelby StrategyEarlier ShelbyLoader and ShelbyC2 generation; behavioral corroboration only2026-10-07
1Unit 42: Tracking Iranian APT Screening Serpens 2026 Espionage CampaignsAppDomainManager hijack config elements2026-10-07
1MITRE ATT&CK T1574.014: AppDomainManagerTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1127.001: MSBuild proxy executionTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1685: Disable or Modify ToolsTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1102: Web ServiceTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1547.001: Registry Run KeysTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1036.005: Masquerading: Match Legitimate Resource Name or LocationTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1572: Protocol TunnelingTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1059.001: PowerShellTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1090: ProxyTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1204.002: User Execution: Malicious FileTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1497: Virtualization/Sandbox EvasionTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1620: Reflective Code LoadingTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1027: Obfuscated Files or InformationTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK T1071.001: Web ProtocolsTechnique definition and mitigation M-codes2026-10-07
1MITRE ATT&CK Enterprise Mitigations (M-code catalog)M-code names used in hardening tiers2026-10-07
1Microsoft Learn: Visual Studio trust settingsHardening I12026-10-07
1Microsoft Learn: Attack surface reduction rules referenceHardening I22026-10-07