Last active
November 29, 2022 17:45
-
-
Save jamesbercegay/a8f169059c6184e76b12d98d887542b3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I have done some preliminary research into this bug and so far it does not seem like a backdoor. Just some really weird logic when handling routes, and rendering templates. | |
As to why widgetConfig[code] executes via a POST request, it is because of the following code located in /includes/vb5/frontend/applicationlight.php | |
$serverData = array_merge($_GET, $_POST); | |
if (!empty($this->application['handler']) AND method_exists($this, $this->application['handler'])) | |
{ | |
$app = $this->application['handler']; | |
call_user_func(array($this, $app), $serverData); | |
return true; | |
} | |
$this->application['handler'] is set via some logic in the class constructor that matches the string value of $_REQUEST['routestring'] to an array of "quick routes". | |
/**Standard constructor. We only access applications through init() **/ | |
protected function __construct() | |
{ | |
if (empty($_REQUEST['routestring'])) | |
{ | |
return false; | |
} | |
if (isset(self::$quickRoutes[$_REQUEST['routestring']])) | |
{ | |
$this->application = self::$quickRoutes[$_REQUEST['routestring']]; | |
return true; | |
} | |
foreach (self::$quickRoutePrefixMatch AS $prefix => $route) | |
{ | |
if (substr($_REQUEST['routestring'], 0, strlen($prefix)) == $prefix) | |
{ | |
$this->application = $route; | |
return true; | |
} | |
} | |
return false; | |
} | |
The quick routes array looks like this: | |
* @var array Quick routes that match the beginning of the route string | |
*/ | |
protected static $quickRoutePrefixMatch = array( | |
'ajax/apidetach' => array( | |
'handler' => 'handleAjaxApiDetached', | |
'static' => false, | |
'requirePost' => true, | |
), // note, keep this before ajax/api. More specific routes should come before | |
// less specific ones, to allow the prefix check to work correctly, see constructor. | |
'ajax/api' => array( | |
'handler' => 'handleAjaxApi', | |
'static' => false, | |
'requirePost' => true, | |
), | |
'ajax/render' => array( | |
'handler' => 'callRender', | |
'static' => false, | |
'requirePost' => true, | |
), | |
); | |
After that the handler from the quick routes is executed, and the process of setting up the template rendering begins. | |
/** | |
* Renders a template from an ajax call | |
* | |
* @param array Array of server data (from $_POST and/or $_GET, see execute()) | |
*/ | |
protected function callRender($serverData) | |
{ | |
$routeInfo = explode('/', $serverData['routestring']); | |
if (count($routeInfo) < 3) | |
{ | |
throw new vB5_Exception_Api('ajax', 'render', array(), 'invalid_request'); | |
} | |
$this->router = new vB5_Frontend_Routing(); | |
$this->router->setRouteInfo(array( | |
'action' => 'actionRender', | |
'arguments' => $serverData, | |
'template' => $routeInfo[2], | |
// this use of $_GET appears to be fine, | |
// since it's setting the route query params | |
// not sending the data to the template | |
// render | |
'queryParameters' => $_GET, | |
)); | |
Api_InterfaceAbstract::setLight(); | |
$this->sendAsJson(vB5_Template::staticRenderAjax($routeInfo[2], $serverData)); | |
} | |
The template code that is executed is as follows: | |
<template name="widget_php" templatetype="template" date="1452807873" username="vBulletin" version="5.2.1 Alpha 2"><![CDATA[<vb:if condition="empty($widgetConfig) AND !empty($widgetinstanceid)"> | |
{vb:data widgetConfig, widget, fetchConfig, {vb:raw widgetinstanceid}} | |
</vb:if> | |
<vb:if condition="!empty($widgetConfig)"> | |
{vb:set widgetid, {vb:raw widgetConfig.widgetid}} | |
{vb:set widgetinstanceid, {vb:raw widgetConfig.widgetinstanceid}} | |
</vb:if> | |
<div class="b-module{vb:var widgetConfig.show_at_breakpoints_css_classes} canvas-widget default-widget custom-html-widget" id="widget_{vb:raw widgetinstanceid}" data-widget-id="{vb:raw widgetid}" data-widget-instance-id="{vb:raw widgetinstanceid}"> | |
{vb:template module_title, | |
widgetConfig={vb:raw widgetConfig}, | |
show_title_divider=1, | |
can_use_sitebuilder={vb:raw user.can_use_sitebuilder}} | |
<div class="widget-content"> | |
<vb:if condition="!empty($widgetConfig['code']) AND !$vboptions['disable_php_rendering']"> | |
{vb:action evaledPHP, bbcode, evalCode, {vb:raw widgetConfig.code}} | |
{vb:raw $evaledPHP} | |
<vb:else /> | |
<vb:if condition="$user['can_use_sitebuilder']"> | |
<span class="note">{vb:phrase click_edit_to_config_module}</span> | |
</vb:if> | |
</vb:if> | |
</div> | |
</div>]]></template> | |
Here is the backtrace for anyone interested. | |
0 eval() called at [/var/www/vbulletin/includes/vb5/frontend/controller/bbcode.php:227] | |
1 vB5_Frontend_Controller_Bbcode::evalCode(debug_print_backtrace();exit;) called at [/var/www/vbulletin/includes/vb5/template/runtime.php:1039] | |
2 vB5_Template_Runtime::parseAction(bbcode, evalCode, debug_print_backtrace();exit;) called at [/var/www/vbulletin/includes/vb5/template.php(369) : eval()'d code:24] | |
3 eval() called at [/var/www/vbulletin/includes/vb5/template.php:369] | |
4 vB5_Template->render(1, 1) called at [/var/www/vbulletin/includes/vb5/template.php:688] | |
5 vB5_Template::staticRender(widget_php, Array ([routestring] => ajax/render/widget_php,[widgetConfig] => Array ([code] => debug_print_backtrace();exit;)), 1, 1) called at [/var/www/vbulletin/includes/vb5/template.php:701] | |
6 vB5_Template::staticRenderAjax(widget_php, Array ([routestring] => ajax/render/widget_php,[widgetConfig] => Array ([code] => debug_print_backtrace();exit;))) called at [/var/www/vbulletin/includes/vb5/frontend/applicationlight.php:302] | |
7 vB5_Frontend_ApplicationLight->callRender(Array ([routestring] => ajax/render/widget_php,[widgetConfig] => Array ([code] => debug_print_backtrace();exit;))) called at [/var/www/vbulletin/includes/vb5/frontend/applicationlight.php:186] | |
8 vB5_Frontend_ApplicationLight->execute() called at [/var/www/vbulletin/index.php:41] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment