From 22f3c37457b9830ceaf427b14b67aad5f014d23f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 13:26:12 +0000 Subject: [PATCH 1/2] fix(corpus): retarget AS-REP detection + add GCP parity pairs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acts on the weekly corpus-review findings (issue #50): - asrep-probing-4771: key the detection on the real roast artifact — a successful 4768 with pre-auth type 0 (RC4 0x17) — and demote the 4771 0x18 burst to a secondary Kerbrute enumeration/spray tell. Previously the pair only saw the collateral probing, not the AS-REP its red mate emits. - Add two GCP pairs for parity with the other big-three clouds: IAM policy backdoor (T1098, setIamPolicy) + its SetIamPolicy audit detection, and Cloud Audit log tamper (T1562.008, DeleteSink/auditConfigs strip) + its self-witnessing Admin Activity detection. - Add an unpaired Discovery recon entry gcp-enum-recon (T1580/T1526/T1069.003), mirroring the unpaired smb-enum-nxc. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_013hEgodLmdYjrEGBLo5wdiQ --- CHANGELOG.md | 21 +++++++++++++++ entries/blue/asrep-probing-4771.md | 28 +++++++++++++++----- entries/blue/gcp-audit-log-tamper-audit.md | 29 +++++++++++++++++++++ entries/blue/gcp-iam-policy-audit.md | 30 ++++++++++++++++++++++ entries/red/gcp-audit-log-disable.md | 24 +++++++++++++++++ entries/red/gcp-enum-recon.md | 26 +++++++++++++++++++ entries/red/gcp-iam-policy-backdoor.md | 26 +++++++++++++++++++ 7 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 entries/blue/gcp-audit-log-tamper-audit.md create mode 100644 entries/blue/gcp-iam-policy-audit.md create mode 100644 entries/red/gcp-audit-log-disable.md create mode 100644 entries/red/gcp-enum-recon.md create mode 100644 entries/red/gcp-iam-policy-backdoor.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 99ee866..25be285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,27 @@ GitHub Release; `sync-fanout.yml` then opens the Kali sync PR. ## [Unreleased] +### Added + +- **GCP parity — 2 new red↔blue pairs (+4 entries) and a recon entry (+1).** Brings + GCP up from a single pair to rough parity with the other big-three clouds. + **Persistence** (`T1098`): IAM policy backdoor — `setIamPolicy` binding a rogue + principal — detected on the `SetIamPolicy` `ADD` binding delta in Cloud Audit + Logs. **Defense Evasion** (`T1562.008`): Cloud Audit log tamper — `DeleteSink` / + `auditConfigs` strip — detected via the self-witnessing Admin Activity events + (plus a Data Access gap monitor). Also adds an unpaired **Discovery** + (`T1580`/`T1526`/`T1069.003`) `gcp-enum-recon` entry (projects / Asset Inventory / + IAM blast-radius mapping), mirroring the unpaired on-prem `smb-enum-nxc`. + +### Changed + +- **`asrep-probing-4771` retargeted to the real AS-REP roast artifact.** The + detection now keys primarily on a *successful* `4768` with pre-authentication + type 0 (RC4 `0x17`) — the roastable AS-REP its red mate actually emits — and keeps + the `4771 0x18` one-source-many-accounts burst as a secondary Kerbrute + enumeration/spray tell. Previously it only saw the collateral `4771` probing, not + the roast itself. + ## [v2.3.0] - 2026-07-10 ### Added diff --git a/entries/blue/asrep-probing-4771.md b/entries/blue/asrep-probing-4771.md index 429985c..ab7d140 100644 --- a/entries/blue/asrep-probing-4771.md +++ b/entries/blue/asrep-probing-4771.md @@ -1,8 +1,8 @@ --- id: asrep-probing-4771 -title: Detect AS-REP / Kerbrute probing (4771 0x18) +title: Detect AS-REP roast (4768 no-preauth) + Kerbrute probing (4771) detection: splunk-spl -event_ids: [4771] +event_ids: [4768, 4771] attack: tactic: TA0006 techniques: [T1558.004] @@ -10,10 +10,26 @@ source: TrustedSec "Actionable Purple Teaming" (BH USA 2023) pair: asreproast-getnpusers --- -One client address generating Kerberos pre-auth failures (`4771`, failure code -`0x18`) across many distinct accounts is the spray/roast tell — a real user -fat-fingers their own name, not five-plus others. Tune the threshold to the -environment. +Detect on the artifact, not the collateral. The roastable AS-REP is a +*successful* `4768` TGT request with **pre-authentication type 0** (no pre-auth) +for a non-machine account — that is the account `GetNPUsers`/`--asreproast` +actually harvests, and the ticket is issued under the account's long-term key +(RC4 `0x17`), exactly what `hashcat -m 18200` cracks. A normal account pre-auths +with type 2 (encrypted timestamp), so type 0 on a user is the tell. The +one-source-to-many-accounts `4771 0x18` burst is a *secondary* enumeration tell: +it fires on wrong-password pre-auth failures against pre-auth-**required** +accounts (Kerbrute enum / spraying), never on the roast itself — so keep it, but +alert on the `4768` first. + +```spl +index=main EventCode=4768 Pre_Authentication_Type=0 Account_Name!="*$" + Ticket_Encryption_Type=0x17 +| stats count values(Account_Name) AS Accounts by Client_Address +| sort -count +``` + +Secondary tell — Kerbrute enumeration / spray burst (one source, many accounts, +wrong-password pre-auth failures). Tune the threshold to the environment: ```spl index=main EventCode=4771 Failure_Code="0x18" diff --git a/entries/blue/gcp-audit-log-tamper-audit.md b/entries/blue/gcp-audit-log-tamper-audit.md new file mode 100644 index 0000000..b47f0e8 --- /dev/null +++ b/entries/blue/gcp-audit-log-tamper-audit.md @@ -0,0 +1,29 @@ +--- +id: gcp-audit-log-tamper-audit +title: Detect audit-log tamper (GCP, DeleteSink / auditConfig strip) +detection: gcp-logging +event_ids: [] +attack: + tactic: TA0005 + techniques: [T1562.008] +source: GCP logging abuse (blind Data Access telemetry) +pair: gcp-audit-log-disable +--- + +The tamper is self-witnessing: sink and auditConfig changes are Admin Activity +events, which are always-on and immutable, so the act of going dark is itself +logged. Alert on `DeleteSink`/`UpdateSink`, and on any `SetIamPolicy` that removes +or narrows `auditConfigs` (a `REMOVE` delta on the audit config). Pair it with a +gap monitor — an unexpected drop-to-zero in a project's Data Access log volume is +the corroborating signal when the config change slips through. + +GCP Cloud Audit Logs telemetry (native Cloud Logging filter below; also queryable +as Sentinel `GCPAuditLogs`), companion-only — `PURPLE-TEAM.md` is on-prem Windows. +Triage by `protoPayload.authenticationInfo.principalEmail` (the actor) and +`protoPayload.resourceName` (the sink or project touched). + +```text +logName=~"cloudaudit.googleapis.com%2Factivity" +(protoPayload.methodName=~"DeleteSink$" OR protoPayload.methodName=~"UpdateSink$" + OR protoPayload.methodName=~"SetIamPolicy$") +``` diff --git a/entries/blue/gcp-iam-policy-audit.md b/entries/blue/gcp-iam-policy-audit.md new file mode 100644 index 0000000..a2b6a6e --- /dev/null +++ b/entries/blue/gcp-iam-policy-audit.md @@ -0,0 +1,30 @@ +--- +id: gcp-iam-policy-audit +title: Detect IAM policy backdoor (GCP audit, SetIamPolicy binding ADD) +detection: gcp-logging +event_ids: [] +attack: + tactic: TA0003 + techniques: [T1098] +source: GCP IAM abuse (resource IAM policy binding persistence) +pair: gcp-iam-policy-backdoor +--- + +Every IAM grant lands in Cloud Audit Logs (Admin Activity) as a `SetIamPolicy` +call whose `serviceData.policyDelta.bindingDeltas` carries the `ADD` action, the +role, and the member. Alert on additions of sensitive roles +(`roles/owner`, `roles/editor`, `*Admin`) or grants to unexpected/external +principals — and treat a binding whose member is `allUsers`/`allAuthenticatedUsers` +as an immediate, standalone finding. + +GCP Cloud Audit Logs telemetry (native Cloud Logging filter below; also queryable +as Sentinel `GCPAuditLogs`), companion-only — `PURPLE-TEAM.md` is on-prem Windows. +Triage each hit by `protoPayload.authenticationInfo.principalEmail` (the actor) +and the added `member`/`role`. + +```text +logName=~"cloudaudit.googleapis.com%2Factivity" +protoPayload.methodName=~"SetIamPolicy$" +protoPayload.serviceData.policyDelta.bindingDeltas.action="ADD" +protoPayload.serviceData.policyDelta.bindingDeltas.role=("roles/owner" OR "roles/editor" OR "roles/resourcemanager.projectIamAdmin") +``` diff --git a/entries/red/gcp-audit-log-disable.md b/entries/red/gcp-audit-log-disable.md new file mode 100644 index 0000000..6deb090 --- /dev/null +++ b/entries/red/gcp-audit-log-disable.md @@ -0,0 +1,24 @@ +--- +id: gcp-audit-log-disable +title: GCP Cloud Audit log tamper (delete sink / strip auditConfigs) +section: GCP / cloud IAM +phase: Defense Evasion +attack: + tactic: TA0005 + techniques: [T1562.008] +platform: [cloud] +source: GCP logging abuse (blind Data Access telemetry) +pair: gcp-audit-log-tamper-audit +--- + +Blind the defenders before the noisy work. Delete or redirect the log sink that +exports to the SIEM, or strip the project's `auditConfigs` so Data Access logs +stop flowing — either way the analytics that key on those events go dark. Note +the ceiling: Admin Activity logging cannot be disabled and records the tamper +itself, so this buys time, not silence. +(Cloud — no slots.) + +```sh +gcloud logging sinks delete --project= +gcloud projects set-iam-policy policy-no-auditconfigs.json +``` diff --git a/entries/red/gcp-enum-recon.md b/entries/red/gcp-enum-recon.md new file mode 100644 index 0000000..faed60b --- /dev/null +++ b/entries/red/gcp-enum-recon.md @@ -0,0 +1,26 @@ +--- +id: gcp-enum-recon +title: GCP enumeration (projects, assets, IAM — recon) +section: GCP / cloud IAM +phase: Discovery +attack: + tactic: TA0007 + techniques: [T1580, T1526, T1069.003] +platform: [cloud] +source: GCP post-access recon (blast-radius mapping) +pair: null +--- + +Once a token or service-account key lands, map the blast radius before touching +anything. List every reachable project, sweep all resources with the Asset +Inventory API, then read the IAM policy to learn who holds what — the shortest +path from "a credential" to "the accounts worth backdooring." Read-only and +low-signal on its own (Data Access telemetry, often unmonitored), which is why it +ships unpaired. +(Pure recon — no paired blue detection.) + +```sh +gcloud projects list +gcloud asset search-all-resources --scope=projects/ +gcloud projects get-iam-policy --format=json +``` diff --git a/entries/red/gcp-iam-policy-backdoor.md b/entries/red/gcp-iam-policy-backdoor.md new file mode 100644 index 0000000..0318bb5 --- /dev/null +++ b/entries/red/gcp-iam-policy-backdoor.md @@ -0,0 +1,26 @@ +--- +id: gcp-iam-policy-backdoor +title: GCP IAM policy backdoor (setIamPolicy → rogue principal) +section: GCP / cloud IAM +phase: Persistence +attack: + tactic: TA0003 + techniques: [T1098] +platform: [cloud] +source: GCP IAM abuse (resource IAM policy binding persistence) +pair: gcp-iam-policy-audit +--- + +With `resourcemanager.projects.setIamPolicy` (any Owner/`*.admin` role), bind an +attacker-controlled principal straight into the project's IAM policy — a rogue +service account, a personal Google identity, or `allUsers`. Granting +`roles/owner` (or the quieter `roles/resourcemanager.projectIamAdmin`) is durable, +survives SA-key rotation, and blends into normal IAM churn. Prefer an existing +low-noise SA as the member so the grant looks routine. +(Cloud — no slots.) + +```sh +gcloud projects add-iam-policy-binding \ + --member='serviceAccount:@.iam.gserviceaccount.com' \ + --role='roles/owner' +``` From b3de4d5b51bc3d72ee6218e69e12ef86495e0504 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 13:34:06 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(corpus):=20address=20review=20=E2=80=94?= =?UTF-8?q?=20broaden=20AS-REP=20etype,=20scope=20GCP=20tamper=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From Copilot review on #51: - asrep-probing-4771: drop the Ticket_Encryption_Type=0x17 constraint from the primary 4768 clause. The AS-REP etype is negotiated (RC4 in RC4-enabled domains, AES where RC4 is disabled), so pinning 0x17 misses AES-only roasts. The invariant is pre-auth type 0 on a user account; key on that. Prose and CHANGELOG softened to "RC4 or AES" accordingly. - gcp-audit-log-tamper-audit: restrict the SetIamPolicy branch to auditConfigDeltas REMOVE so it detects audit-config tampering specifically, instead of matching every IAM grant (noisy, and overlapping the gcp-iam-policy-audit detection). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_013hEgodLmdYjrEGBLo5wdiQ --- CHANGELOG.md | 4 +++- entries/blue/asrep-probing-4771.md | 17 ++++++++++------- entries/blue/gcp-audit-log-tamper-audit.md | 3 ++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25be285..f42d45b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,9 @@ GitHub Release; `sync-fanout.yml` then opens the Kali sync PR. - **`asrep-probing-4771` retargeted to the real AS-REP roast artifact.** The detection now keys primarily on a *successful* `4768` with pre-authentication - type 0 (RC4 `0x17`) — the roastable AS-REP its red mate actually emits — and keeps + type 0 (the AS-REP etype is negotiated — often RC4 `0x17`, AES where RC4 is + disabled — so the clause keys on the type-0 invariant, not the cipher) — the + roastable AS-REP its red mate actually emits — and keeps the `4771 0x18` one-source-many-accounts burst as a secondary Kerbrute enumeration/spray tell. Previously it only saw the collateral `4771` probing, not the roast itself. diff --git a/entries/blue/asrep-probing-4771.md b/entries/blue/asrep-probing-4771.md index ab7d140..4924898 100644 --- a/entries/blue/asrep-probing-4771.md +++ b/entries/blue/asrep-probing-4771.md @@ -10,12 +10,16 @@ source: TrustedSec "Actionable Purple Teaming" (BH USA 2023) pair: asreproast-getnpusers --- -Detect on the artifact, not the collateral. The roastable AS-REP is a -*successful* `4768` TGT request with **pre-authentication type 0** (no pre-auth) -for a non-machine account — that is the account `GetNPUsers`/`--asreproast` -actually harvests, and the ticket is issued under the account's long-term key -(RC4 `0x17`), exactly what `hashcat -m 18200` cracks. A normal account pre-auths -with type 2 (encrypted timestamp), so type 0 on a user is the tell. The +Detect on the invariant, not the IOC. The roastable AS-REP is a *successful* +`4768` TGT request with **pre-authentication type 0** (no pre-auth) for a +non-machine account — that is the account `GetNPUsers`/`--asreproast` actually +harvests. The AS-REP is issued under the account's long-term key — RC4 (`0x17`) +where it's enabled, AES (`0x11`/`0x12`) in RC4-disabled domains — and cracked +offline (`hashcat -m 18200` for the RC4 case). Unlike Kerberoasting the attacker +doesn't force the etype, so the *invariant* is the type-0 pre-auth on a user, not +the negotiated cipher — key on it directly and don't constrain the encryption +type, or AES-only domains slip through. A normal account pre-auths with type 2 +(encrypted timestamp), so type 0 on a user is the tell. The one-source-to-many-accounts `4771 0x18` burst is a *secondary* enumeration tell: it fires on wrong-password pre-auth failures against pre-auth-**required** accounts (Kerbrute enum / spraying), never on the roast itself — so keep it, but @@ -23,7 +27,6 @@ alert on the `4768` first. ```spl index=main EventCode=4768 Pre_Authentication_Type=0 Account_Name!="*$" - Ticket_Encryption_Type=0x17 | stats count values(Account_Name) AS Accounts by Client_Address | sort -count ``` diff --git a/entries/blue/gcp-audit-log-tamper-audit.md b/entries/blue/gcp-audit-log-tamper-audit.md index b47f0e8..a786d29 100644 --- a/entries/blue/gcp-audit-log-tamper-audit.md +++ b/entries/blue/gcp-audit-log-tamper-audit.md @@ -25,5 +25,6 @@ Triage by `protoPayload.authenticationInfo.principalEmail` (the actor) and ```text logName=~"cloudaudit.googleapis.com%2Factivity" (protoPayload.methodName=~"DeleteSink$" OR protoPayload.methodName=~"UpdateSink$" - OR protoPayload.methodName=~"SetIamPolicy$") + OR (protoPayload.methodName=~"SetIamPolicy$" + AND protoPayload.serviceData.policyDelta.auditConfigDeltas.action="REMOVE")) ```