Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 6 additions & 3 deletions offensive/companion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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, GitHub Actions + GitLab + Jenkins CI/CD, the Harbor container
registry, HashiCorp Vault, and Terraform Cloud:

| Attack (red) | Detection (blue) | ATT&CK |
| --------------------------------- | ----------------------------------------------------- | --------- |
Expand Down Expand Up @@ -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`/`/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
Expand Down
25 changes: 25 additions & 0 deletions offensive/companion/entries/blue/jenkins-api-token-audit.md
Original file line number Diff line number Diff line change
@@ -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 "generateNewToken"
| table _time, user, uri
Comment thread
Copilot marked this conversation as resolved.
Outdated
```
25 changes: 25 additions & 0 deletions offensive/companion/entries/blue/jenkins-job-backdoor-audit.md
Original file line number Diff line number Diff line change
@@ -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/<name>/configSubmit` (reconfigure) are the invariants.
Comment thread
Copilot marked this conversation as resolved.
Outdated
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 "/configSubmit")
Comment thread
Gerrrt marked this conversation as resolved.
Outdated
| table _time, user, uri
```
26 changes: 26 additions & 0 deletions offensive/companion/entries/blue/jenkins-script-console-audit.md
Original file line number Diff line number Diff line change
@@ -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
```
26 changes: 26 additions & 0 deletions offensive/companion/entries/red/jenkins-api-token.md
Original file line number Diff line number Diff line change
@@ -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 <user>:<pass> -X POST \
"https://<jenkins>/user/<user>/descriptorByName/jenkins.security.ApiTokenProperty/generateNewToken" \
--data "newTokenName=ci-cache"
```
25 changes: 25 additions & 0 deletions offensive/companion/entries/red/jenkins-job-backdoor.md
Original file line number Diff line number Diff line change
@@ -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/<name>/configSubmit` — both logged by the Audit
Trail plugin. (CI controller — no slots.)
Comment thread
Copilot marked this conversation as resolved.
Outdated

```sh
# create a job whose build step runs attacker code (config.xml carries the payload)
curl -s -u <user>:<api-token> -H "Content-Type: application/xml" --data-binary @config.xml \
"https://<jenkins>/createItem?name=ci-cache"
```
25 changes: 25 additions & 0 deletions offensive/companion/entries/red/jenkins-script-console.md
Original file line number Diff line number Diff line change
@@ -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 <user>:<api-token> --data-urlencode 'script=println "id".execute().text' \
"https://<jenkins>/scriptText"
```
Loading