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.

One thought on “Local File Inclusion (LFI) Vulnerability in SAM Pro (Free Edition)

  1. Pingback: L’hebdo de l’écosystème WordPress n°65 - WPHebdo

Leave a Reply

Your email address will not be published. Required fields are marked *