基本介绍
这里所谓的二次注入其实就是将可能导致SQL注入的字符先存入到数据库中,而当我们再次调用这个恶意构造的字符时就可以触发SQL注入,这一种注入在平时并不常见,但是确实是存在的一种注入,故此在这里将其单独拎出来说一下
注入原理
二次注入的原理是在第一次进行数据库插入数据的时候,仅仅只是使用了addslashes或者是借助get_magic_quotes_gpc对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据,在将数据存入到了数据库中之后开发者就认为数据是可信的,在下一次进行需要进行查询的时候直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入,比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中然后在下一次使用中在拼凑的过程中就形成了二次注入:
总结起来二次注入其实是分为两个步骤:
-
插入恶意数据
-
引用恶意数据
注入思路
二次排序注入思路:
1、黑客通过构造数据的形式在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令
2、服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应
3、黑客向服务端发送第二个与第一次不相同的请求数据信息
4、服务端接收到黑客提交的第二个请求信息后为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行
5、服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功
注入案例
这里以Sql-labs中的Less-24为例做演示:
程序源代码
login_create.php
<html>
<head>
</head>
<body bgcolor="#000000">
session_start();
<div align="right">
<a style="font-size:.8em;color:#FFFF00" href='index.php'><img src="../images/Home.png" height='45'; width='45'></br>HOME</a>
</div>
//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 "<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>;
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>";
echo "<center><img src=../images/Less-24-user-created.jpg><font size='3' color='#FFFF00'>";
//echo "<h1>User Created Successfully</h1>";
echo "</br>";
echo "</br>";
echo "</br>";
echo "</br>Redirecting you to login page in 5 sec................";
echo "<font size='2'>";
echo "</br>If it does not redirect, click the home button on top right</center>";
header('refresh:5, url=index.php');
}
else
{
<script>alert('Please make sure that password field and retype password match correctly')</script>
header('refresh:1, url=new_user.php');
}
}
}
</body>
</html>
从以上代码来主要实现用户注册功能,且对用户的账号密码中的特殊字符进行了转义~
login.php
<html>
<head>
</head>
<body bgcolor="#000000">
<font size="3" color="#FFFF00">
<div align="right">
<a style="font-size:.8em;color:#FFFF00" href='index.php'><img src="../images/Home.png" height='45'; width='45'></br>HOME</a>
</div>
session_start();
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
function sqllogin(){
$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'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
//print_r($row) ;
if ($row[1]) {
return $row[1];
} else {
return 0;
}
}
$login = sqllogin();
if (!$login== 0)
{
$_SESSION["username"] = $login;
setcookie("Auth", 1, time()+3600); /* expire in 15 Minutes */
header('Location: logged-in.php');
}
else
{
<tr><td colspan="2" style="text-align:center;"><br/><p style="color:#FF0000;">
<center>
<img src="../images/slap1.jpg">
</center>
</p></td></tr>
}
</body>
</html>
以上代码主要实现用户登录认证功能~
pass_change.php
<html>
<head>
</head>
<body bgcolor="#000000">
session_start();
if (!isset($_COOKIE["Auth"]))
{
if (!isset($_SESSION["username"]))
{
header('Location: index.php');
}
header('Location: index.php');
}
<div align="right">
<a style="font-size:.8em;color:#FFFF00" href='index.php'><img src="../images/Home.png" height='45'; width='45'></br>HOME</a>
</div>
//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 '<font size="3" color="#FFFF00">';
echo '<center>';
if($row==1)
{
echo "Password successfully updated";
}
else
{
header('Location: failed.php');
//echo 'You tried to be smart, Try harder!!!! :( ';
}
}
else
{
echo '<font size="5" color="#FFFF00"><center>';
echo "Make sure New Password and Retype Password fields have same value";
header('refresh:2, url=index.php');
}
}
if(isset($_POST['submit1']))
{
session_destroy();
setcookie('Auth', 1 , time()-3600);
header ('Location: index.php');
}
</center>
</body>
</html>
以上代码为修改密码逻辑,在L38行会更新用户的账号密码,此处我们如果先通过注册方式注册一个带有注释符的账号,例如:admin'#,那么在更新密码时,更新的sql语句就会变成下面的这样:
$sql = "UPDATE users SET PASSWORD='$pass' where username=' admin'# ' and password='$curr_pass' ";
由此可见,可以直接将后门的语句全部给注释掉,最后实现对admin账号的改密码操作,下面具体来实现一下~
初始用户表
注册恶意账号
注册一个admin'#账号:
查询表内信息
再次查询用户表信息时发现出现了admin'#账户:
登陆恶意账号
随后登陆admin'#账号
修改账号密码
随后进入修改密码的页面设置新的密码,这里打算给admin账号设置一个新的密码:
提交表单之后成功修改账号密码
admin密码被改
再次查看用户表发现admin账号的密码发生了变化,改为了——al1ex,成功实现了二次排序注入
文末小结
当目标系统有对用户的输入进行转义但是没有进行替换操作时,可能存在二次排序注入的可能性,这时候可以找相关的利用点,例如:上面的用户注册到更新用户信息
原文始发于微信公众号(七芒星实验室):二次注入简单介绍
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论