Exploitation Level: Medium: requires some level of social engineering
DREAD Score: 6.8
Vulnerability: Reflected XSS
Patched Version: 5.5.2
WordPress released version 5.5.2 yesterday, which fixed a reflected XSS vulnerability we reported earlier this year. The root cause of this issue is a bug in the way WordPress determines a user’s current page, and which may cause a few other problems as well.
Are You Affected?
This vulnerability is exploitable on every WordPress site and user account. For the exploit to be successful, the attacker must trick an unsuspecting user into clicking on a malicious link or visiting a booby-trapped website.
The root cause of this issue is a bug in the way the $pagenow global variable has been set-up.
Put shortly, these regexes are trying to determine which file is being loaded. They also mitigate simple spoofing techniques like trying to set $pagenow’s value to “test.php” by visiting /wp-admin/index.php/wp-admin/test.php.
That being said, those regexes also contain a very subtle mistake which has gone unnoticed for quite some time: they are using the special dot character.
In a vanilla regular expression, the dot character matches against basically every character except newlines. Add that to the fact that PHP_SELF can contain decoded user-input coming straight from the URI, and you may see how it could cause some issues.
Getting back to our previous example with what we now know, if you want $pagenow to contain test.php, you can force it by visiting /wp-admin/index.php/%0a/wp-admin/test.php.
With that in mind, let’s see how deep the rabbit hole goes.
$pagenow may be used to initiate the $hook_suffix global variable, which is also used quite a bit in WordPress.
This is the get method of the WP_Screen class, used to obtain information about the screen a user is currently viewing. It essentially generates an object of that class and sets the properties according to the information it has and some of it, as you may have guessed, is coming from $hook_suffix. From the above screenshot, you can see that both the id and base properties are now tainted with user-input as a result of this functionality.
Since the resulting instance is used a lot by plugins who often rely on the get_current_screen function to get information about the page being visited, this is a big deal. It also means the $current_screen global variable can contain user-input too!
While an XSS vulnerability is kind of bad, we believe the most interesting piece to this attack vector is the myriad of assumptions it is challenging.
We believe it will lead to very interesting issues in the future — and expect that we will most likely encounter this technique again.
To protect against this XSS vulnerability, we strongly encourage WordPress users to update their site to the latest version available as soon as possible — version 5.5.2 at the time of writing.
Users who are unable to update immediately can leverage the Sucuri Web Application Firewall or equivalent technology to virtually patch the vulnerability.