Hunit Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 3 min read
Hunit exposes a "My Haikus" Spring Boot application whose /api/user/ endpoint dumps every user's credentials in plaintext. One of those accounts, an admin, has SSH access directly. Root comes from a cron job that pulls a bare git repository and executes a script from it as root, and the git user's SSH key is left world-readable.
Reconnaissance
Nmap
Scan all ports to find the full service list, since SSH is not on its default port.
PORT STATE SERVICE 8080/tcp open http-proxy 12445/tcp open netbios-ssn 18030/tcp open http 43022/tcp open ssh
Explain command
| -p- | Scan all 65535 TCP ports. |
| -sCV | Run the default scripts and probe service versions. |
Four non-standard ports: a web app on 8080, Samba on 12445, a second web server on 18030, and SSH on 43022. The app on 8080 is the obvious target.
Web enumeration
Fingerprint the application on port 8080.
[200 OK] Title[My Haikus], JQuery
My Haikus is a haiku blog built with jQuery and an HTML5 UP template, backed by a Spring Boot API. Spring Boot apps commonly expose REST endpoints under /api/, so probe for one.
Exploitation
Plaintext credential leak via /api/user/
Request the endpoint with a trailing slash, since /api/user without one returns 404.
[
{"role":"Editor","login":"rjackson","password":"<snip>"},
{"role":"Editor","login":"jsanchez","password":"<snip>"},
{"role":"Admin","login":"dademola","password":"$DADEMOLA_PASSWORD"},
{"role":"Editor","login":"jwinters","password":"<snip>"},
{"role":"Editor","login":"jvargas","password":"<snip>"}
]
The endpoint returns every user's role, login and password in plaintext, including the admin account dademola. SSH is reachable on the non-standard port found during the scan.
dademola@hunit:~$ id uid=1001(dademola) gid=1001(dademola) groups=1001(dademola)
Shell as dademola.
Privilege Escalation
Git repository cron job
A backup of the crontab reveals two root cron jobs tied to a bare git repository.
*/3 * * * * /root/git-server/backups.sh */2 * * * * /root/pull.sh
pull.sh pulls updates into the working copy of the /git-server bare repository every 2 minutes, and backups.sh runs the pulled script every 3 minutes, both as root. The git user's SSH key is world-readable.
-rwxr-xr-x 1 root root 2590 Nov 5 2020 id_rsa
Clone the repository with that key, replace backups.sh with a payload that sets the SUID bit on bash, and push the change.
Enumerating objects: 4, done. To 127.0.0.1:/git-server a1b2c3d..e4f5a6b master -> master
Git requires user.email and user.name before it will commit, otherwise the commit silently fails and push reports nothing to do. Wait for the cron job to pull and execute the modified script, then check for the SUID bit.
-rwsr-sr-x 1 root root 1037528 Jan 1 2020 /bin/bash
The cron job ran as root and set the SUID bit. Spawn bash with -p to keep the elevated privileges.
bash-5.0# id uid=1001(dademola) gid=1001(dademola) euid=0(root) egid=0(root)
Effective root.