Created 星期五 27 九月 2019
状态:良好 心情:要放长假了,要回家了,心情激动

攻击说明

攻击途径:远程网络
攻击复杂度:低
认证:需要后台管理员权限
机密性:完全地
完整性:不受影响
可用性:不受影响
漏洞位置:系统后台修改专题管理处

问题产生:

XYHCMS V3.5
行云海CMS是完全开源的一套CMS内容管理系统,简洁,易用,安全,稳定。
后台在修改专题管理处,可修改内容显示的模板文件路径,系统会包含该指定文件,如果这个路径被攻击者恶意修改为攻击代码所在的文件路径,应用程序便会执行恶意代码。至于恶意文件可通过上传jpg,txt等任意文件后缀名的方式上传到服务器中。

0x01.代码位置:

漏洞代码位置:\App\Home\Controller\SpecialController.class.php 第63-行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public function shows($id = 0) {
$id = I('id', 0, 'intval');
if ($id == 0) {
$this->error('参数错误');
}

$content = M('special')->find($id);
if (!$content) {
//$this->error('专题不存在');
R('Home/Empty/_empty'); //404
return;
}
$cid = $content['cid'];

$cate = get_category(10);
$self = Category::getSelf($cate, $cid); //当前栏目信息

if (empty($self)) {
$self = array(
'id' => 0,
'name' => '',
'ename' => '',
'url' => '',
);
}

$this->assign('cate', $self);

$patterns = array('/' . C('TMPL_TEMPLATE_SUFFIX') . '$/');
$replacements = array('');
$template_show = preg_replace($patterns, $replacements, $content['template']);

/*测试
$patterns = array('/^Show_/', '/.html$/');
$replacements = array('', '');
$template_show = preg_replace($patterns, $replacements, $content['template']);
*/
if (empty($template_show)) {
$this->error('模板不存在');
}

$this->assign('title', $content['title']);
$this->assign('keywords', $content['keywords']);
$this->assign('description', $content['description']);
$this->assign('comment_flag', $content['comment_flag']); //是否允许评论,debug,以后加上个全局评价 $content['comment_flag'] && CFG_Comment
$this->assign('content', $content);
$this->assign('table_name', 'special');
$this->assign('id', $id);
$this->display($template_show);

代码分析:
这里主要关注传入display方法中的template_show参数(Thinkphp框架的问题,display函数中第一个的变量可控,就能造成任意代码执行),这里可以分析发现,template_show是根据用户传入的id参数从数据库中Special表中的template字段中获取得到。于是我们去找写入到这个字段的系统功能代码。
代码位置:\App\Manage\Controller\SpecialController.class.php 第53-80行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//添加
public function add() {

//当前控制器名称
$actionName = strtolower(CONTROLLER_NAME);

if (IS_POST) {
$this->addPost();
exit();
}

$cate = get_category(2);
$cate = Category::toLevel($cate);
$_styleShowList = get_file_folder_List('./Public/Home/' . C('CFG_THEMESTYLE'), 2, 'Special_*');

$styleShowList = array();
foreach ($_styleShowList as $v) {
if (strpos($v, 'Special_index') === false) {
$styleShowList[] = $v;
}
}

$this->assign('cate', $cate);
$this->assign('styleShowList', $styleShowList);
$this->assign('flagtypelist', get_item('flagtype'));
$this->assign('type', '添加专题');
$this->display();
}

代码分析:
addPost方法直接把请求中的数据写入到数据库中,没有合理的过滤,于是模板文件路径我们可以任意写入,但是这个文件路径不能过长,数据库tamplate字段有长度限制。

0x02.缺陷利用

1.于是我们利用系统功能先上传一张图片或者txt后缀的文件,或者其他的域名都无所谓,测试中上传了一个txt文件,文件内容是显示phpinfo信息的代码:
uK1Uwd.png
2.得到文件路径:/uploads/file1/20190927/5d8d77316548f.txt
3.于是利用系统后台修改专题管理处功能,添加一条专题信息,如下图所示,把模板路径设置为上传的文件路径:
uK8ivT.png
uK8M26.png
4.于是查看这条记录,就能执行txt文件中的任意代码:
uK8DsS.png
5.执行了txt文件中获取phpinfo信息的代码:
uK8Xz6.png

修复建议

1.应用程序不允许用户设置任意模板文件路径;
2.display方法中传入的参数合理化判断。