Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/main-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ jobs:
ci/check_mock_services_loopback.py \
ci/check_no_real_rmm_license.py \
ci/check_no_suspicious_pth.py \
ci/check_snowflake_report_integrity.py; do
ci/check_snowflake_report_integrity.py \
ci/check_snowflake_tools_syntax.py; do
name=$(basename "$check" .py)
if python3 "$check"; then
echo "- ✅ \`${name}\`" >> $GITHUB_STEP_SUMMARY
Expand Down
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ The report at `reports/snowflake-platform-assessment/` is a set of linked static
→ [tools/lateral-movement/sccm-abuse/README.md](tools/lateral-movement/sccm-abuse/README.md) — SCCM ELEVATE1/2
→ [tools/lateral-movement/azure-arc/README.md](tools/lateral-movement/azure-arc/README.md) — Azure Arc MSI pivot
→ [tools/lateral-movement/exchange-hybrid/README.md](tools/lateral-movement/exchange-hybrid/README.md) — evoSTS token forge
→ [tools/lateral-movement/snowflake-pivot/README.md](tools/lateral-movement/snowflake-pivot/README.md) — Snowflake Chain E storage-integration enum, Chain G share / replication exfil, bind-param evasion
→ [tools/kerberos/README.md](tools/kerberos/README.md) — S4U2self/proxy, RBCD, NTLM relay, EPA recon, NTLM reflection LPE, AES roasting

### AD CS & Identity
→ [tools/ad-cs/README.md](tools/ad-cs/README.md) — ESC1–ESC16, chain.py, Shadow Credentials 2026
→ [tools/cloud-identity/README.md](tools/cloud-identity/README.md) — WIF, OIDC, Golden SAML, Silver SAML, SyncJacking, EvilTokens, FOCI, PRT devtools, CloudTrail blinding
→ [tools/cloud-identity/snowflake/README.md](tools/cloud-identity/snowflake/README.md) — Snowflake JWT key-pair (Chain F), PAT scope walk, SCIM token harvester
→ [tools/entra-abuse/README.md](tools/entra-abuse/README.md) — device-code, PRT, token replay (historical)

### Lateral Movement
Expand All @@ -126,6 +128,7 @@ The report at `reports/snowflake-platform-assessment/` is a set of linked static
→ [tools/llm-attacks/m365-copilot/README.md](tools/llm-attacks/m365-copilot/README.md) — EchoLeak (CVE-2025-32711), ShareLeak (CVE-2026-21520)
→ [tools/llm-attacks/agentforce/README.md](tools/llm-attacks/agentforce/README.md) — PipeLeak Agentforce
→ [tools/llm-attacks/mcp-abuse/git-mcp-cve-class/README.md](tools/llm-attacks/mcp-abuse/git-mcp-cve-class/README.md) — Git MCP CVE-2025-68143/68144/68145
→ [tools/llm-attacks/cortex/README.md](tools/llm-attacks/cortex/README.md) — Cortex Search index poisoning, Cortex Agent MCP poisoning (Chain I), Cortex Guardrails FP/FN harness

### EDR Silencing & BYOVD
→ [tools/edr-silencing/callback-integrity/README.md](tools/edr-silencing/callback-integrity/README.md) — kernel callback enumeration
Expand Down Expand Up @@ -176,7 +179,8 @@ The report at `reports/snowflake-platform-assessment/` is a set of linked static
→ [docs/analysis/firmware-landscape-2026/README.md](docs/analysis/firmware-landscape-2026/README.md) — Hydroph0bia, LogoFAIL successors, UEFI cert expiry
→ [docs/analysis/apple-mie-impact.md](docs/analysis/apple-mie-impact.md) — Apple Memory Integrity Enforcement
→ [docs/analysis/vishing-2026-market.md](docs/analysis/vishing-2026-market.md) — deepfake vishing economics + healthcare targeting
→ [docs/analysis/snowflake-platform-attack-surface-2026.md](docs/analysis/snowflake-platform-attack-surface-2026.md) — CVE inventory, UNC5537 analysis, Cortex AI/Native Apps/SPCS attack surface, chains A–E, detection gaps
→ [docs/analysis/snowflake-platform-attack-surface-2026.md](docs/analysis/snowflake-platform-attack-surface-2026.md) — CVE inventory, UNC5537 analysis, Cortex AI/Native Apps/SPCS attack surface, chains A–I, Trail vs ACCOUNT_USAGE field mapping
→ [detection/snowflake/README.md](detection/snowflake/README.md) — Cross-chain Sigma/KQL/SPL index, streaming ingest pattern, connector-debug-log secret-leak detector

