如何安全地进行SQL注入测试

如果从Gitlab最近的离线事件(他们处理的非常好)能够吸取某个教训的话,那就是公司必须溺爱般地保护他们的生产资料库;而作为渗透工程师,这个责任也延伸到我们。生产资料库从本质上就不适合作为实验的场所,因为任何意外的结果都可能对数据造成不可逆的不良影响,但渗透测试(至少黑盒渗透)却必须通过实验的方式寻找漏洞。本篇文章讨论的就是如何在避免修改数据的情况下安全地在生产资料库寻找漏洞。

许多公司都允许对生产伺服器和资料库的测试,而这也并非没有道理:生产环境是公司最可能被攻击的位置,所以必须经过严密测试。虽然本文中说的所有内容都同样适用于非生产环境,但在其他环境下意外修改数据的后果相比之下并不严重。作为渗透工程师,最大的噩梦恐怕就是自己的一个失误搞垮了客户的生产环境。运气好的话也许仅导致一些离线时间,通过备份可以恢复伺服器;差的话可能用户没有完整的备份,失误直接导致关键数据丢失。我们必须找到一种不会意外修改生产数据的方法来测试SQL注入。

我用谷歌搜索了「安全的SQL注入」,却没有找到任何相关的结果。当然,肯定有其他人写过这个话题,NetSPI(原作者公司)的其他员工们也提到过他们解决这个问题的方法,但我希望通过这篇博文让这个话题获得更广泛的关注并易于访问。

准备测试环境

让我们来重现一下常见的资料库环境,来测试我们的注入。我们先安装三款企业常用的关系资料库管理系统(RDBMS),MySQL、MSSQL、和Oracle,并在它们中各创建一个储存用户的表(USERS),如下。

再添加一些用户。

新手渗透工程师的第一天

在设置完成后,每个资料库里都有一个名为USERS的表,它们的结构如下:

对于多数渗透测试来说,用户表通常第一个被触碰的表,因为它被用于用户登录。我们假设查询它的代码如下:

SELECT username FROM USERS WHERE username=$username and password=$password;

很明显,这段代码存在SQL注入漏洞,但它本身并不能对系统造成什么影响(仅是泄露数据),所以我们案例中的新手渗透工程师可以大胆地随意注入』 or 1=1 --。但如果是下面这段查询代码呢?这段代码用于更新用户的电子邮箱:

UPDATE USERS set email=$email where username=$username;

这回,如果渗透工程师还在大意地随便乱用』 or 1=1 --,则后果不堪设想。

UPDATE USERS set email=; -- where username = $username;

糟啦!

公司资料库中的所有电子邮件都被删除了。假设这个公司没有完整的备份,无法恢复这些邮件,那接下来该怎么办?更新一下简历,准备去面试吧– 这个工程师可以和这份工作说再见了。

如何保住你的工作

有几种办法可以避免上述的失误,而它们的关键其实都在于多花一秒时间去思考伺服器需要执行什么类型的查询来实现被测试的功能。咱们换个角度来看刚才执行的这个查询。

UPDATE USERS set email=$email where username=$username;

虽然在黑盒测试中我们看不到伺服器上执行的代码,但我们能看到浏览器向它发送的请求,如下:

POST /updateEmail HTTP/1.1
Host: jakereynolds.co
Connection: close
Content-Length: 165
Content-Type: application/x-www-form-urlencoded

username=jake&[email protected]

从这个HTTP请求的格式和服务端点的名称应该不难推断出伺服器需要执行的查询。很明显,这个服务端点的用途是更新用户的电邮,那必然会执行UPDATE查询。我们的目标就是找到既可证明SQL注入漏洞存在,又不会造成破坏的注入载荷,并用其进行测试。

我们先来试试串联两个字元串。我们先用一个单引号结束当前的字元串,然后用相应的串联运算符将另一个字元串与其串联。如果资料库成功将两个字元串串联在一起,我们就能得知它存在SQL注入漏洞了。

虽然每个资料库系统的语法不太一样,但它们的功效都等同于:

UPDATE USERS set email=+concat where username=jake;

若是成功,那么资料库的内容将被更新为:

再来看看一些其他办法。MySQL和Oracle都允许对数字字元串进行算术运算。对于MSSQL,如果某个注入点不是字元串,而是整数值,则可以直接注入数字进行算术运算。

举例如下:

UPDATE USERS set email=1+1 where username=jake;

我们现在已经有办法根据不同资料库系统进行安全的SQL注入测试了。但如果我们不知道伺服器运行的具体是哪个资料库系统,该怎么办?有没有任何一个载荷,可以通用于这三种RDBMS?

在做了一系列尝试后,我没能发现任何一个在这三种资料库系统中功能完全一样的运算符或函数。但是,我们并不需要这个载荷在对每种系统效果都一模一样,只要它能核实注入漏洞的存在就够了。

如之前所述,在MSSQL中「+」运算符被用于串联字元串和加法运算,而在 MySQL和Oracle中它只被用于加法运算。也就是说,在MSSQL中,表达式『1』+『1』 会被评估为『11』,而在MySQL和Oracle中它则会被评估为『2』。所以,以下载荷便可通用于测试全三种资料库系统:

UPDATE USERS set email=1+1 where username=jake;

若资料库是 MSSQL ,则新的值会是『11』。

成功了!我们现在可以利用这个载荷随意对最常见的三种RDBMS进行测试,并且不用担心会造成任何不可逆转的影响。未来的挑战是扩展它以适应更多的RDBMS和更复杂的注入点。这个挑战就留给读者了。

本文由看雪翻译小组 buusc 编译,来源netspi@Jake Reynolds,转载请注明来自看雪社区

推荐阅读:

相关文章