In a recent penetration test, we were able to gain administrative access to a client’s WordPress installation by exploiting a known SQL injection vulnerability (CVE-2015-2314) allowing unauthorised access to download usernames and password hashes. Often in tests against WordPress installations, this provides us with enough access to inject malicious code into the site’s template files and gain remote code execution privileges on the operating system hosting the site.
In this instance however, the client had secured the installation by making all site files read-only to the web server user and protected the media upload directory from being accessed directly. This meant that no new PHP code could be introduced to the site – a technique that is often used by attackers to run their own malicious code to act as a foothold on the victim’s network.
WordPress currently has 37,910 plugins available, contributed by enthusiasts the world over. As a result of this popularity however, they are often built without a strong security posture in mind. In an attempt to gain further access to the web server, all plugins installed on the site were downloaded and examined for security flaws.
In order to get access to the underlying web server operating system, at least one of the plugins needed to use either a code execution function unsafely, e.g.
or a file inclusion function unsafely, e.g.
Luckily for us, of around 30 plugins installed on the site in question, we found several uses of the “eval()” function inside of the “Custom Content Type Manager” WordPress plugin (See Figure 1). This plugin provides a flexible method of creating content types other than “post” and “page” within WordPress and allows the user to specify their own collection of fields for those types.
The first use of the eval function was found in the “Visibility Control” settings of a custom field to enter PHP code (See Figure 2).
Code entered here is then rendered on the custom content type editing page (See Figure 3).
The second use of the eval function was found within the “OnCreate”, “OnEdit” or “OnSave” calculated values fields of the hidden field type. When creating a custom field, these can again be set to execute arbitrary PHP, which is passed to an “eval” function. In this example, the custom field is used to execute phpinfo(), which displays detailed information about the configuration of the application server (See Figure 4 & 5).
The third instance was found within the “Default Value” field of a “Date and Time” field type (See Figure 6).
As with the “Visibility Control” example, this is used to send operating system commands to the system within the new content type edit form (See Figure 7).
In the penetration test, we needed just one of these “eval” statements to download custom software to the server and establish a foothold on the internal network. WordPress is currently the most popular content management system in use on the web, used by a massive 23.9% of all websites. This popularity comes with its own risks: freely available vulnerability scanning software exists specifically to target WordPress (http://wpscan.org/) and due to the sheer number and complexity of WordPress plugins available, securing a WordPress install is a struggle that a lot of organisations face. WordPress users have the task of securing every one of their plugins whilst attacks may only need one security flaw in order to gain access. Unfortunately, this type of attack chain – using insecure WordPress plugins – is common within penetration tests that we run.
As this issue was previously undiscovered and no patch was available (i.e. a “zero day”), it has been assigned a new vulnerability reference, CVE-2015-3173.
The author of the Custom Content Type Manager plugin has been informed of this vulnerability and has issued a fix in version 0.9.8.6.
- Custom Content Type Manager – https://wordpress.org/plugins/custom-content-type-manager/
- WPML – SQLi vulnerability – https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-2314
To contact Nettitude’s editor, please email firstname.lastname@example.org.