### Research Docs — Methodology
→ [docs/methodology/callstack-spoofing.md](docs/methodology/callstack-spoofing.md)
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ Each tool below ships under [tools/](tools/) and has a sibling `detection/` dire
### Lateral Movement

- **Lateral Movement** — [tools/lateral-movement/](tools/lateral-movement/). RPC-based DCOM / TSCH / SCMR / WMI execution; SCCM ELEVATE1/2 plus the TAKEOVER-5 Entra-integration chain (SpecterOps, November 2025); Azure Arc MSI pivot with CVE-2026-26117 (`himds` pipe DACL); Exchange hybrid evoSTS token forge.
- **Snowflake Pivot** — [tools/lateral-movement/snowflake-pivot/](tools/lateral-movement/snowflake-pivot/). Snowflake-specific lateral primitives: Storage Integration enumeration (Chain E), Direct Share + replication-group exfil (Chain G, audit-bypass via server-side data motion), bind-parameter evasion against `QUERY_HISTORY`. Talks to `mock-snowflake` on 9600.

### Cloud Identity

- **Cloud Identity Attacks** — [tools/cloud-identity/](tools/cloud-identity/). The modern cloud-identity surface: Workload Identity Federation wildcard `sub` abuse, Golden SAML, Silver SAML (secondary cert), SyncJacking via `ImmutableId` takeover, EvilTokens-style device-code 2026 PhaaS (Broker client ID FOCI path), FOCI Conditional Access bypass, PRT extraction via dev tools, and a CloudTrail-blinding catalog. Talks to the lab mocks: `mock-oidc` (9300), `mock-saml` (9400), `mock-entra` (9100/9102).
- **Snowflake Cloud Identity** — [tools/cloud-identity/snowflake/](tools/cloud-identity/snowflake/). Snowflake-specific identity abuse for the post-UNC5537 / post-MFA control surface: JWT key-pair signer (Chain F — service-user key theft from CI / orchestration hosts), PAT scope walk, SCIM token harvester with a role-race primitive. Talks to `mock-snowflake` on 9600.
- **Entra ID Abuse (legacy)** — [tools/entra-abuse/](tools/entra-abuse/). Earlier device-code phishing, PRT simulation, and token-replay work. Kept for historical reference; current Entra work lives under `cloud-identity/`.

### Kernel LPE (Windows)
Expand Down Expand Up @@ -118,6 +120,7 @@ Each tool below ships under [tools/](tools/) and has a sibling `detection/` dire
- **M365 Copilot** — [tools/llm-attacks/m365-copilot/](tools/llm-attacks/m365-copilot/). EchoLeak (CVE-2025-32711, zero-click email → Copilot → exfil) and ShareLeak (CVE-2026-21520, Copilot Studio form-field injection). Both run against `mock-copilot` on 8090.
- **Agentforce** — [tools/llm-attacks/agentforce/](tools/llm-attacks/agentforce/). PipeLeak public lead-form hijack simulation against `mock-agentforce` on 8091.
- **MCP Abuse** — [tools/llm-attacks/mcp-abuse/](tools/llm-attacks/mcp-abuse/). Tool poisoning and capability-confusion patterns, plus the Git MCP server CVE class (CVE-2025-68143 / -68144 / -68145 — commit-message injection, diff injection, path traversal).
- **Cortex** — [tools/llm-attacks/cortex/](tools/llm-attacks/cortex/). Cortex Search index-poisoning bench (rank hijack, payload injection, semantic-model confusion); Cortex Agent + MCP poisoning bench (Chain I — second-order tool calls and agent-executed SQL from poisoned tool output); Cortex Guardrails FP/FN test harness with a structurally-derived public-disclosure payload corpus. Talks to `mock-snowflake` on 9600 and `mock-snowflake-mcp` on 9620.
- **Eval Harness** — [tools/llm-attacks/eval/](tools/llm-attacks/eval/). AgentDojo-format harness paired with a PromptArmor adapter (instruction hierarchy + cosine similarity), an MCPSec adapter (schema validation + capability enforcement), and a defense-benchmark runner.
- **Indirect Injection Corpus** — [tools/llm-attacks/indirect-injection/](tools/llm-attacks/indirect-injection/). Prompt-injection payloads organized by delivery channel — PDF, DOCX, HTML, email (plaintext and HTML), calendar invites, and image alt text — including a `m365_copilot` channel for the Copilot-specific surface.

