二次注入漏洞

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。其他类型的二次注入也有类似于此的漏洞。

危害

可以通过二次注入爆破数据库信息,也可以通过单引号截断用户名进行修改管理员帐号等。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据