二次注入

二次注入是SQL注入的一种,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了检查,那么这些注入进去的指令会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏。

那为什么需要二次注入,因为在字符型注入一般都有单引号的存在,首先构造注入闭合单引号,再通过第二次构造语句,在第一次注入的基础上进行注入。

步骤1:代码审计

在之前的审计课程中我们已经对网站的大部分功能进行了审计,因而本次审计从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\,点击注册:

二次注入_第1张图片

我们点击注册后,进入用户界面,这时发现账号为nice\\,我们再查看数据数据库,却发现是nice\

二次注入_第2张图片

这是为什么呢?这是因为函数的特性。它是使用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加限制,使用正则匹配,只允许注册用户时输入英文和数字,不允许输入特殊字符,从而就修复了这个漏洞


你可能感兴趣的:(二次注入)