概要
类型:Web-SQL注入
来源:BUUCTF
知识点:堆叠注入;MySQL表结构的修改;MySQL查看表、列
思路
首先可以看到一个很简单的查询界面。
使用F12查看网页源代码,发现作者并不希望我们依赖sqlmap进行解题。
总之先随便查询些什么吧。发现输入'1'和'2'时,页面均有返回,并且根据返回的内容来看,可以分析出查询的是某个表的第一个字段。
其次还是来分析一下闭合方式,输入“1'”时发生语法错误,输入“1"”则无事发生。可判断此处为单引号闭合。
接着使用万能密码“' or 1=1#”绕过查询的条件,我们得到了被查询表的每一条记录。但看起来这里似乎没有我们想要的flag。
在MySQL中,show tables可以返回当前数据库中存在的所有表的名称:
';show tables#
由于前面判断是单引号闭合,并且在MySQL中,“;”的作用是将语句分隔开来,因此我们先让后端查询一个空值,然后再执行show tables,并且通过“#”将后面可能存在的语句都注释掉,避免了语法的错误。这也叫做【堆叠注入】,因为这看起来就像是很多语句叠在一起之后,一起提交到后端中。
发现存在两张表,一个叫作“1919810931114514”,另一个叫做“words”。
同样的,再使用show columns,分别查看这两张表的结构,也就是其中包含的字段名称:
';show columns from `words`#
在`words`表中似乎并没有我们想要的信息。
';show columns from `1919810931114514`#
再看看`1919810931114514`表,果然找到了“flag”字段,这应该就是flag所在的位置了,显然我们应该想办法把该表的记录打印出来。
自然地,我们会想到使用select语句输出表的内容,然而作者显然不会让这道题太过简单,我们发现诸如select、where等MySQL常用的关键字都被【过滤】了,也就是只要查询中出现这些关键字,都不能被执行。当然在某些题目中,一些过滤机制是可以想办法过滤的。
目前已知有两张表,而从字段的数量来看,显然默认被查询的表是`words`表,因为该表有两个字段“id”、“data”,和查询所得是对应的。
那么,我们就想到可以将表名进行替换,使flag所在的`1919810931114514`表成为默认被查询的`words`表,这样做就能让后端自己将表的内容打印出来。
然而,笔者在这里犯了一个错误。
笔者先将两表的表名进行替换以后,发现无论输入什么都会出现一个错误,显示缺少id字段。
虽然这确实侧面印证了我们成功地修改了表的名称,但问题是此时的`words`表的结构实际上和原来的并不一样。通过报错,可以推测默认的查询语句如下:
select * from words where id="xxx";
此时的`words`表并没有id这个字段,就必然会发生语法的错误,更糟糕的是,因为这个错误,后面堆叠注入的语句也不起作用了,也就是说我们现在开始没有办法将这个新的`words`表的“flag”字段修改为“id”。
此时只能销毁靶机,从头来过了。正确的做法是,我们应该在一次堆叠注入中完成所有事情,包括两表名称的替换,以及字段名称的修改。
在MySQL中,修改表名主要有两种方法:
ALTER TABLE table_name1 RENAME table_name2;
RENAME TABLE table_name1 to table_name2;
在MySQL中,用以下语句修改表中某字段:
ALTER TABLE table_name CHANGE old_name new_name varchar(20)# 最后一个参数为数据类型;
综上所述,payload可以写为:
';rename tables `words` to `words2`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#
在上述语句中,我们将`words`表的表名改为words2,然后将`1919810931114514`表的表名改为words,最后将新`words`表的“flag”字段改为“id”。
最后,只需要使用万能密码查询表的所有记录,就能看到flag了。
总结
相对于比较简单的SQL注入而言,这道题在步骤上确实显得有些曲折了,因为过滤机制给我们带来了一些麻烦。但总体而言,找注入点、判断闭合方式、爆破表、爆破字段的思路还是比较清晰的。笔者在这道题中的做法——对已知表的结构进行修改,也可以提供一种灵活的思路。