Throwback Threat Thursday is a series of posts where we recall older vulnerabilities that have since been patched by their developers. In the past, these vulnerabilities caused significant impacts to the security of website owners. Some vulnerable sites may still be found in the wild.
Back in early 2017, our research team was looking into multiple open-source projects for security issues. While looking into the then-current WordPress 4.7.0, we found a severe content injection (privilege escalation) vulnerability. It would allow unauthenticated users to modify the content of any post or page within a WordPress site via the REST API.
This was a big deal, ranking a nine on the DREAD score and gaining a “severe” security risk ranking by our researchers. We then discretely informed the WordPress Security Team, who worked with us to make sure hosts and other providers were aware and patched before any information was made public. A fix silently was added in version 4.7.2 to give everyone time to patch.
Now that it has been nearly two years since we divulged the details on this threat, let’s take a look back at how it worked and what was done to stop it.
How the WP-JSON Content Injection Worked
This vulnerability allowed for privilege escalation through the WordPress REST API added in version 4.7.0. One of the REST endpoints within the API allowed for viewing, editing, deleting, and creating posts. But a bug allowed visitors to edit any post on the site.
Because the Rest API was enabled on all sites running WordPress 4.7.0 or 4.7.1 at the time, many sites were vulnerable. The bug was first found in /wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php.
Notably, the registered route is designed to populate the ID request parameter with digits. So, if you sent a request to /wp-json/wp/v2/posts/7890, you’d set the ID parameter to 7890. While this behavior is actually beneficial to preventing attackers from creating malicious ID values, a problem arose with how the REST API managed access.
We discovered it prioritized $_GET and $_POST values over those generated by the expression. This makes it possible for an attacker to send a request like /wp-json/wp/v2/posts/7890?id=12345helloworld. That would allow them to assign 12345helloworld to the ID parameter. Notice how it also now contains characters and digits.
Upon further investigation, the update_item callback and its permission check method update_item_permissions_check caught our attention.
This method was passing the alphanumeric ID directly to the get_post() function – which validates the request checking if the post exists and the user has permission to edit. We discovered that if we sent an ID that didn’t have a corresponding post, we could bypass the permission check and continue executing requests to the update_item method. We also found that it also used the get_instance() static method in wp_posts to grab posts.
But the code within get_instance() would fail on any input that isn’t made up of all numeric characters. For an attacker, WordPress would think it is dealing with a user with enough edit access privilege, and then run the update_item method.
Checking into that method, we found that WordPress casts the ID parameter to an integer before passing it to get_post. Because of the way PHP does type comparisons and conversions, the attacker could submit a request like /wp-json/wp/v2/posts/456?id=789ABC to change the post with the ID 789.
From there, it was possible for an attacker to change content on any post or page on a victim site. They could even add shortcodes that could exploit vulnerabilities in plugins, infect the site with spam, further spread malware, or more.
As is often the case with vulnerabilities, keeping your plugins up to date was the best course of action. But if you want more information on how to keep your site secure against future vulnerabilities, check out our WordPress Security Guide.
Want more robust protection from the latest threats? We can help. Our team and tools can protect your WordPress websites, and restore it back to normal in the event of a hack.