#1.二次注入原理
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
也就是说在应用程序中输入恶意造的数据库查询语句时会被转义,但是在数据库内部调用读取语句的时候又被还原。
#2.二次注入,可以概括为以下两步:
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
#3.区别
参考网上的总结,二次注入和普通注入的区别主要有:
普通注入:(1)在http后面构造语句,是立即直接生效;
(2)普通注入很容易被扫描工具扫描到。
二次注入:(1)先构造语句(此语句含有被转义字符的语句);
(2)将我们构造的恶意语句存入数据库;
(3)第二次构造语句(结合前面已被存入数据库的语句构造。因为系统没有对已存入的数据做检查,成功注入);
(4)二次注入更加难以被发现。
#4.动手试一下
本次测试环境是sqli-labs。
(1)先在网站注册两个账户,分别是test和test’#
注册的主要代码如下:
if (isset($_POST['submit']))
{
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
//print_r($row);
if (!$row[0]== 0)
{
?>
<script>alert("The username Already exists, Please choose a different username ")</script>;
<?php
header('refresh:1, url=new_user.php');
}
else
{
if ($pass==$re_pass)
{
# Building up the query........
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());
echo "</br>";
··················
可以看到传入的username、password、re_password仍均被mysql_escape_string进行了转义处理,但是在数据库中还是插入了test’#,
这是因为当数据写入到数据库的时候反斜杠会被移除,所以写入到数据库的内容就是原始数据,并不会在前面多了反斜杠。
数据库中查询两个账户的信息。如下:
密码分别为123456和111111.
(2)打开页面可以看到一个登陆界面,尝试用admin’#进行注入,失败。
部分源代码如下:
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
可以看到使用了mysql_real_escape_string进行转义处理,无法进行SQL注入。
在登陆页面先用用户test’#进行登陆,登陆后发现可以进行密码修改。
在这里我们将test’#新密码修改为222222。
查询数据库用户信息:
用户test的密码变成了222222!我修改的是用户test’#的密码呀,为什么用户test的密码变了呢?
5.原因
我们在修改用户test’#密码时候实际上执行如下代码:
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
这是因为上面的数据库更新语句,在用户名为 "admin'#" 时执行的实际是:
$sql = "UPDATE users SET PASSWORD='$pass' where username='test'#' and password='$curr_pass' ";
#在数据库语言中起注释的作用,所以这样子的话,不知不觉中被更改密码的成了test,而不是test’#。
/因为我们将问题数据存储到了数据库,而程序再取数据库中的数据的时候没有进行二次判断便直接带入到代码中,从而造成了二次注入。
本人转载于
作者:selecthch
来源:CSDN
原文:https://blog.csdn.net/weixin_42277564/article/details/92835879