Expand Down
59 changes: 59 additions & 0 deletions ci/check_snowflake_tools_syntax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""CI gate: every Python module under the Snowflake tooling subtree must
compile cleanly (no syntax errors / no obvious import-time failures).

Compiling is cheap and catches the most common breakage:
- syntax errors after a Python upgrade
- typos in `from x import y` paths

The full import path is not exercised here — that would require the
runtime dependencies, which is the lab harness's job, not CI's.
"""
from __future__ import annotations

import py_compile
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent

SCOPES = [
ROOT / "tools" / "cloud-identity" / "snowflake",
ROOT / "tools" / "lateral-movement" / "snowflake-pivot",
ROOT / "tools" / "llm-attacks" / "cortex",
ROOT / "infra" / "lab" / "mock-snowflake",
ROOT / "infra" / "lab" / "mock-snowflake-mcp",
]


def iter_py(scope: Path):
for path in scope.rglob("*.py"):
if "__pycache__" in path.parts:
continue
yield path


def main() -> int:
errors: list[str] = []
checked = 0
for scope in SCOPES:
if not scope.exists():
print(f"SKIP: {scope.relative_to(ROOT)} not present")
continue
for path in iter_py(scope):
checked += 1
try:
py_compile.compile(str(path), doraise=True)
except py_compile.PyCompileError as exc:
errors.append(f"{path.relative_to(ROOT)}: {exc.msg.strip()}")
if errors:
print("FAIL: snowflake tooling syntax errors:")
for e in errors:
print(f" {e}")
return 1
print(f"OK: snowflake tooling syntax — {checked} module(s)")
return 0


if __name__ == "__main__":
sys.exit(main())
66 changes: 66 additions & 0 deletions detection/snowflake/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Snowflake Detection Pack

Cross-chain index of every Snowflake-related Sigma / KQL / SPL rule in
this repo, mapped to the attack chains documented at
[`docs/analysis/snowflake-platform-attack-surface-2026.md`](../../docs/analysis/snowflake-platform-attack-surface-2026.md).

Rules live next to the offensive PoCs they pair with (per the repo's
detection-pairing convention). This file is the cross-cutting view —
useful when building a SIEM rule set rather than evaluating one tool.

## Per-chain mapping

| Chain | What it does | Detection rules |
|-------|--------------|-----------------|
| A — Credential theft to bulk exfil | UNC5537 replay; bulk `COPY INTO @stage` from a non-MFA / no-network-policy user. | [`bulk_exfil_baseline.yml`](sigma/bulk_exfil_baseline.yml) (new) + bind-param coverage: [`snowflake_bind_param_audit_gap.yml`](../../tools/lateral-movement/snowflake-pivot/detection/sigma/snowflake_bind_param_audit_gap.yml) |
| B — Cortex Code indirect injection | Pre-1.0.25 Cortex Code CLI executes shell-pipe-sh under indirect prompt injection. | [`cortex_code_pre_1_0_25.yml`](sigma/cortex_code_pre_1_0_25.yml) (new) |
| C — Native App Marketplace supply-chain | Installed Native App auto-updates to a manifest with new external integrations. | [`native_app_unexpected_version_bump.yml`](sigma/native_app_unexpected_version_bump.yml) (new) |
| D — Federated-IdP compromise | Forged SAML/OAuth assertion authenticates a high-privileged Snowflake user. | [`federated_login_anomaly.yml`](sigma/federated_login_anomaly.yml) (new) + [`snowflake_keypair_auth_abuse.yml`](../../tools/cloud-identity/snowflake/detection/sigma/snowflake_keypair_auth_abuse.yml) |
| E — Storage Integration cross-cloud pivot | New external stage on an integration outside the bucket allowlist. | [`snowflake_storage_integration_misuse.yml`](../../tools/lateral-movement/snowflake-pivot/detection/sigma/snowflake_storage_integration_misuse.yml) |
| F — Key-pair JWT auth abuse | Stolen RSA private key signs JWT for a service user (post-MFA reality). | [`snowflake_keypair_auth_abuse.yml`](../../tools/cloud-identity/snowflake/detection/sigma/snowflake_keypair_auth_abuse.yml) |
| G — Direct Share / Replication exfil | `ALTER SHARE ADD ACCOUNTS` or replication group with a non-allowlisted target. | [`snowflake_share_creation_unknown_consumer.yml`](../../tools/lateral-movement/snowflake-pivot/detection/sigma/snowflake_share_creation_unknown_consumer.yml) + [`snowflake_replication_group_unknown_target.yml`](../../tools/lateral-movement/snowflake-pivot/detection/sigma/snowflake_replication_group_unknown_target.yml) |
| H — SPCS over-broad EAI egress | Wildcard / OPEN_ANY network rule referenced by an `EXTERNAL ACCESS INTEGRATION`. | Covered by [`snowflake_storage_integration_misuse.yml`](../../tools/lateral-movement/snowflake-pivot/detection/sigma/snowflake_storage_integration_misuse.yml) (classifies EAI rules as critical-impact); pair with cloud-network egress observation per the chain notes. |
| I — Cortex Agent MCP poisoning | Tool output triggers planner-initiated follow-up tool calls or SQL execution. | [`cortex_agent_directive_followup.yml`](../../tools/llm-attacks/cortex/detection/sigma/cortex_agent_directive_followup.yml) + [`cortex_agent_sql_from_tool_output.yml`](../../tools/llm-attacks/cortex/detection/sigma/cortex_agent_sql_from_tool_output.yml) + [`cortex_search_rank_anomaly.yml`](../../tools/llm-attacks/cortex/detection/sigma/cortex_search_rank_anomaly.yml) |

## PAT, SCIM, and Connector secret-leak detections

These do not map to a single chain — they apply across multiple paths
where the same primitive shows up:

- [`snowflake_pat_anomaly.yml`](../../tools/cloud-identity/snowflake/detection/sigma/snowflake_pat_anomaly.yml)
— PAT scope-walk fingerprint + new-source anomaly.
- [`snowflake_scim_role_race.yml`](../../tools/cloud-identity/snowflake/detection/sigma/snowflake_scim_role_race.yml)
— SCIM PATCH `snowflakeRole` without IdP-side correlate.
- [`connector_secret_leak_in_logs.yml`](sigma/connector_secret_leak_in_logs.yml)
(new) — connector debug logs containing master keys / session tokens
(CVE-2025-27496 / CVE-2025-46329 class).

## SIEM-side cross-cutting hunts

Microsoft Sentinel (KQL):

- [`tools/cloud-identity/snowflake/detection/kql/snowflake_identity_hunt.kql`](../../tools/cloud-identity/snowflake/detection/kql/snowflake_identity_hunt.kql)
- [`tools/lateral-movement/snowflake-pivot/detection/kql/snowflake_pivot_hunt.kql`](../../tools/lateral-movement/snowflake-pivot/detection/kql/snowflake_pivot_hunt.kql)
- [`tools/llm-attacks/cortex/detection/kql/cortex_hunt.kql`](../../tools/llm-attacks/cortex/detection/kql/cortex_hunt.kql)
- [`kql/streaming_query_history_pipeline.kql`](kql/streaming_query_history_pipeline.kql) (new — streaming-ingest pattern)

Splunk (SPL):

- [`tools/cloud-identity/snowflake/detection/spl/snowflake_identity_hunt.spl`](../../tools/cloud-identity/snowflake/detection/spl/snowflake_identity_hunt.spl)
- [`tools/lateral-movement/snowflake-pivot/detection/spl/snowflake_pivot_hunt.spl`](../../tools/lateral-movement/snowflake-pivot/detection/spl/snowflake_pivot_hunt.spl)
- [`tools/llm-attacks/cortex/detection/spl/cortex_hunt.spl`](../../tools/llm-attacks/cortex/detection/spl/cortex_hunt.spl)
- [`spl/connector_secret_leak_regex.spl`](spl/connector_secret_leak_regex.spl) (new — debug-log secret-cohort regex)

## Streaming ingest

`SNOWFLAKE.ACCOUNT_USAGE` views have up to ~45m latency. For real-time
detection on the chains above:

- Ingest `INFORMATION_SCHEMA.QUERY_HISTORY_BY_USER` on a 60-second
poll instead of waiting on ACCOUNT_USAGE.
- Where Snowflake Trail is enabled, prefer the Trail event stream —
see the field-level mapping table in the analysis companion.
- The
[`kql/streaming_query_history_pipeline.kql`](kql/streaming_query_history_pipeline.kql)
hunt is the Sentinel-side projection assuming a Kafka or
Event-Hubs-fronted ingest.
32 changes: 32 additions & 0 deletions detection/snowflake/kql/streaming_query_history_pipeline.kql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Streaming QUERY_HISTORY → real-time alerting
//
// Pattern: poll INFORMATION_SCHEMA.QUERY_HISTORY_BY_USER on a 60-second
// cadence (no propagation latency) → push to an event hub / Kafka
// topic → ingest into Sentinel under `Snowflake_QueryHistoryStream_CL`.
//
// Expected end-to-end latency: ~90 seconds (poll interval + Kafka +
// Sentinel ingestion). Compare to the ~45-minute ACCOUNT_USAGE
// baseline.
//
// This KQL hunts streaming data for the union of chains where minutes
// matter: an active exfil session that the SOC wants to terminate
// inside the session window, not after the fact.

let lookback = ago(15m);

Snowflake_QueryHistoryStream_CL
| where TimeGenerated > lookback
| where
(QueryType_s startswith "COPY" and QueryText_s contains "@" and
BytesWrittenToResult_d > 104857600)
or
(QueryText_s contains "ALTER SHARE" and QueryText_s contains "ADD ACCOUNTS")
or
(QueryType_s startswith "CREATE_REPLICATION_GROUP")
or
(QueryText_s contains "ALTER NETWORK POLICY" and QueryText_s contains "0.0.0.0/0")
| project
TimeGenerated, UserName_s, RoleName_s, AuthenticationMethod_s,
ClientIp_s, SessionId_s, QueryType_s, QueryText_s,
BytesWrittenToResult_d
| order by TimeGenerated desc;
46 changes: 46 additions & 0 deletions detection/snowflake/sigma/bulk_exfil_baseline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
title: Snowflake — Bulk COPY INTO External Stage (Chain A baseline)
id: 8e7d2c1f-3b4a-4e5c-8f0a-1b2c3d4e5f6a
status: experimental
description: |
Baseline detection for Chain A (UNC5537 replay). Fires when a session
emits a high-volume `COPY INTO @<external_stage>` whose external-stage
URL is not on the approved-exfil-stage watchlist.

Designed as a coarse alarm that surfaces *any* unusual bulk exfil; pair
with `snowflake_bind_param_audit_gap.yml` (in the snowflake-pivot tool
directory) for sessions where bind parameters degrade the audit signal.
references:
- https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion
- https://docs.snowflake.com/en/sql-reference/account-usage/query_history
author: security-research
date: 2026-05-15
tags:
- attack.exfiltration
- attack.t1567.002
logsource:
product: snowflake
service: query_history
detection:
copy_to_external:
query_type|startswith: 'COPY'
query_text|contains: '@'
external_stage_not_in_watchlist:
external_stage_in_watchlist: false
large_result:
bytes_written_to_result|gte: 104857600 # 100 MB
condition: copy_to_external and external_stage_not_in_watchlist and large_result
fields:
- event_timestamp
- user_name
- role_name
- session_id
- query_text
- bytes_written_to_result
- rows_produced
falsepositives:
- Legitimate first-run of a new pipeline that loads from / unloads to
a freshly-created external stage. Maintain a 24h grace + on-call
notification.
- Bulk export jobs run during quarter close that are not normally on
the watchlist; tag the approved stages instead of suppressing.
level: high
Loading
Loading