MySQL二次注入
SQL漏洞简介
MySQL数据库查询语句:
SELECT * FROM [table] WHERE XXX = ' $args ' && XXX = $number
假设这是运行在服务器上的,$args
和$number
为用户填写的表单。如果未对$args
和$number
进行任何限制,这极容易存在风险。
在语句中可以看到,$args
外有单引号(双引号也行)包围,这说明这是字符型的数据。而$number
外没有任何包围,这说明这是整型数据。
要添加限制的话,整型只需要使用 is_numeric($number)
判断即可。
要对$args
进行限制的话,则需要考虑单引号(双引号)闭合等问题。方法有很多种,addslashes()是其中一种。
addslashes()会自动在单引号,双引号和反斜杠前增加一个反斜杠,起到类似注释的作用。现在进行处理前后的对比。
$args = "admin' and 1=2 order by 100# ";
$args1 = addslashes($args);
SELECT * FROM [table] WHERE XXX = ' admin' and 1=2 order by 100# ' --$args
SELECT * FROM [table] WHERE XXX = ' admin\' and 1=2 order by 100# ' --$args1
可见使用了addslashes()对单引号进行转义后,变量无法闭合单引号,查询语句正常执行。不添加转义而引起的超预期查询则为一般的SQL注入。
二次注入漏洞
如果在查增改阶段均进行单引号等转义,那么一般不会存在SQL注入。然而由于MySQL在对待转义符号\
时有一种机制:
只在传入执行时会有反斜杠,然后保存在数据中时反斜杠会被去除,还原数据本身。导致插入数据库中的数据的单引号等被还原,等到再次查询该语句时(如果没有对检出数据进行处理),数据中的单引号等会引起意外闭合原本的SQL单引号,然后执行恶意代码。
这是一种宽容的政策,原本应该替换或删除的敏感符合仅仅做了转义,安全通过了一次SQL执行后便被信任,导致后续存在风险。但有时为了数据完整性又不得不采取这样的方法。
现在来分析插入数据库中的数据起到怎样的破坏(以一份PHP文件为例):
这是一条植入数据库的信息,可见反斜杠已经没有了。
这时模拟用户登陆(密码隐藏,不对程序起影响):
可见正常经过addslashes()处理的变量中的单引号此时是有反斜杠的,但这并不影响进行判断。注意,此时的 username
已经被遍历为 admin'#
。尽管此时这里有单引号和注释符,但不会造成语法出错。因为它已经被参数化了。直到这步,程序还是正常运行的。
然后一般的程序会从中调取很多信息返回给客户端,例如:
这里用到了mysqli_fetch_array()
方法,官方介绍:
mysqli_fetch_array() 函数从结果集中取得一行作为关联数组,或数字数组,或二者兼有。
我们在里面插入的是username字段,这里也用到了。这里的用户名数据也是需要数据库查询获得的,这里也是出错的地方。
从代码执行方面来看:
首先是登陆
主要看$sql
这条语句,在WHERE
后面的判断语句中,$username
由表单获得(且经过addslashes()处理)。所以此时的$username
即使有单引号等也不会引起语句错误。
感到疑惑的地方是,此时保存在数据库中的username
不是已经去反斜杠了,可以引起语句错误了吗?但在这语句中,username
代表的是列名,所以存储在数据库中的数据不能对该语句造成闭合。
展示信息出错
由于数据由数据库里获得,有些开发者就把数据当作可信赖的进而用来查询后继信息。如把从数据库里获得的用户名存入session或干脆直接继续在其他库内进行信息查询。此时数据中的单引号就会引发闭合错误,进而执行恶意语句。
此论点及注入点仅针对工作室练习平台的二次注入ctf。其他类型的二次注入也有类似于此的漏洞。
危害
可以通过二次注入爆破数据库信息,也可以通过单引号截断用户名进行修改管理员帐号等。