0x00前言
前几天出了个ECShop<= 2.7.x/3.6.x
前台RCE,实训太无聊了来分析一波
0x01环境搭建
- ECShop_V2.7.3
- nginx
- php
0x02漏洞原理
漏洞的触发点在/user.php:301,可以看到代码逻辑做了个判断,如果http头部的referer不包含user.php
,就将referer赋值给$back_act
接下来第325行以$back_act的值为参数,传入assign
方法,该方法的作用是注册变量,将可控变量传递给模板对象,接着使用display方法就能将这个模板渲染出来,来看一下display
方法的具体实现(/includes/cls_template.php:100)
可以看到代码获取了$out,$out中有一部分代码就是前面assign注册的变量(这里的技术细节我就不讨论了,有兴趣的师傅可以研究研究),然后将$out依据$_echash
分割并且对奇数块执行了insert_mod方法,$_echash
是代码里写死的
所以这里的$val是可控的,继续往下跟insert_mod
方法(/includes/cls_template.php:1155)
该方法实现了一个动态函数调用,将传入的字符串分割后,前半部分拼接进函数名,后半部分反序列化为一个对象并传入该函数(这里因为参数可控,直接就能反序列化漏洞了,但是不知道为啥没有师傅提到,可能是被RCE掩盖了8),所以此处我们就能调用一个insert_
开头的函数,这里通过网上流传的payload可以知道是调用了一个insert_ads
方法(/includes/lib_insert.php:136)
代码将传入的对象取出num和id拼接进sql语句,因为对象是可控的,所以这里就存在了sql注入漏洞,结合前面的$out分割和分割取ads函数名和反序列化可以构造注入payload如下
拼接进去后的sql长这样
放到数据库里可以成功union select出数据
这意味着查询出的结果也是我们可控的,继续啃代码,可以知道查询出来的position_id等于传入对象的id属性时,$position_style
会被赋值为查询出的position_style
并加入前缀str:
接着传入fetch方法中
跟进fetch方法,后面就是一条长长的利用链了:
- fetch(/includes/cls_template.php:135):取str:后的字符串,
fetch_str
处理后传入_eval执行 - _eval(/includes/cls_template.php:1179):将参数拼接进eval()执行
- fetch_str(/includes/cls_template.php:281):过滤了一堆参数然后将
{}
内的字符串传入select
中处理,返回处理后的字符串 - select(/includes/cls_template.php:371):如果传入的参数以
$
开头,则将其传入get_val
并将结果拼接到<?php echo ' . $res . '; ?>
返回 - get_val(/includes/cls_template.php:553):避开其他几个判断,直接将参数传入
make_val
执行并返回 - make_var(/includes/cls_template.php:663):将字符串拼接进
$p = '$this->_var[\'' . $val . '\']';
并返回
根据以上利用链,最后构造的payload为{$'];assert(xxxxxx);//}
最后拼接进eval的参数长这样(其实上面利用链中还有其他许多分支可以最后拼接出可执行的代码,我就不深入研究了
0x03漏洞利用
最后就是构造完整的payload了,我的构造脚本如下,扔到php里运行就好
|
|
payload运行效果
0x04参考链接
0x05后话
ECShop3.*中只是加了一些防护,核心漏洞点换汤不换药,有兴趣的师傅自行研究8
ECShop4.0的修复方案是把插入sql的num和id强转为int,但是前面还有个动态函数调用和反序列化还是有风险的感觉,等一个师傅来解答。
有趣的是昨天分析下载代码的时候注册了一下ECShop官方的账号,今天就有小改改打电话问我是不是搞电商的,和她说我只是下载代码来学习研究的,她还推荐我去分析最新的4.*版本,好的我一定分析,咕咕咕