RedPanda
Personal Rating: Medium
Enumeration
The initial nmap scan shew the ports 22 and 8080 as open.
sudo nmap <IP>
On http://<TARGETIP>:8080/ there was a website with a search field. A caption "Made with Spring Boot" could be seen.
Searches can be made like this:
An XML file can be exported here: http://<TARGETIP>:8080/export.xml?author=woodenk The file had a format like this:
I tried fuzzing for directories, php files and parameters for the existing pages, with no useful results. Some basic OS command and SQL injection attempts yielded nothing either. Also an sqlmap scan didn't return anything interesting.
SpringBoot SSTI w/ WAF Bypass
Investing time in that however was a bad idea. The exploit seemed very advanced and i didnt know if it was the way to go. Before I tried most of the injection types, but forgot SSTI. Spring Boot supports multiple template engines in the backgound and soon i found that the payload #{7*7}
returned the result ??49_en
_
US??
.
Quick googling returns that Thymeleaf seems to be common as a template engine for Spring Boot Following that, i found that *{7*7}
returned 49
.
Running a tplmap scan and testing many common payloads i could exclude some template engines and found out, that a WAF bans those characters: _ $ % ~
I tried circumventing the WAF by URL encoding, trying other encoding types and common payloads. But it seemed like the Firewall blocks the Input directly and exoding is either blocked or not recognized by the backend.
At this point a friend of mine started with the box and we investigated together. Through some quick research we found out, that Spring boot supports many template engines, but Thymeleaf stood out as the most likely according to how often it is used and what my payloads returned. Checking out the Thymeleaf documentation and searching for some payloads we found out, that a Thymeleaf JRE vulnerability made this payload work to get the environment variables:
You searched for: {PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin, SHELL=/bin/bash, JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64, TERM=unknown, USER=woodenk, LANG=en_US.UTF-8, SUDO_USER=root, SUDO_COMMAND=/usr/bin/java -jar /opt/panda_search/target/panda_search-0.0.1-SNAPSHOT.jar, SUDO_GID=0, MAIL=/var/mail/woodenk, LOGNAME=woodenk, SUDO_UID=0, HOME=/home/woodenk}
As he explained, the T at the beginning stands for the variable 'class' that is of the type java.lang.System With his knowlege about java he made this payload:
Which returned: You searched for: Process[pid=72538, exitValue="not exited"]
With string concatenation he made this advanced payload work to give the output of the os command 'id':
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(105).concat(T(java.lang.Character).toString(100))).getInputStream())}
So we have three parts and the middle part has to be created and concatenated for each letter of the os command:
1: *{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(105)
2: .concat(T(java.lang.Character).toString(100)) //add this for each characters
3: ).getInputStream())}
I wrote a quick and dirty Python script as payload generator. Not very elegant as i had to insert the first char manually, but I just wanted to get it to work somehow quickly:
A reverse shell did not work this way, but by using the generated payload to cat /home/woodenk/.ssh/id_rsa we could get ssh access to the machine as the user woodenk.
I found out that i couldn't transfer files to the homedir of the user because the partition was full to a 100%. I was told that this is a really solid way to secure a filesystem from unauthorized writes; Artificially shrinking it to the absolute minimum size. Anyhow, there was /dev/shm which was writeable and had space, so I used that as file storage. I put LinEnum.sh, linuxprivchecker and pspy there and used these utilities to check for misconfigurations. Especially pspy served useful - I could discover a script that is run to delete certain files regularly. But the permissions were not misconfigured and the files were deleted already. That script was just auxiliary, but not of any use for us.
Java Code Analysis
Checking out /opt we found the webserver files there. Investigating the folders an interesting file was found. I had to get a tip from the forum where people said that a java file is to be analyzed. The java file we then fould was called App.java and we took the time to analyze it thouroughly:
The request header of requests to the website is saved to a file /opt/panda_search/redpanda.log and later used in the variable 'line' in the main function. The header parts are separated as seen in this part of the program:
"uri" is used as a string in the main function in the variable "artist" as seen below, but only, if it contains an image!
The function getArtist reads the Artist tag of an image. So to summarize whats happening here: The request header of a request to the website is saved in a log, which is then read by the java Program. The uri part of the header is saved in a variable and if it is an image, the content of that image is written to an XML file at /credits/<imagecontent-variable>_credits.xml
Custom Exploit: LFI + XXE in Java
Again, as seen below, the header is separated and we cannot change the uri, otherwise the request would fail. So we use ||/../../../../../../dev/shm/soos.jpg
as our user agent in the request. This way we write the user agent in the variable "uri" instead of "user_agent". The image at the location /dev/shm/soos.jpg is crafted by us to have a special Artist tag.
The variable xmlPath that is created in the main function will then contain the Artist tag of our image. The tag will be set to /../../../../../../dev/shm/file
:
At /dev/shm we will place the xml that we downloaded before with the name file_credits.xml. It will be loaded in the following code part as the "path" variable:
This function uses the xml file at "path" as a template and writes back to it some info related to the website. Because the XML parser runs as root, we can craft the XML file to contain an XXE like this:
When we send a request with the above mentioned user agent now, the root flag should be written to the XML file.
Summary
Summarizing what was done to pwn this box:
Using this Python script to generate the payload that returns the users private ssh key when sending a request with
curl -v -u http://<TARGETIP>:8080/search -X POST -d 'name=<PAYLOAD>'
Creating a file
/dev/shm/soos.jpg
that contains the image tagArtist: /../../../../dev/shm/file
Creating a file /dev/shm/file_credits.xml that contains an XXE exploit to read /root/root.txt
Sending a request to the website that contains the user agent
||/../../../../../../dev/shm/soos.jpg
Reading the root flag that was written back to the XML file
This box was very difficult for me and I had to consult the forum and ask a friend for help. I would not have found the java SSTI without his java proficiency. But I learned that you sometimes have to come back to an application that you already exploited, to use it to get higher privileges. Also the way of combining image metadata, a command injection and an LFI was very interesting.
Last updated