Blinder Tunnel Campaign (CL-STA-1178)
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).
Source Review & Web Hunter Notes
| Tier | Source | Key finding | Carry forward |
|---|---|---|---|
| 1 | Unit 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. |
| 1 | Elastic 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. |
| 1 | Unit 42: Tracking Iranian APT Screening Serpens 2026 Espionage Campaigns | Explains 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. |
| 1 | MITRE ATT&CK technique pages: T1574.014, T1127.001, T1685, T1102, T1547.001, T1036.005, T1572, T1059.001, T1090, T1204.002, T1497, T1620, T1027, T1071.001 | Technique definitions, platform scope and mitigation M-codes used for the mapping and hardening tiers. | Yes. Authority for technique IDs and M-codes. |
| 1 | Microsoft Learn: Visual Studio trust settings | Visual 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. |
| 1 | Microsoft Learn: Attack surface reduction rules reference | Rule 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[.]239is 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.
Hunt Brief & Attack Chain
Hypotheses (ordered by fidelity)
| ID | Hypothesis | MITRE | Falcon events | Confidence |
|---|---|---|---|---|
| H1 | A process named RuntimeBroker.exe is running from a path other than System32, or any image runs from the RuntimeBrokers staging folder. | T1036.005, T1574.014 | ProcessRollup2 | HIGH |
| H2 | A Visual Studio hosting binary (vshost32.exe) runs outside Program Files beside a .exe.config, sideloading a tunneling loader. | T1574.014, T1574.001 | ProcessRollup2 | MEDIUM |
| H3 | MSBuild or devenv launched a user-profile binary during a project open (weaponized design-time build). | T1127.001, T1204.002 | ProcessRollup2 | MEDIUM |
| H4 | The MicrosoftRuntime Run value points at the RuntimeBrokers folder. | T1547.001 | AsepValueUpdate, RegGenericValueUpdate | HIGH |
| H5 | Campaign DLLs, the lure archive or staging-folder files were written to disk. | T1204.002, T1574.001 | NewExecutableWritten, PeFileWritten, ZipFileWritten | HIGH |
| H6 | A masqueraded host process resolves or connects to the GitHub API, and a rare process stacks out among api.github.com clients. | T1102, T1071.001 | DnsRequest, NetworkConnectIP4 | MEDIUM |
| H7 | The Chisel tunnel or staging infrastructure is contacted (published IPs, phishing domains). | T1572, T1090, T1071.001 | NetworkConnectIP4, DnsRequest | HIGH |
| H8 | The implant spawns a child process from the masqueraded host. | T1059.001 | ProcessRollup2 | MEDIUM |
Attack chain
| Step | Behavior | Telemetry | Query |
|---|---|---|---|
| 1 Lure | Recruiter persona for Dubai Airports IT; Inno Setup careers portal decoy (no network or backend activity), then the coding-challenge archive with a planted bug | File write of the archive (ZipFileWritten) | Q6 |
| 2 Stage one | Project opened in Visual Studio; design-time build runs the overridden GetFrameworkPaths target; creates %LOCALAPPDATA%\Microsoft\RuntimeBrokers, copies Resources binaries, launches RuntimeBroker.exe | ProcessRollup2 (MSBuild or devenv parent) | Q2, Q4 |
| 3 Stage two | Renamed signed vshost.exe reads RuntimeBroker.exe.config: custom AppDomainManager runs before Main, etwEnable false | Process path (visible); config content (not visible to CQL) | Q1, N1 (native) |
| 4 Stage three | DLL search-order sideload of RuntimeBroker.dll (ShelbyLoader V2): anti-VM checks, requires parent explorer.exe, 120 s persistence timer, 63 s beacon | PeFileWritten, AsepValueUpdate, DnsRequest | Q5, Q6, Q7, Q11 |
| 5 C2 | GitHub 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 comments | DnsRequest (host only; path is TLS-hidden) | Q10, Q11, N3 |
| 6 RAT | RuntimeBrokerApi.dll (ShelbyC2 V2), AES-CBC encrypted on disk, loaded reflectively; runs commands through PsProxy.dll without powershell.exe | In-memory only | GAP |
| 7 Pivot | Blackwood 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[.]29 | NetworkConnectIP4 | Q8, Q11 |
| 8 Parallel op | Same infrastructure hosted Google Drive lookalike phishing against an Israeli entity (May to June 2026) | DnsRequest | Q9 |
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.
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.
| Type | Value | Confidence | Action | Context | Expiry |
|---|---|---|---|---|---|
| SHA-256 | 6e7d9b33f1e72ea1ede71373a604ecdb060dab7d42055179c1eede9ecd1fd239 | MEDIUM | detect | DubaiAirport_Carrers_IT_Test.zip (lure archive) | 2027-04-07 |
| SHA-256 | f5b12772db6817f7a765a6fe7565fd3d4f87edc28e42fe3ec0244a372a410fc9 | MEDIUM | detect | FlightManager.csproj (weaponized project file) | 2027-04-07 |
| SHA-256 | 53f35e49eb9b271fd8cbcd3daacb525328dbf159a03dbd1c7adebe0363daa402 | MEDIUM | detect | RuntimeBroker.dll (ShelbyLoader V2) | 2027-04-07 |
| SHA-256 | 3fd810a3aa0039993393741b32287c367a9a5037a41e826906440887cdd3ed13 | MEDIUM | detect | PsProxy.dll (in-memory PowerShell engine) | 2027-04-07 |
| SHA-256 | 76273382e4252c1f60a2251141e108942494409c759358320735891762c0682e | MEDIUM | detect | Blackwood.dll (Chisel wrapper) | 2027-04-07 |
| SHA-256 | d3561bd4aad003dc3e08157b0891860bb496b80cd6e44901692e08ab1d4e8260 | MEDIUM | detect | Blackwood.dll.conf (contacts 91.107.156[.]29) | 2027-04-07 |
| SHA-256 | f5ba1645694c62f527ed6ceda8c68a5c3dd92b4032439167e8e937e72803b4bd | MEDIUM | detect | Blackwood archive (contacts 65.109.214[.]145) | 2027-04-07 |
| SHA-256 | 7cc571aca6d8715d9aaad3d83e1bcd30467565d583db1dfe73697c5d00a1f875 | MEDIUM | detect | Blackwood archive (contacts 87.248.129[.]239) | 2027-04-07 |
| IPv4 | 91.107.156[.]29 | MEDIUM | detect | Chisel tunneling endpoint (Blackwood config). Hetzner, Germany; suspected Iranian reseller | 2027-04-07 |
| IPv4 | 87.248.129[.]239 | MEDIUM | detect | Older Blackwood server. Iranian ISP TOSE'EH ERTEBATAT NOVIN ARIA; active April to June 2025 | 2027-04-07 |
| IPv4 | 65.109.214[.]145 | MEDIUM | detect | Phishing and Blackwood server, port 8080 | 2027-04-07 |
| IPv4 | 38.180.136[.]127 | MEDIUM | detect | Phishing staging server (early May 2026) | 2027-04-07 |
| Domain | cloud[.]g-drive[.]cam | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Domain | googeldrive[.]cam | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Domain | drivegoogel[.]cam | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Domain | googelmeet[.]online | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Domain | meetonline[.]cam | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Domain | asdfafadafg[.]online | MEDIUM | detect | Google Drive / Meet lookalike used in the parallel credential-harvesting operation | 2027-04-07 |
| Registry | HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\MicrosoftRuntime | HIGH | hunt | ShelbyLoader V2 persistence; points to %LOCALAPPDATA%\Microsoft\RuntimeBrokers\RuntimeBroker.exe. Behavioral (Q5) | n/a |
| Path | %LOCALAPPDATA%\Microsoft\RuntimeBrokers\ | HIGH | hunt | Staging folder created by the weaponized .csproj (Q2, Q6) | n/a |
| File name | RuntimeBrokerApi.dll | HIGH | hunt | ShelbyC2 V2 main RAT, AES-CBC encrypted on disk. No hash published (placeholder in section 10) | n/a |
| GitHub | hxxps[:]//github[.]com/peakyblinders-tm and hxxps[:]//github[.]com/GreenBeret0 | LOW | enrich | C2 accounts; infrastructure taken down by GitHub. Also named: ArthurShelby, JohnShelllby. Historical | n/a |
| Attribution | MusicDel[.]ir in an MP3 COMMENT field | LOW | enrich | Attribution artifact in the attacker's repository README audio. Not a network block | n/a |
Affected Surface & Telemetry Matrix
| Surface | Required telemetry | Priority | Gap risk |
|---|---|---|---|
| Developer workstations (Windows) that open third-party Visual Studio projects | Process creation with parent and path, registry autostart, file write, DNS and network with process context | CRITICAL | Config 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 domains | HIGH | Delivery channel is unreported |
| Egress proxy / secure web gateway | URL path logging with TLS inspection for api.github.com | MEDIUM | Without inspection the repository path is invisible |
| Visual Studio installations | Trust settings state, project-open audit | MEDIUM | No native Falcon event for a project open |
| Identity plane (Google Workspace lookalike phishing) | Sign-in logs for credential reuse | MEDIUM | Out of scope for endpoint CQL |
| Linux / macOS / cloud workloads | None required | LOW | Chain is Windows and .NET specific; no non-Windows behavior in the sources |
ATT&CK Mapping
| Tactic | Technique | Name | Observed behavior | Query | Mitigations |
|---|---|---|---|---|---|
| Execution | T1204.002 | User Execution: Malicious File | Coding-challenge archive opened as a job assessment | Q6 | M1040, M1038, M1017 |
| Defense Evasion / Execution | T1127.001 | Trusted Developer Utilities Proxy Execution: MSBuild | Design-time build runs the overridden GetFrameworkPaths target | Q2, Q4 | M1042, M1038 |
| Persistence / Defense Evasion | T1574.014 | Hijack Execution Flow: AppDomainManager | RuntimeBroker.exe.config swaps in a custom AppDomainManager | Q1, Q3 (config: N1) | M1022 |
| Persistence / Defense Evasion | T1574.001 | Hijack Execution Flow: DLL | RuntimeBroker.dll and Blackwood.dll sideloaded by renamed signed hosts | Q3, Q6, Q7 | See T1574.014 page |
| Defense Evasion | T1685 | Disable or Modify Tools | <etwEnable enabled="false"/> in the host config disables .NET event tracing | N1 (native only) | M1047, M1022, M1054 |
| Defense Evasion | T1036.005 | Masquerading: Match Legitimate Resource Name or Location | vshost.exe renamed RuntimeBroker.exe; folder named RuntimeBrokers | Q1, Q2, Q12 | M1045, M1038, M1022 |
| Defense Evasion | T1027 | Obfuscated Files or Information | Obfuscar obfuscation; AES-encrypted payload files | None (static) | M1049, M1047, M1040 |
| Defense Evasion | T1497 | Virtualization/Sandbox Evasion | WMI, process, registry and file checks; CPU, RAM and disk checks; parent must be explorer.exe | None | Not listed |
| Defense Evasion | T1620 | Reflective Code Loading | RuntimeBrokerApi.dll decrypted and loaded as a raw .NET assembly | None (in-memory) | Not listed |
| Persistence | T1547.001 | Boot or Logon Autostart: Registry Run Keys | HKCU Run value MicrosoftRuntime | Q5 | None preventive per MITRE |
| Execution | T1059.001 | Command and Scripting Interpreter: PowerShell | PsProxy.dll custom runspace, no powershell.exe | Q12 (consequences only) | M1049, M1045, M1042, M1038, M1026 |
| Command and Control | T1102.001 / T1102.002 | Web Service: Dead Drop Resolver / Bidirectional Communication | GitHub repo tasking; Issues Search API fallback | Q10, Q11 | M1031, M1021 |
| Command and Control | T1071.001 | Application Layer Protocol: Web Protocols | HTTPS to the GitHub API | Q10, Q11 | M1037, M1031 |
| Command and Control | T1572 | Protocol Tunneling | Chisel tunnel over HTTP | Q8, Q11 | M1037, M1031 |
| Command and Control | T1090 | Proxy | Reverse SOCKS proxy (R:0.0.0.0:10999:socks) | Q8, Q11 | M1037, 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.
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.exeoutside System32; parentMSBuild.exeordevenv.exewith an AppData\Local image. - Event ID 11 (file create):
*.exe.configcreated 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.dllloaded by an image that is notpowershell.exe,pwsh.exeor 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.
CrowdStrike LogScale CQL Hunt Queries
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).
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 name | From | Rule type | Pattern | Exclusions | Action |
|---|---|---|---|---|---|
| BlinderTunnel, RuntimeBroker Outside System32 | Q1 | Process Creation (Windows) | Image filename .*\\RuntimeBroker\.exe | Excluded image filename .*\\Windows\\System32\\RuntimeBroker\.exe | Detect: High |
| BlinderTunnel, RuntimeBrokers Staging Folder | Q2 | Process Creation (Windows) | Image filename .*\\AppData\\Local\\Microsoft\\RuntimeBrokers\\.* | None | Detect: High |
| BlinderTunnel, Child of RuntimeBroker | Q12 | Process Creation (Windows) | Parent image filename .*\\RuntimeBroker\.exe | Baseline-driven; none until baselined | Detect: 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).
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.
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
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 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
# 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.
Detection Validation Gates
Work these in order. A query that has not cleared gate 2 has no business being an alert.
| Gate | What to prove | How | Pass criteria |
|---|---|---|---|
| G1 · Telemetry ready | The events each query depends on arrive in your tenant | Run 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 baseline | You know what normal looks like | Run 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 test | The query fires on the behavior it claims | On 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 test | Tuning did not blind the query | Re-run G3 with the TUNING exclusions applied. | Test events still fire. |
| G5 · Promotion | Safe to alert | Custom IOA in Monitor mode for one business week on a pilot policy. | Zero unexplained detections. |
| G6 · Response readiness | The team can act on a hit | Tabletop the section 14 runbook with a developer-endpoint scenario. | Analyst can name the credential and token rotation scope without prompting. |
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.
- 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.
- 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.configcreation 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.
- 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.
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 reviewP3 · 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
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.
| Phase | Actions | Owner | Evidence 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 L1 | Falcon 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 L2 | Containment timestamp; P6 output; memory image |
| C2 · Scope | Run 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 hunter | List 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 / Engineering | Rotation timestamps; repository audit review |
| C4 · Eradicate | After 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 / IT | Removal log; post-clean Q1 to Q5 re-run |
| C5 · Recover | Reimage, restore from known-good, re-enroll the sensor, restore credentials only after C3. Re-enable the host with Visual Studio trust settings applied (I1). | IT | Reimage ticket; baseline re-check |
| C6 · Lessons | Report 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 intel | Updated IOC list; revision ticket |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Hardening | Coverage |
|---|---|---|---|---|---|
| T1204.002 | Lure archive and careers installer | Q6 | No | S3, N3 | PARTIAL archive file name only; the Inno Setup installer name and hash are not published, and the delivery channel is unreported |
| T1127.001 | Design-time build executes the overridden target | Q2, Q4 | No (Q2 yes) | I1, N5 | PARTIAL the process shadow is visible; the .csproj parse and target override are not. N1 sweep covers files at rest |
| T1574.014 / T1036.005 | Renamed vshost as RuntimeBroker.exe | Q1, Q2, Q3 | Yes (Q1, Q2) | N4, S1 | GOOD path anomaly is near-zero FP. Q3 is noisy on legacy .NET developer machines |
| T1685 | etwEnable false in the host config | None | No | I4, N4 | GAP 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.001 | RuntimeBroker.dll / Blackwood.dll sideload | Q6, Q7 | No | I2, I3 | PARTIAL 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.001 | MicrosoftRuntime Run value | Q5 | No | None preventive | GOOD depends on registry autostart telemetry (gate G1) |
| T1620 / T1059.001 | ShelbyC2 V2 in memory; PsProxy runspace; no powershell.exe | Q12 | Yes (Q12) | I4, S1 | GAP 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 |
| T1102 | GitHub API C2 and Issues Search fallback | Q10, Q11 | No | N1, N2 | PARTIAL 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 / T1090 | Blackwood and Chisel reverse SOCKS | Q8, Q11 | No | N1 | PARTIAL IPs are perishable and single-sourced; the tunnel is inside vshost32.exe, so process-level hunting is the durable angle |
| T1071.001 | Phishing and staging domains | Q9 | IOC Mgmt | N2 | PARTIAL perishable; Israeli-entity phishing credential theft happens at the identity plane, not on the endpoint |
| T1497 / T1027 | Anti-VM checks and Obfuscar obfuscation | None | No | None | GAP 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.
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-07Changelog
References
| Tier | Source | Used for | Accessed |
|---|---|---|---|
| 1 | Unit 42: Blinder Tunnel Campaign Targets Iraqi Infrastructure | Primary source: chain, tools, C2, IOCs, attribution | 2026-10-07 |
| 1 | Elastic Security Labs: The Shelby Strategy | Earlier ShelbyLoader and ShelbyC2 generation; behavioral corroboration only | 2026-10-07 |
| 1 | Unit 42: Tracking Iranian APT Screening Serpens 2026 Espionage Campaigns | AppDomainManager hijack config elements | 2026-10-07 |
| 1 | MITRE ATT&CK T1574.014: AppDomainManager | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1127.001: MSBuild proxy execution | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1685: Disable or Modify Tools | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1102: Web Service | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1547.001: Registry Run Keys | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1036.005: Masquerading: Match Legitimate Resource Name or Location | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1572: Protocol Tunneling | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1059.001: PowerShell | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1090: Proxy | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1204.002: User Execution: Malicious File | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1497: Virtualization/Sandbox Evasion | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1620: Reflective Code Loading | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1027: Obfuscated Files or Information | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK T1071.001: Web Protocols | Technique definition and mitigation M-codes | 2026-10-07 |
| 1 | MITRE ATT&CK Enterprise Mitigations (M-code catalog) | M-code names used in hardening tiers | 2026-10-07 |
| 1 | Microsoft Learn: Visual Studio trust settings | Hardening I1 | 2026-10-07 |
| 1 | Microsoft Learn: Attack surface reduction rules reference | Hardening I2 | 2026-10-07 |