ZZZCMS任意文件读取漏洞分析

关注着CNVD的漏洞通报,发现ZZZCMS 7.1版本存在一个任意文件读取的漏洞通告,遂尝试复现一波。

先说一下漏洞利用,权限为管理员才行

在有管理员权限后,才可以利用查看日志的方式,读取到任意文件内容,关键的函数是load_file()

0x00 漏洞利用条件

  • 管理员权限
  • 后台管理目录
  • 后台数据库为mysql

管理员权限,emmm~相信大家已经可以通过很多方式拿到

后台管理目录,通过爆破admin000admin999,可以找到

后台数据库类型约束,一般来讲都会使用Mysql

当然下文中有两个漏洞利用点,另一个不需要这个约束条件


0x01 出现问题的地方

问题出现在admin371\save.php 第899行附近的restore()函数

zzphp

可以看出,path参数是可控的

跟进 load_file() 函数,在admin371\save.php 文件首部

//读取文件
function load_file( $path, $location = NULL ) {
    $path = str_replace( '//', '/', $path );
    if ( is_file( $path ) ) {
        return file_get_contents( $path );
    } elseif ( !is_null( $location ) ) {
        $locationpath = PLUG_DIR . 'template/' . $location . '.tpl';
        if ( is_file( $locationpath ) ) {
            return file_get_contents( $locationpath );
        } elseif(conf('runmode')==1) {
            return false;
        }else{
            error ( '404,很抱歉您访问的页面不存在,请检查网址是否正确!',SITE_PATH);
        }
    } elseif ( is_file( SITE_DIR . $path ) ) {
        return file_get_contents( SITE_DIR . $path );
    } else {
        error( "载入文件失败,请检查文件路径!," . str_replace( DOC_PATH, '', $path ) );
        return false;
    }
}

如果load_file(path)只传递path参数,那么直接通过file_get_contentss($path)返回读取文件的内容

虽然 load_file() 能够读取文件,但是并没有回显的地方,该如何解决呐?

继续跟进 db_exec() 函数

可以写入日志

那么针对文件中以分号+换行结尾的,认为是一条完整的SQL语句,无论执行成功与否,将会写入日志

再看str_log()函数的定义

// 日志记录
function str_log( $s, $dir = 'error',$file = '' ) {
    $time = $_SERVER[ 'time' ];
    $ip = $_SERVER[ 'ip' ];
    $uid = intval( get_session( 'adminid' ) );
    $day = date( 'Ym', $time );
    $mtime = date( 'Y-m-d H:i:s' );
    $dbtype= $_SERVER[ 'conf' ]['db'];
    switch(    $dbtype['type']){
    case 'access':
        $name = md5( strtotime(date("Y-m-d"),time()).    $dbtype['accessname']) . ".zzz";
        break;
        case 'mysql':
        $name = md5( strtotime(date("Y-m-d"),time()).    $dbtype['user'].$dbtype['password']) . ".zzz";
        break;
        case 'sqlite':
        $name = md5( strtotime(date("Y-m-d"),time()).    $dbtype['sqlitename']) . ".zzz";
        break;
        default:
        $name = md5( strtotime(date("Y-m-d"),time()).conf('adminpath')) . ".zzz";
        break;
    }
    $url = isset( $_SERVER[ 'REQUEST_URI' ] ) ? $_SERVER[ 'REQUEST_URI' ] : '';
    $logpath = empty($file) ? RUN_DIR . $dir . '/' . $name : RUN_DIR . $dir . '/' . md5($file).".zzz";
    check_dir(dirname($logpath),true);
    is_array( $s )and $s = tojson( $s );
    $s = "$mtime\t$ip\t$url\t$uid\r\n$s\r\n";
    return error_log( $s, 3, $logpath );
}

其主要在于

case 'mysql':
    $name = md5( strtotime(date("Y-m-d"),time()).    $dbtype['user'].$dbtype['password']) . ".zzz";

其日志文件名是经过MD5摘要信息,暴力破解也不太实际

系统管理 -> 操作记录 可以直接看到日志文件名

查看日志文件名

那么尝试一下构造读取网站的配置文件,发现日志文件中成功写入

成功写入

那么这里就是一个漏洞利用点了!

0x02 漏洞利用点2

在如上,我们看到了管理员可以直接读取日志文件,那么看看其针对文件路径读取是否严格过滤了呐?

直接抓包修改测试,发现居然可以直接读取任意文件

成功读取

分析一下原因呐?

调用module

参数moudle的值就是调用渲染的模版名,位于相对路径下的./template/目录

可利用的就是log.tpl模版

log.tpl

非常棒,这里就没有数据库类型限制了

又是一个任意文件读取的漏洞点!


0x03 攻击Payload

妈个蛋,又找到了0day,懒得提交了~

Payload1:

此处内容已隐藏,评论后刷新即可查看!

Payload2:

此处内容已隐藏,评论后刷新即可查看!

本文仅供安全学习研究用途,共勉!

发表评论 / Comment

用心评论~

金玉良言 / Appraise
zzzcmsLV 1
2019-10-15 21:33
的确很厉害
蘑菇LV 1
2019-10-12 14:05
从内容来看的确很厉害
鱼头汤LV 2
2019-09-29 10:41
无敌
LV 1
2019-09-27 10:40
膜拜
ManYuLV 1
2019-09-25 08:38
牛逼