二阶注入
简单的说,二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。
网站对我们输入的一些重要的关键字进行了转义,但是这些我们构造的语句已经写进了数据库,可以在没有被转义的地方使用
可能每一次注入都不构成漏洞,但是如果一起用就可能造成注入。
普通注入与二次注入的区别:
普通注入:
-
在http后面构造语句,是立即直接生效的
-
一次注入很容易被扫描工具扫描到
二次注入:
-
先构造语句(有被转义字符的语句)
-
我们构造的恶意语句存入数据库
-
第二次构造语句(结合前面已经存入数据库的语句,成功。因为系统没有对已经存入数据库的数据做检查)
-
二次注入更加难以被发现
2、二次注入原理
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
二次注入的原理,主要分为两步
第一步:插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容。
第二部:引入恶意数据
在将数据存入到了数据库中之后,开发者就认为数据是可信的。早下一次需要进行查询的时候,直接从数据库中取出了恶意数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。
二次注入示例:
寻找插入数据库,并会转义的操作
输入参数1' -->参数经过转义函数1\‘ -->参数进入数据库还原为1’
寻找另一处引用这个数据的操作
将1‘从数据库中取出-->取出后直接给变量并带入SQL-->SQL注入触发
3、二次注入方法
环境准备
sqli-libs Less-24
修改username的字段长度。
alter table `users` change `username` `username` varchar(255) character set gbk collate gbk_chinese_ci Not NULL;
1、尝试在注册页面插入恶意数据,我们先注册一个账号,用户名为:admin'#,密码为123456。
2、查看恶意数据是否成功写入数据库
这是因为当数据写入到数据库的时候反斜杠会被移除,所以写入到数据库的内容就是原始数据,并不会在前面多了反斜杠。
而这时的admin原密码是admin,并且两个账号都存储在数据库内的。当我们重新修改admin'#的密码时,这里修改为12345678;可以发现admin的密码却被修改为了12345678;而admin'#用户的密码并没有发生变化。
代码审计
分析源码,出现问题的页面很显然是注册页面与密码修改重置的页面。
注册用户时:
仅对特殊字符进行了转义,判断输入两次密码是否一致,然后将用户键入,将数据插入至数据库。
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
$sql = "select count(*) from users where username='$username'";
$sql = "insert into users (username, password) values(\"$username\", \"$pass\")"
修改密码时:
admin'# 中的单引号用来闭合了username的的第一个单引号,#变成了注释符,相当于直接username='admin'。成功执行后admin密码被修改。
$username= $_SESSION["username"];//直接取出了数据库中的数据
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//对该用户的密码进行更新
这是因为上面的数据库更新语句,在用户名为 "admin'#" 时执行的实际是:
$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";
实际语句变成:
$sql = "UPDATE users SET PASSWORD='12345678' where username='admin‘#
4、二次注入的防御:
产生原因:
因为我们将问题数据存储到了数据库,而程序再取数据库中的数据的时候没有进行二次判断便直接带入到代码中,从而造成了二次注入。
防御方式:
1、对外部提交的数据,需要更加谨慎的对待。