About the security month

With the help of our code analysis solution RIPS we identified critical vulnerabilities in the WordPress core itself and in many of the most popular WordPress plugins. Some of them have multiple million active installations. As an example, the e-commerce plugin WooCommerce that enables WordPress site owners to sell products via their site has more active installations than the largest e-commerce plattform itself. In December 2018, we released a new vulnerability each day with a description, code summary and video for learning purposes.

To summarize, the RIPS advent calendar 2018 included:

  • a wormable Stored XSS on wordpress.org
  • a WordPress core privilege escalation
  • 16 vulnerable plugins that have over 21 million active installations in total

Vulnerability Types

The types of vulnerabilities that were featured in our advent calendar can be put into two categories: Vulnerabilities that occur because 1) plugin developers misuse WordPress security functions and / or forget sanitization entirely, and 2) developers do not have a complete understanding of the privilege system or architecture of WordPress. This lead to many privilege escalation flaws being uncovered.

Vulnerability Origins

Let’s have a deeper look at these issues. In most cases, plugin developers make use of the functionality and API of WordPress, or any other framework/CMS in use. This usually leads to two kinds of security issues.

#1 Misusing functions provided by the framework

Most CMS systems provide a range of security related functions for plugin developers. WordPress for example offers multiple interfaces to securely craft SQL queries with user input. One function WordPress provides is particularly dangerous: esc_sql(). This function is secure, if used in the correct context. The function internally escapes all single quotes (') and therefor prevents SQL injections in quoted strings.

Example of a secure call to esc_sql()

1
$wpdb->query("SELECT * FROM wp_users WHERE email='" . esc_sql($_GET['email']) . "'");

If an attacker tried to inject the string ' OR 1=1 -- into the SQL markup, the call to esc_sql would return \' OR 1=1 --, thus sanitizing the user input.

However, if the user input is inserted without quotes surrounding it, the function fails because it is used in the wrong context.

Insecure call to esc_sql()

1
$wpdb->query("SELECT * FROM wp_users WHERE id=" . esc_sql($_GET['id']));

Because esc_sql() only escapes single quotes, an attacker can simply supply the string 1 OR 1=1. Since no single quote is involved, nothing gets escaped and the resulting SQL query would be SELECT * FROM wp_users WHERE id=1 OR 1=1.

Problems like these arise because WordPress can impossibly provide a single function to sanitize any user input for plugins which have use cases that WordPress does not know yet. This circumstance that leads to various context specific functions being provided, mixed with a lack of understanding of vulnerabilities and insufficient documentation often lead to security issues.

On Day 21 of our advent calendar, a plugin with over 700.000 active installations misused exactly the function described above.

#2 Lack of understanding of the CMS architecture

Often times plugin developers use functionality of a CMS without considering how other components or plugins may affect their usage of such functionality. To give a concrete example, WordPress provides the post meta API to plugin developers. When a WordPress post is stored in the database, it can store meta information as key value pairs. To give a fictitious example, a plugin might keep track of the last author of a WordPress blog who edited a certain post. To do so it will execute the following code when the post is updated and saved by an author of a blog.

Updating post meta

1
2
3
$post_id = $_POST['post_id'];
$current_user = esc_html($_POST['last_author']);
update_post_meta($post_id, 'fictitious_plugin_last_author', $current_user);

This code will update the value of the meta entry with the key fictitious_plugin_last_author with the user input $_POST['post_id']. In this example, the user input is escaped and sanitized before storing it in the database.

Whenever somebody reads the post with the ID that now has the updated meta entry, the plugin will display the last author to the reader via the following code.

Retrieving post meta

1
2
$post_id = $_GET['post_id'];
echo "This post was last edited by " . get_post_meta($post_id, 'fictitious_plugin_last_author');

Here, the post meta value is directly embedded into the HTML markup of the page. However, since it was sanitized with esc_html() before storing it in the database, XSS attacks are successfully prevented.

However, the WordPress core provides an ajax callback that allows to update any unprotected meta entries with arbitrary, unsanitized inputs. Although the plugin securely handles and saves the user input sanitized into the database, it outputs it without further sanitization. Since an attacker can simply use the ajax callback to update the data the plugin trusts, a Stored XSS can be achieved.

The popular plugin Jetpack which has over 5 million active installations and is developed by Automattic, the company behind WordPress, made this mistake. The details are disclosed on the 11th day of our advent calendar.

Why Publishing Vulnerabilities is Important

Publishing details about a vulnerability, after it has been reported to the vendor and a fix is released, has benefits for vendors and users of plugins. The plugin vendors can learn from their mistakes and the mistakes of others in order to secure their plugins and PHP applications.

The benefit for site owners is that it gives them a metric to help decide which plugins to install or not. WordPress site owners can choose between almost 50.000 plugins to customize their site to their needs. By using a public track record of vulnerabilities in plugins, they can estimate if the plugin is safe to use or not.

Vendor Reactions

When contacting vendors to notify them about vulnerabilities in their software, different reactions should be expected. Nobody likes being called out for their mistakes. Most plugin vendors replied very quickly and often responded within the next couple of days. However, most of the time a patch release was postponed until the next regular release of the plugin. This lead to unpatched security vulnerabilities for weeks, in some cases months.

Consequences for site owners

WordPress site owners can customize the behavior and design of their site with plugins and themes. Considering that there are almost 50.000 plugins available in the WordPress plugin repository, it becomes clear that catching all vulnerabilities is impossible. This is why site owners have to trust the plugins they download and it is wise to keep the list short. It is common for big sites to have dozens of plugins installed, since WordPress does not offer features such as analytics, advertisement or e-commerce by default. Some sites run with over 50 plugins installed.

Which plugins should be installed?

The problem of site owners having to trust plugins to not introduce security vulnerabilities will always be present. Intuitively, administrators should resort to only installing popular plugins with good reviews and a positive history regarding security vulnerabilities. Additionally, it seems intuitive that commercial plugins developed by large companies are more secure than free plugins, developed by a single or few volunteers.

These metrics proved not to be sufficient. The advent calendar only features the most popular and best reviewed WordPress plugins and commercial plugins. Furthermore, some plugins were developed by large companies. The advent calendar features 8 vulnerabilities in WooCommerce, an e-commerce plugin with over 4 million active installations, which is developed by Automattic, the company that runs wordpress.com.

The best site owners can do is to minimize the amount of installed plugins and follow security principles such as acting with the least required privileges. For example, a site owner does not have to be authenticated as an administrator account when he only wants to edit a blog post. An account with the author role is sufficient for this task. If the owner then triggers for example a Stored XSS payload, the attack won’t be able to do as much harm as it could have had when the site owner would have been authenticated as an administrator.