Overview
Ubuntu 20.04. IP: 10.10.10.x. Topics: SSTI (Spring Boot), log poisoning, path traversal, XXE, source code review.
Chain: SSTI in the search box, shell as woodenk, credentials in the source, SSH,
analysis of a root cron job (a Java jar), a four-vulnerability chain (log poisoning + path
traversal + metadata-driven path injection + XXE), the root SSH key, root.
Reconnaissance
| |
22/tcp: OpenSSH 8.2p1 (Ubuntu)8080/tcp: HTTP (http-proxy)
HTTP (port 8080):
- A “Red Panda Search” image search page.
- Page source:
<title>Red Panda Search | Made with Spring Boot</title>, so the framework is Java Spring Boot. - Searching returns “You searched for:
”, a potential XSS/SSTI vector (our input reaches the response). - An “Author” link leads to a stats page with an export to XML (
/export.xml?author=woodenk), a lead for later (XML means potential XXE).
Initial Access
SSTI (Spring Boot / SpEL)
Spring Boot uses SpEL. Standard payloads:
| |
The filter blocks ${...} and #{...} but allows *{...}.
RCE:
| |
Result: uid=1000(woodenk) gid=1001(logs) ..., RCE as woodenk.
Reverse shell. shell.sh on the attacking machine:
| |
| |
Three SSTI payloads in sequence (download, chmod, run):
| |
Shell as woodenk.
Lateral Movement
woodenk to SSH
Grep the configuration files:
| |
It contains MySQL credentials, and the same password works for the system user:
| |
| |
User flag: /home/woodenk/user.txt.
Privilege Escalation
Analysing the root cron job
| |
Every 2 minutes as UID 0 (root):
| |
Source: /opt/credit-score/LogParser/final/src/main/java/com/logparser/App.java
What the program does (main loop):
- Reads the log line by line (
redpanda.log). isImage(line): skips lines without.jpg.parseLog(line): splits the line on||into four fields[status_code, ip, user_agent, uri].getArtist(uri): builds"/opt/panda_search/src/main/resources/static" + uri, opens the image, reads theArtistfield from the EXIF metadata and returns it.- Builds
xmlPath = "/credits/" + artist + "_creds.xml". addViewTo(xmlPath, uri): parses the XML file at that path (the XXE).
The four-vulnerability chain:
| # | Vulnerability | Gives | How |
|---|---|---|---|
| 1 | Log poisoning | Control over uri | Injecting ` |
| 2 | Path traversal | Point at our own image | ../ in uri leaves static/ and points at /tmp/smooch.jpg |
| 3 | Metadata path injection | Point at our own XML | The Artist field (attacker-controlled) reaches xmlPath unsanitized; Artist = ../tmp/hax means /tmp/hax_creds.xml is parsed |
| 4 | XXE | Read a root file | An external entity in our XML reads /root/.ssh/id_rsa into our world-readable file |
Step by step:
A. Malicious XML (based on export.xml), with an XXE entity in <author>:
| |
On the target:
| |
B. Malicious image, set the Artist field to the traversal (without _creds.xml, the
program appends it):
| |
Upload it to the target at /tmp/smooch.jpg.
C. Trigger: poison the log so uri points at our image:
| |
D. Wait ~2 minutes (cron) and read the file (the XXE entity wrote the root key):
| |
E. Log in as root:
| |
Root flag: /root/root.txt.
Detection and Mitigation
- Signature filters leak: blocking
${}and#{}without*{}does not close SpEL SSTI. Do not evaluate user input as a template. - Hardcoded passwords in source are often shared with a system account.
- If logs are later parsed, attacker-controlled headers (User-Agent) become an injection vector.
- Attacker-controlled data in path construction (
"/credits/" + artist) without sanitization is path traversal. - XML parsers are XXE-prone by default; disable DTDs and external entities
(
FEATURE_SECURE_PROCESSING, disableDOCTYPE). - File metadata is input; the EXIF
Artistfield is not trusted text.
Lessons Learned
- Try all SSTI delimiter variants; a filter that misses one is still exploitable.
pspyreveals root cron jobs without needing root.- Chain small bugs: field injection into a delimited log, traversal, metadata-driven path injection, XXE.
Command Reference
| |