二次注入: 二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。二次注入是sql注入的一种,但是比普通sql注入利用更加困难,利用门槛更高(大部分市在白盒测试中进行代码审计发现并利用的)。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询。
原理: 在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,在后端代码中可能会被转义,但在存入数据库时还是原来的数据,数据中一般带有单引号和#号,然后下次使用在拼凑SQL中,所以就形成了二次注入
过程: 插入1‘# 转义成1\’# 不能注入,但是保存在数据库时变成了原来的1’# 利用1’#进行注入,这里利用时要求取出数据时不转 义
演示: 这里我们使用sqli-labs的第24关为例
使用万能密码 admin‘# 失败
进行代码审计
重要代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > 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; > } > > }
可以看到使用了mysql_real_escape_string进行转义处理,无法进行SQL注入
此函数的相关资料
发现有注册功能 我们进行注册一个名为admin’#的账号
并且进入数据库查询
数据库的一些基础操作指令
*
net stop mysql`
net strat mysql
mysql -u用户名 -p密码
show databases use 数据库名
use 库名;
*tables; create database 库名 drop database 库名*
注册账号的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 //$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>; <?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\")";
可以看到传入的数据都进行了转义处理 但是存储到数据库中的数据依旧被转义回来了
然后我们进行密码修改 发现修改的并不是 dhakkan‘#的密码 而是数据库中 dhakkan的密码,进行代码审计我们就不难发现 后面的sql语句被我们用’#注释掉了
1 **$sql = "UPDATE users SET PASSWORD='$pass ' where username='dhakkan' #' and password='$curr_pass ' " ;**
我们如果将用户名改为恶意语句进行操作即完成了sql注入
因为我们将问题数据存储到了数据库,而程序再取数据库中的数据的时候没有进行二次判断便直接带入到代码中,从而造成了二次注入。