$ nmap -p- --min-rate 5000 10.129.227.207
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-10 09:28 EDT
Nmap scan report for 10.129.227.207
Host is up (0.0087s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy
Red Panda Search SSTI
The page was some kind of search engine:
When we search for something, it shows our result back on the screen:
There are a few possibilities in my mind:
XSS -> But there's no users present to 'view' our requests
SQL Injection -> Might have a database present, but not typical for non-logins.
SSTI
When we use ${7*7}, we get a unique error:
It seems that some characters are being blocked. We can fuzz this using wfuzz.
$ wfuzz -w /usr/share/seclists/Fuzzing/alphanum-case-extra.txt -u http://10.129.227.207:8080/search -d name=FUZZ --sl=0 /usr/lib/python3/dist-packages/wfuzz/__init__.p:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.129.227.207:8080/search
Total requests: 95
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000005: 400 0 L 2 W 110 Ch "%"
000000011: 500 0 L 3 W 120 Ch "+"
000000009: 500 0 L 3 W 120 Ch ")"
000000060: 500 0 L 3 W 120 Ch "\"
000000093: 500 0 L 3 W 120 Ch "}"
000000091: 500 0 L 3 W 120 Ch "{"
it seems that some of the characters here straight up cause crashes. When we filter for the word banned, then we see some more characters:
$ wfuzz -w /usr/share/seclists/Fuzzing/alphanum-case-extra.txt -u http://10.129.227.207:8080/search -d name=FUZZ --sw=69 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.129.227.207:8080/search
Total requests: 95
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000004: 200 28 L 69 W 755 Ch "$"
000000063: 200 28 L 69 W 755 Ch "_"
000000094: 200 28 L 69 W 755 Ch "~"
These characters are banned, but the rest are not. This is what happens when I used #{7*7}:
This confirms that SSTI works, and the payload was taken from a Freemarker cheat sheet, meaning the page runs in Java (but not necessarily FreeMarker!). We can use this payload after replacing the $ with * because # doesn't seem to work.
The /credits directory contains XML files with the number of views that each Artist got for their respective images. However, the /opt directory has some interesting stuff.
woodenk@redpanda:/opt$ ll
total 24
drwxr-xr-x 5 root root 4096 Jun 23 2022 ./
drwxr-xr-x 20 root root 4096 Jun 23 2022 ../
-rwxr-xr-x 1 root root 462 Jun 23 2022 cleanup.sh*
drwxr-xr-x 3 root root 4096 Jun 14 2022 credit-score/
drwxr-xr-x 6 root root 4096 Jun 14 2022 maven/
drwxrwxr-x 5 root root 4096 Jun 14 2022 panda_search/
credit-score was a new thing. Within it there were a lot of directories leading to an App.java file that contains source code for it. We can break it down here.
It firsts takes a string and splits it into 3 portions, and only the last one is important.
After parsing the string (uri), it checks to see which Artist has an image matching the query. The uri variable is passed into the fullpath variable without sanitisation, making it vulnerable to directory traversal if we can control it. The Artist variable is embedded in the metadata of the image, which is also controllable.
The goal here is to somehow pass an XML file that we control to the addViewTo function that has a malicious XML payload. The function above does not seem to check or verify the XML that is passed to it, so I'll be trying to read the /root/.ssh/id_rsa file.
The reason we are using this is because the XML files would be read from /credits../tmp/read.xml after a single ../. Then we need to transfer our XML file over as read_creds.xml.
Afterwards, we can create our malicious string based on the template and drop it into /opt/panda_search/redpanda.log: