二次注入是SQL注入的一种,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了检查,那么这些注入进去的指令会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏。
那为什么需要二次注入,因为在字符型注入一般都有单引号的存在,首先构造注入闭合单引号,再通过第二次构造语句,在第一次注入的基础上进行注入。
在之前的审计课程中我们已经对网站的大部分功能进行了审计,因而本次审计从messageSub.php
入手,它是留言板的页面,我们首先查看其源码:
if (isset($_POST['submit']) && !empty($_POST['message']) && isset($_SESSION['username'])) {
$clean_message = clean_input($_POST['message']);
$query = "INSERT INTO comment(user_name,comment_text,pub_date) VALUES ('{$_SESSION['username']}','$clean_message',now())";
mysql_query($query, $conn) or die(mysql_error());
mysql_close($conn);
header('Location: message.php');
可以看到,在处理POST过来的变量时,没有用到sqlwaf,只是对输入的字符串加上了单引号,然后直接就带入了SQL语句进行查询。
在上述中的这种查询语句是双条件、或者多条件的。
我们查询语句并不仅仅指select,条件也并不仅仅指where后面的条件。只要输入的内容,有一定的输入关系和顺序,就可以了。
看这个双条件,分别为:$_SESSION['username']
和$clean_message。
我们可以构造如下语句:
$query = "INSERT INTO comment(user_name,comment_text,pub_date) VALUES ('xxx\',',(),1);#',now())
首先用用户名截断掉后面的单引号,那么闭合的单引号就会到第二个字符串的前面,可以看到,在comment后查询了三个内容,我们再在values中放入任意的查询内容:1。
这样就达到了截断单引号的目的,再将后面的数据修改为payload,这样就理论上达到了二次注入的条件。
因此payload为:
,(select admin_pass from admin limit 0,1),1);#
当然这一切的前提就是用户名后面有一个\
,如果没有\,就不能转义掉单引号,也就无从谈起了,因此我们需要控制用户名。那么如何控制呢?
可以新注册一个用户,在注册用户名时,添加一个\
。
因此我们找到设置用户名的地方:也就是注册的地方:regCheck.php。
$clean_name = clean_input($_POST['user']);
$clean_pass = clean_input($_POST['passwd']);
可以看到,它使用clean_input函数对我们输入的用户名进行了过滤
我们自然要查看一下如何过滤的,在sys/lib.php
中找到了过滤函数:
function clean_input( $dirty ) {
return mysql_real_escape_string( stripslashes( $dirty ) );
}
它先将我们输入的字符自动转移,再进行反转义,也就是说,比如我们输入xxx\
,它会转义成为xxx\\
。但进入数据库的时候,他会是一个\
还是两个呢?
我们来进行测试,注册账号nice\
,点击注册:
我们点击注册后,进入用户界面,这时发现账号为nice\\
,我们再查看数据数据库,却发现是nice\
。
这是为什么呢?这是因为函数的特性。它是使用mysql的函数进行过滤,因此到数据库就变成了单斜杠,既然是单斜杠,那么我们就可以利用了。
但是在网页上还是nice\
,因此我们需要重新登录,刷新Session值,因为网页上的名称是以数据库为准的,因此重新登陆即可。
再将我们之前构造好的语句,在留言板提交,理论上是可以将管理员的密码爆出来的。
修复代码示例
//过滤输入变量
$clean_name = clean_input($_POST['user']);
if (!preg_match("/^[a-zA-Z0-9]+$/",$clean_name)) {
die('用户名只允许\w+');
}
$clean_pass = clean_input($_POST['passwd']);
$avatar = '../images/default.jpg';
在注册的地方regcheck.php
加限制,使用正则匹配,只允许注册用户时输入英文和数字,不允许输入特殊字符,从而就修复了这个漏洞