WordPress – CSRF>XSS>Shell>Profit.

I did a small penetration test in 2013/14 for a client’s WordPress site, which has since been my go-to anecdote for explaining the potential for XSS… probably because, to non-sec folk, what it achieved sounds amazing, although its really rather easy to explain how and why it worked. This is that anecdote…After a short scan with WPScan I was able to determine that the site was using a plugin vulnerable to both CSRF and XSS. The plugin allowed an administrator to specify some keywords in its configuration page, which it used to aid in bettering the site’s SEO (somehow). This input was “XSSable” in a stored manner and the POST requests to modify it didn’t need any sort of token to validate the session. Tut tut.
So, the attack idea was simple.. create a malicious site which fired off an automated POST request to the plugin’s config page; which, when visited by a logged in user, updated the SEO keywords with an XSS payload. This, in-turn, executes and does something nastier in the victim’s browser when the page reloads.
The something nastier was to make another post request to the WordPress ‘user-new.php’ page to automatically create me an Administrator-level user. However this request required a CSRF token to authenticate it which could only be gotten by first actually being on the ‘user-new.php’ page. This wasn’t an issue of-course, the XSS payload first sends a GET request to that page via AJAX, stores its response in a variable and scrapes the token out of it with a bit of regex, then finally constructs the admin-adding POST request which is ready to ruin someone’s day. Brill.
What made the attack super-effective was that i found that it could be directed to non-administrator users, whom could modify the plugin’s settings due to poor privilege-level checking, allowing them to serve as mules to smuggle in the XSS payload, which would then be effective against admins upon their next visit.
Whats funny about the attack was that, to remove the vulnerable XSS payload, the victim may visit the plugin config page, which would restart the attack and both recreate the attacker’s account and redirect the victim away before they could delete it.
While you will always have to manually find a method of gaining XSS via a plugin or theme, the “create an admin” section of the exploit will always remain the same (scrape a token, make a request) therefore i’ve made a small BeEF module to do just that. Rather than worry that your exploit might not work for whatever reason you can just drop a BeEF hook and inject the payload manually into the browser. If it fails you can inject it again. After creating your admin account, you can simply log in and upload yourself a plugin-shell or backdoor any writable PHP pages.
Link: wordpress_add_admin.zip
Update: This module was pulled into the official BeEF repository, so if you have BeEF, you already have “wordpress_add_admin” as an available exploit (https://github.com/beefproject/beef/tree/master/modules/exploits/wordpress_add_admin).