diff --git a/offensive/companion/README.md b/offensive/companion/README.md index 7081eac..34232e8 100644 --- a/offensive/companion/README.md +++ b/offensive/companion/README.md @@ -84,11 +84,11 @@ No mainstream tool ships attacks paired with the telemetry they trip. ## Corpus -50 paired concepts + 1 unpaired recon entry (SMB enum), spanning Credential +53 paired concepts + 1 unpaired recon entry (SMB enum), spanning Credential Access, Privilege Escalation, Lateral Movement, Persistence, Execution, Defense Evasion, and Discovery — on-prem AD, a multi-cloud slice (Entra/M365, AWS, GCP), -Kubernetes, Okta, GitHub Actions + GitLab CI/CD, the Harbor container registry, -HashiCorp Vault, and Terraform Cloud: +Kubernetes, Okta, CI/CD (GitHub Actions, GitLab, Jenkins), the Harbor container +registry, HashiCorp Vault, and Terraform Cloud: | Attack (red) | Detection (blue) | ATT&CK | | --------------------------------- | ----------------------------------------------------- | --------- | @@ -142,6 +142,9 @@ HashiCorp Vault, and Terraform Cloud: | Rogue agent pool (Terraform) | audit `agent_pool` `create` _(IaC)_ | T1543 | | Org/team token backdoor (Terraform) | audit `authentication_token` `create` _(IaC)_ | T1098 | | Variable injection (Terraform) | audit `variable` `create`/`update` _(IaC)_ | T1072 | +| Script Console RCE (Jenkins) | audit `/script`/`/scriptText` request _(CI)_ | T1059 | +| User API token backdoor (Jenkins) | audit `generateNewToken` request _(CI)_ | T1098 | +| Job/pipeline backdoor (Jenkins) | audit `/createItem`/`/job//configSubmit` request _(CI)_ | T1072 | 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/offensive/companion/entries/blue/jenkins-api-token-audit.md b/offensive/companion/entries/blue/jenkins-api-token-audit.md new file mode 100644 index 0000000..68ef9ab --- /dev/null +++ b/offensive/companion/entries/blue/jenkins-api-token-audit.md @@ -0,0 +1,25 @@ +--- +id: jenkins-api-token-audit +title: Detect API token creation (Jenkins audit log) +detection: jenkins-audit-log +event_ids: [] +attack: + tactic: TA0003 + techniques: [T1098] +source: Jenkins persistence (user API token) +pair: jenkins-api-token +--- + +A request to `ApiTokenProperty/generateNewToken` is the invariant. API tokens are minted +rarely, so one generated by an unexpected actor — or against a privileged/service account, +or during an incident — is the persistence tell. Reconcile new tokens against known CI +integrations, prefer short-lived tokens, and alert on generation for accounts that don't +normally hold API tokens. + +Jenkins Audit Trail plugin telemetry, companion-only — `PURPLE-TEAM.md` is on-prem +Windows. + +```spl +index=jenkins sourcetype=jenkins:audit "ApiTokenProperty/generateNewToken" +| table _time, user, uri +``` diff --git a/offensive/companion/entries/blue/jenkins-job-backdoor-audit.md b/offensive/companion/entries/blue/jenkins-job-backdoor-audit.md new file mode 100644 index 0000000..27312fe --- /dev/null +++ b/offensive/companion/entries/blue/jenkins-job-backdoor-audit.md @@ -0,0 +1,25 @@ +--- +id: jenkins-job-backdoor-audit +title: Detect job create/reconfigure (Jenkins audit log) +detection: jenkins-audit-log +event_ids: [] +attack: + tactic: TA0002 + techniques: [T1072] +source: Jenkins abuse (malicious job / pipeline) +pair: jenkins-job-backdoor +--- + +`/createItem` (new job) and `/job//configSubmit` (reconfigure) are the invariants. +Job changes are routine in active shops, so the signal is one by an unexpected actor, on +a sensitive/privileged job, outside config-as-code (JCasC/pipeline-in-SCM), or immediately +followed by a build. Prefer pipelines defined in version-controlled `Jenkinsfile`s so +config drift is reviewable, and alert on UI-side job edits that bypass that path. + +Jenkins Audit Trail plugin telemetry, companion-only — `PURPLE-TEAM.md` is on-prem +Windows. + +```spl +index=jenkins sourcetype=jenkins:audit ("/createItem" OR uri="*/job/*/configSubmit") +| table _time, user, uri +``` diff --git a/offensive/companion/entries/blue/jenkins-script-console-audit.md b/offensive/companion/entries/blue/jenkins-script-console-audit.md new file mode 100644 index 0000000..42fb235 --- /dev/null +++ b/offensive/companion/entries/blue/jenkins-script-console-audit.md @@ -0,0 +1,26 @@ +--- +id: jenkins-script-console-audit +title: Detect Script Console use (Jenkins audit log) +detection: jenkins-audit-log +event_ids: [] +attack: + tactic: TA0002 + techniques: [T1059] +source: Jenkins abuse (Groovy Script Console) +pair: jenkins-script-console +--- + +A request to `/script` or `/scriptText` is the invariant. The Script Console is +admin-only and rarely used legitimately (mostly break-glass), so *any* hit — especially +outside a change window, from a service account, or right before a credential-store read +— is high-signal for controller RCE / credential theft. Alert in real time, scope +`RunScripts`/`Administer` tightly, and pair with process-exec telemetry on the controller +host. + +Jenkins Audit Trail plugin telemetry, companion-only — `PURPLE-TEAM.md` is on-prem +Windows. + +```spl +index=jenkins sourcetype=jenkins:audit ("/scriptText" OR "/script") +| table _time, user, uri, node +``` diff --git a/offensive/companion/entries/red/jenkins-api-token.md b/offensive/companion/entries/red/jenkins-api-token.md new file mode 100644 index 0000000..69b123f --- /dev/null +++ b/offensive/companion/entries/red/jenkins-api-token.md @@ -0,0 +1,26 @@ +--- +id: jenkins-api-token +title: Jenkins user API token (durable non-interactive access) +section: Jenkins / CI/CD +phase: Persistence +attack: + tactic: TA0003 + techniques: [T1098] +platform: [jenkins] +source: Jenkins persistence (user API token) +pair: jenkins-api-token-audit +--- + +Mint an **API token** for a user (your own, or a higher-privileged one you've +compromised): a long-lived, non-interactive credential that drives the Jenkins REST API +and CLI, keeps working after the account's password/session is reset, and blends in among +CI automation. Generating one hits +`.../descriptorByName/jenkins.security.ApiTokenProperty/generateNewToken`, which the +Audit Trail plugin records. (CI controller — no slots.) + +```sh +# mint an API token for durable API + CLI access +curl -s -u : -X POST \ + "https:///user//descriptorByName/jenkins.security.ApiTokenProperty/generateNewToken" \ + --data "newTokenName=ci-cache" +``` diff --git a/offensive/companion/entries/red/jenkins-job-backdoor.md b/offensive/companion/entries/red/jenkins-job-backdoor.md new file mode 100644 index 0000000..9815ec7 --- /dev/null +++ b/offensive/companion/entries/red/jenkins-job-backdoor.md @@ -0,0 +1,25 @@ +--- +id: jenkins-job-backdoor +title: Jenkins job/pipeline backdoor (run code on controller + agents) +section: Jenkins / CI/CD +phase: Execution +attack: + tactic: TA0002 + techniques: [T1072] +platform: [jenkins] +source: Jenkins abuse (malicious job / pipeline) +pair: jenkins-job-backdoor-audit +--- + +Jenkins is a deployment tool — abuse it to run code across the estate. Create a job (or +reconfigure one) whose build step runs your payload, then let it execute on the +controller or fan out to build **agents** (harvesting their credentials and reaching the +networks they can). A cron/SCM trigger makes it recurring. Creating a job hits +`/createItem`; reconfiguring one hits `/job//configSubmit` — both logged by the Audit +Trail plugin. (CI controller — no slots.) + +```sh +# create a job whose build step runs attacker code (config.xml carries the payload) +curl -s -u : -H "Content-Type: application/xml" --data-binary @config.xml \ + "https:///createItem?name=ci-cache" +``` diff --git a/offensive/companion/entries/red/jenkins-script-console.md b/offensive/companion/entries/red/jenkins-script-console.md new file mode 100644 index 0000000..b1c1430 --- /dev/null +++ b/offensive/companion/entries/red/jenkins-script-console.md @@ -0,0 +1,25 @@ +--- +id: jenkins-script-console +title: Jenkins Script Console RCE (controller code exec + cred dump) +section: Jenkins / CI/CD +phase: Execution +attack: + tactic: TA0002 + techniques: [T1059] +platform: [jenkins] +source: Jenkins abuse (Groovy Script Console) +pair: jenkins-script-console-audit +--- + +The iconic Jenkins move: with **Overall/Administer** (or `RunScripts`), POST Groovy to +the controller's Script Console and get instant code execution *as the Jenkins process* — +run OS commands, and decrypt every stored credential in memory +(`com.cloudbees.plugins.credentials.SystemCredentialsProvider`) in one request. `/script` +is the form, `/scriptText` the API. Both are logged by the Audit Trail plugin. (CI +controller — no on-host target slot.) + +```sh +# run Groovy on the controller (RCE; swap in the credentials-dump one-liner to loot creds) +curl -s -u : --data-urlencode 'script=println "id".execute().text' \ + "https:///scriptText" +```