二次注入(存储型注入),这种手法所利用的原理是:在网站处理用户提交的数据的时候,只是将某些敏感字符进行了转义。因而使得用户第一次提交的时候不会被当做代码执行。但是这些数据存入数据库的时候却没有转义(比如用户输入的数据为admin'#
,进行执行代码的时候会转义为admin\'#
,存入数据库的数据仍为admin'#
),而网站程序默认数据库中的数据都是安全的,当网站程序第二次调用刚才存储的脏数据的时候,则不会转义使用而是直接使用,因此就会达到注入的效果。
注意两点:
1、网站会将数据原封不动的存入数据库中。
2、网站会直接调用数据库中的数据而不会对其进行检测等操作。(信任数据库中的数据)
第一次进行数据库插入数据的时候,使用了 addslashes 、get_magic_quotes_gpc、mysql_escape_string、mysql_real_escape_string等函数对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。
一个用户登录界面,可以注册新用户和登录。
我们登录一个Dumb:Dumb
看一下
可以更改密码
我们看一下我们当前的users表
我们注册一个新用户admin'#
,密码为123456
admin'#
是直接原数据存入了数据库
我们登录admin'#
用户,进行修改密码
将密码修改为nihao
但发现admin
用户的密码变为了nihao
然后我们就获得了admin:nihao
,可以登录这个账户了。这就是我们的目的
注册用户
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
if (isset($_POST['submit']))
{
# Validating the user input........
//$username= $_POST['username'] ;
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
echo "";
$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 "";
echo "" ;
//echo "User Created Successfully
";
echo "";
echo "";
echo "";
echo "Redirecting you to login page in 5 sec................";
echo "";
echo "If it does not redirect, click the home button on top right";
header('refresh:5, url=index.php');
}
else
{
?>
<script>alert('Please make sure that password field and retype password match correctly')</script>
<?php
header('refresh:1, url=new_user.php');
}
}
}
?>
对用户输入的数据进行了转义
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
插入数据库
insert into users ( username, password) values(\"$username\", \"$pass\")
为什么插入的是原数据而不是转义后的数据,我觉得应该是数据库内部的操作,自动去除了转义符\
。
之所以转义,是为了预防用户进行SQL注入
修改密码
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
if (isset($_POST['submit']))
{
# Validating the user input........
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_affected_rows();
echo '';
echo '' ;
if($row==1)
{
echo "Password successfully updated";
}
else
{
header('Location: failed.php');
//echo 'You tried to be smart, Try harder!!!! :( ';
}
}
else
{
echo '' ;
echo "Make sure New Password and Retype Password fields have same value";
header('refresh:2, url=index.php');
}
}
?>
同样对用户输入的数据进行了转义
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
但是注意,这里的username是直接拿过来的,没有进行转义操作!!!
如果对username进行转义了,就不会出现二次注入漏洞了
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
https://blog.csdn.net/hhhhhhhhh85/article/details/121328475
https://blog.csdn.net/weixin_43901998/article/details/107288123