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.

Leave a Reply

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