算是为了完成任务挑战自我- -。
由于是客户的系统,也出于渗透测试的一概准则,本文中的内容全部经过脱敏处理,仅作为参考案例展示,希望给看这篇文章的同僚们一些思路上的启发。
注入点在进入系统的流量中,存在查询:
{"id":"a"}
返回值为:
{"data":[],"status":true}
惯常使用单引号进行测试,发现返回值有些许不同:
1.当值为a',返回值为{"status":true}
2.当值为a'',返回值为{"data":[],"status":true}
当注入一个单引号时data不见了(这里很容易被当做负载均衡响应),虽然不明显,但反复测试后发现包的差别一直存在,不是巧合事件。
但由于有些WAF对单个单引号存在检测(点名某数的WAF),只到这里是不能直接判断是否存在注入的。
3.当值为a''',返回值为{"status":true}
4.当值为a'''',返回值为{"data":[],"status":true}
5.当值为a';--,返回值为{"data":[],"status":true}
由此确定存在注入(盲注),开始注入。
客户的公司非常big,服务器毫无意外的采用了WAF。
倒是一点不装- -。
已知:
1.请求在json里
2.WAF会直接拦截chunkEncode
最先尝试的还是垃圾参数超长绕过,没想到一发有效,塞了五千个垃圾参数就OK了,但是这也导致响应变得尤其缓慢。不过本来我就不打算用时间盲注,先不管这个。
继续注入,结果发现还有一个WAF?
注入' or 1=1;--,响应变为了{"status":false}
注入' or 1=9;--,响应同上
显然代码/第二层WAF中发生了某种拦截(如果仅仅是过滤,不会出现第三种响应)。由于响应包仍然符合系统格式,推测是代码中存在拦截。
代码中存在的拦截就不能从垃圾参数等整个包的角度进行绕过了。无脑的方法莽不了,只能带上脑子看看。通过之前的合作,发现客户的所有系统都会存在某些统一的标准(一种做过等保的美- -),所以我推测这个拦截也是统一标准的一环(比如说JAVA里的拦截器或者Python里的装饰器,可以很方便的调用,仅需一个导入一个@XXX)。那么就会存在一个问题:如果它同时保护了多个系统,是否会存在同时保护多种数据库的情况?如果同时保护多种数据库,我们就可以通过数据库之间的语法差异进行绕过。
为了证实我的猜测,在参数中加入多种数据库的特殊关键字,均拦截。基本上算证实了。
接下来是尝试时间:
1.大小写,完全无效。
2.注释,即使插在关键字中间也无效,看来做了类似正则的拦截。
3.%0a,这个我不熟而且没有用。
4.使用非常用关键字如case when等,无效,不愧是大公司。
5.内联注释,里面的内容并没有执行并且还是被拦了。
到这一步其实已经山穷水尽了,苯人的注入能力其实麻麻,求助的同事也爱莫能助。但是一个注入在面前,注出来就是一个紧急,很难让人放弃。又想到内联注释的内容会被检测但并未执行(说明数据库不是mysql),加上之前对此代码的探测发现,灵机一动使用/*!*/包裹垃圾和语句放在一起,竟然绕过了!
现在语句如下:
o' OR /*!asdadaaordsadASD*/ '1'/*1=1*/='';--
到这一步了,其实已经可以通过盲注获取到数据库名。不过由于这次注入过程复杂,我打算对这个注入进行一丢丢更深入的研究。
1.输入o' or 1=1;--,语句理论上未报错,但返回{"status":true}。
2.输入o',语句报错,仍然返回{"status":true}。
3.输入o' or 1=9;--,语句理论上未报错,返回{"data":[],"status":true}。
4.输入o' and 1=9;--,语句理论上未报错,返回{"data":[],"status":true}。
5.输入o' or 1=1;--,语句理论上未报错,返回{"data":[],"status":true}。
到此处,能感觉到代码中对语句的返回条数进行了限制,多于一条的返回将报错。
6.输入o' limit 1;--,返回{"status":true}。
7.输入o' where ROWNUM=2;--,返回{"status":true}。
排除了mysql、postgresql、oracle。感觉这个数据库是MSSQL。
然后用语句跑了个当前用户名,本次注入到此就告一段落了,谢谢观看~