二次注入详解
0x01 前言
前几天看一些面经的时候,看到sql注入的二次注入,当时没一下子反应过来,好家伙,赶紧再次去那个靶场sqli-labs/Less24复现一下二次注入。
0x02 什么是二次注入?
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者即使对用户输入的恶意数据进行转义,当数据插入到数据库中时被处理的数据又被还原,Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
也就是说一次攻击造成不了什么,但是两次配合起来就会早成注入漏洞。
0x03 注入条件
两次注入分别是插入恶意数据、利用恶意数据
所以也就是满足这两个条件即可
- 用户向数据库插入恶意数据,即使后端对语句做了转义,如mysql_escape_string、mysql_real_escape_string等函数
- 数据库能够将恶意数据取出
0x04 靶场实例
首先进入靶场,可以看到与其他靶场不同,这里多了忘记密码和注册密码选项
尝试常规post注入,未果。
这里看到后端源码会发现使用了转义函数mysql_real_escape_string,常规SQL注入流程无法走了
既然可以注册账户那就去注册一下,这里直接注册admin'#
。
用注册的账号登录进去后发现可以修改密码
修改密码这个模块也可以利用,我们不妨想一下修改密码后端实现的逻辑,使用的肯定是sql增删改查中的改语句,于是猜想对应sql语句可能会是这样
update users set password='$new_pass' where username='$user' and password='$old_pass';
(当然闭合方式不一定就是单引号,这里需要碰运气吧。。)
如果我们注册一个这样的账号 admin'#
上述sql语句就变成这样
update users set password='$new_pass' where username='admin'# and password='$old_pass';
显而易见,语句原义被破坏,本来修改的是admin'#
用户的账号和密码,现在却是变成了直接修改admin用户的密码!
那就随便输入个密码123456修改后再拿它去尝试登录admin账户,发现成功登入。
说明数据库中admin用户的密码已经被成功改为123456
0x05 如何防御二次注入?
- 对输入一视同仁,无论输入来自用户还是存储,在进入到 SQL 查询前都对其进行过滤、转义。
- 使用MySQLi参数化更新,事先编译的PHP代码能够带来高效的防护效果