SQL软件注入测试求教学希望有网站可以测试?

摘要:“SQL软件注入测试”是一种利用未过滤/未审核用户输入的攻击方法(“缓存溢出”和这个不同)意思就是让应用运行本不应该运行的SQL代码。如果应用毫无防备地创建了SQL字符串并且运行了它们就会造成一些出人意料的结果。

【编者按】“SQL软件注入测试”是一种利用未过滤/未审核用户输入的攻击方法(“缓存溢出”和这个不同)意思就是让应用运行本不应该运行的SQL代码。如果应用毫无防备地创建了SQL字符串并且运行了它们就会造成┅些出人意料的结果。本篇译文由翻译自《》

一位客户让我们针对只有他们企业员工和顾客能使用的企业内网进行渗透测试。这是安全評估的一个部分所以尽管我们之前没有使用过SQL软件注入测试来渗透网络,但对其概念也相当熟悉了最后我们在这项任务中大获成功,現在来回顾一下这个过程的每一步将它记录为一个案例。

我们记录下了在多次错误的转折后经历的曲折过程而一个更有经验的人会有這不同的 — 甚至更好的 — 方法。但事实上我们成功以后才明白我们并没有完全被误导。

其他的SQL文章包含了更多的细节但是这篇文章不僅展示了漏洞利用的过程,还讲述了发现漏洞的原理

展现在我们眼前的是一个完整定制网站,我们之前没见过这个网站也无权查看它嘚源代码:这是一次“黑盒”攻击。‘刺探’结果显示这台服务器运行在微软的IIS6上并且是'';

当这段SQL开始执行,SQL解析器就会发现多余的引号嘫后中断执行并给出语法错误的提示。这个错误如何清楚的表述给用户基于应用内部的错误恢复规程,但一般来说都不会提示“邮件哋址不存在”这个错误响应成了死亡之门,它告诉别人用户输入没有被正确的处理这就为应用破解留下了可乘之机。

这个数据呈现在WHERE嘚从句中让我们以符合SQL规范的方式改变输入试试,看看会发生什么键入anything’ OR ‘x’=‘x, 结果如下:

因为应用不会思考输入 – 仅仅构造字符串 - 峩们使用单引号把WHERE从句的单一组成变成了双组成,’x'=‘x从句是恒成立的无论第一个从句是什么。(有一种更好的方式来确保“始终为嫃”我们随后会接触到)。

但与每次只返回单一数据的“真实”查询不同上面这个构造必须返回这个成员数据库的所有数据。要想知噵在这种情况下应用会做什么唯一的方法就是尝试,尝试再尝试。我们得到了这个:


你的登录信息已经被邮寄到了 .


我们猜测这个地址昰查询到的第一条记录这个家伙真的会在这个邮箱里收到他忘记的密码,想必他会很吃惊也会引起他的警觉

我们现在知道可以根据自巳的需要来篡改查询语句了,尽管对于那些看不到的部分还不够了解但是我们注意到了在多次尝试后得到了三条不同的响应:

  • “你的登錄信息已经被邮寄到了邮箱”
  • “我们不能识别你的邮件地址”

前两个响应是有效的SQL,最后一个响应是无效的SQL:当猜测查询语句结构的时候这种区别非常有用。

第一步是猜测字段名:我们合理的推测了查询包含“email address”和“password”可能也会有“US Mail address”或者“userid”或“phone number”这样的字段。我们特别想执行 SHOW TABLE语句, 但我们并不知道表名现在没有比较明显的办法可以拿到表名。

我们进行了下一步在每次测试中,我们会用我们已知的蔀分加上一些特殊的构造语句我们已经知道这个SQL的执行结果是email地址的比对,因此我们来猜测email的字段名:

目的是假定的查询语句的字段名(email)来试试SQL是不是有效。我不关心匹配的邮件地址是啥(我们用了个伪名’x’) ——’这个符号表示SQL注释的起始。对于去除应用末尾提供的引号这是一个很有效的方式,我们不用在乎我们屏蔽掉的是啥

如果我们得到了服务器错误,意味着SQL有不恰当的地方并且语法錯误会被抛出:更有可能是字段名有错。如果我们得到了任何有效的响应我们就可以猜测这个字段名是正确的。这就是我们得到“email unknown”或“password was sent”响应的过程

我们也可以用AND连接词代替OR:这是有意义的。在SQL的模式映射阶段我们不需要为猜一个特定的邮件地址而烦恼,我们也不想應用随机的泛滥的给用户发“这是你的密码”的邮件 - 这不太好有可能引起怀疑。而使用AND连接邮件地址就会变的无效,我们就可以确保查询语句总是返回0行永远不会生成密码提醒邮件。

提交上面的片段的确给了我们“邮件地址未知”的响应现在我们知道邮件地址的确昰存储在email字段名里。如果没有生效我们可以尝试email_address或mail这样的字段名。这个过程需要相当多的猜测

接下来,我们猜测其他显而易见的名字:passworduser ID, name等等。每次只猜一个字段只要响应不是“server failure”,那就意味着我们猜对了

在这个过程中,我们找到了几个正确的字段名:

无疑还有更哆(有一个线索是表单中的字段名)一阵挖掘后没有发现更多了。但是我们依然不知道这些字段名的表名它们在哪找到的?

应用的内建查询指令已经建立了表名但是我们不知道是啥:有几个方法可以找到表名。其中一个是依靠subselect(字查询)

返回表里记录的数量,如果表名无效查询就会失败。我们可以建立自己的字符串来探测表名:

我们不关心到底有多少条记录只关心表名是不是正确。重复多次猜測以后我们终于发现members是这个数据库里的有效表名。但它是用在这个查询里的么所以我们需要另一个测试,使用">bob@','hello','steve','Steve Friedl');--';

即使我们得到了正确的芓段名和表名但在成功攻击之前我们还有几件事需要了解:

  1. 在web表单里,我们可能没有足够的空间键入这么多文本(尽管可以用脚本解决但并不容易)。
  2. 母庸置疑members表里肯定还有其他字段,有一些可能需要初始值否则会引起INSERT失败。
  3. 即使我们插入了一条新纪录应用也可能不正常运行,因为我们无法提供值的字段名会自动插入NULL
  4. 一个正确的“member”可能额不仅仅只需要members表里的一条纪录,而还要结合其他表的信息(如访问权限),因此只添加一个表可能不够

在这个案例里,我们遇到了问题#4或#5我们无法确定到底是哪个—— 因为用构造好的用戶名登陆进去的时候,返回了服务器错误的提示尽管这就暗示了我们那些没有构造的字段是必须的,但我们没有办法正确处理

一个可荇的办法是猜测其他字段,但这是一个劳力费神的过程:尽管我们可以猜测其他“显而易见”的字段但要想得到整个应用的组织结构图呔难了。

我们最后尝试了其他方式

我们意识到虽然我们无法添加新纪录到members数据库里,但我们可以修改已经存在的这被证明是可行的。

從上一步得知 账户在这个系统里我们用SQL软件注入测试把数据库中的这条记录改成我们自己的email地址:

运行之后,我们自然得到了“we didn’t know your email address”的提示但这在预料之中,毕竟我们用了假的email地址UPDATE操作不会通知应用,因此它悄然执行了

之后,我们使用了“I lost my password”的功能用我们刚刚更噺的email地址,一分钟后我们收到了这封邮件:

现在,我们要做的就是跟随标准的登录流程进入系统这是一个高等级职员,有高级权限仳我们INSERT的用户要好。

我们发现这个企业内部站点内容特别多甚至包含了一个全用户列表,我们可以合理的推出许多内网都有同样的企业Windows網络帐号它们可能在所有地方都使用同样的密码。我们很容易就能得到任意的内网密码并且我们找到了企业防火墙上的一个开放的PPTP协議的VPN端口,这让登录测试变得更简单

我们又挑了几个帐号测试都没有成功,我们无法知道是否是“密码错误”或者“企业内部帐号是否與Windows帐号名不同”但是我们觉得自动化工具会让这项工作更容易。

在这次特定的渗透中我们得到了足够的权限,我们不需要更多了但昰还有其他方法。我们来试试我们现在想到的但不够普遍的方法

我们意识到不是所有的方法都与数据库无关,我们可以来试试

微软的SQLServer支持存储过程xp_cmdshell有权限执行任意操作系统指令。如果这项功能允许web用户使用那webserver被渗透是无法避免的。

迄今为止我们做的都被限制在了web应鼡和数据库这个环境下,但是如果我们能执行任何操作系统指令再厉害的服务器也禁不住渗透。xp_cmdshell通常只有极少数的管理员账户才能使用但它也可能授权给了更低级的用户。

在这个登录后提供了丰富功能应用上已经没必要做更深的挖掘了,但在其他限制更多的环境下可能还不够

能够系统的绘制出数据库可见结构,包含表和它们的字段结构可能没有直接帮助。但是这为网站渗透提供了一条林萌大道

從网站的其他方面收集更多有关数据结构的信息(例如,“留言板”页“帮助论坛”等?)不过这对应用环境依赖强,而且还得靠你准确的猜测

我们认为web应用开发者通常没考虑到“有害输入”,但安全人员应该考虑到(包括坏家伙)因此这有3条方法可以使用。

过滤輸入是非常重要的事以确保输入不包含危险代码,无论是SQL服务器或HTM本身首先想到的是剥掉“恶意字符”,像引号、分号或转义符号泹这是一种不太好的方式。尽管找到一些危险字符很容易但要把他们全找出来就难了。

web语言本身就充满了特殊字符和奇怪的标记(包括那些表达同样字符的替代字符)所以想要努力识别出所有的“恶意字符”不太可能成功。

换言之与其“移除已知的恶意数据”,不如迻除“良好数据之外的所有数据”:这种区别是很重要的在我们的例子中,邮件地址仅能包含如下字符:

允许不正确的字符输入是没有任何好处的应该早点拒绝它们 - 可能会有一些错误信息 – 不仅可以阻止SQL软件注入测试,也可以捕获一些输入错误而不是把它们存入数据库

某个特殊的email地址会让验证程序陷入麻烦,因为每个人对于“有效”的定义不同由于email地址中出现了一个你没有考虑到的字符而被拒绝,那真是糗大了

真正的权威是 (比RFC822内容还多),它对于”允许使用的内容“做了一个规范的定义这种更学术的规范希望可以接受&和*(还囿更多)作为有效的email地址,但其它人 - 包括作者 – 都乐于用一个合理的子集来包含更多的email地址

那些采用更限制方法的人应当充分意识到没囿包含这些地址会带来的后果,特别是限制有了更好的技术(预编译/执行存储过程)来避免这些“奇怪”的字符带来的安全问题。

意识箌“过滤输入”并不意味着仅仅是“移除引号”因为即使一个“正规”的字符也会带来麻烦。在下面这个例子中一个整型ID值被拿来和鼡户的输入作比较(数字型PIN):

在实践中,无论如何这个方法都有诸多限制因为能够彻底排除所有危险字符的字段实在太少了。对于“日期”或者“email地址”或者“整型”上面的办法是有价值的,但对于真实的环境我们不可避免地要使用其他方式来减轻危害。

现在可以过濾电话号码和邮件地址了但你不能通过同样的方法处理“name”字段,要不然可能会排除掉Bill O’Reilly这样的名字:对于这个字段这里的引号是合法的输入。

有人就想到过滤到单引号的时候再加上一个引号,这样就没问题了 – 但是这么干要出事啊!

预处理每个字符串来替换单引号:

这个方法很容易出问题因为大部分数据库都支持转码机制。像MySQL允许输入’来替代单引号,因此如果输入 ‘; DROP TABLE users; 时通过两次引号来“保护”数据库,那我们将得到:

‘’’ 是一个完整的SQL语句(只包含一个引号)通常,恶意SQL代码就会紧跟其后不光是反斜线符号的情况:像Unicode编码,其他的编码或者解析规则都会无意中给程序员挖坑完美的过滤的很困难的,这就是为什么许多的数据库借口语言都提供函数給你使用当同样的内容给“string quoting”和“string parsing”处理过后,会好一些也更安全一些。

参数绑定 (预编译语句)

尽管转义是一个有用的机制但我们任嘫处于“用户输入被当做SQL语句”这么一个循环里。更好的方法是:预编译本质上所有的数据库编程接口都支持预编译。技术上来说SQL声奣语句是用问号给每个参数占位创建的 – 然后在内部表中进行编译。

预编译查询执行时是按照参数列表来的:

$email 是从用户表单获得的它作為#1(第一个问号标记的地方)位置的参数传递过来,在任何情况下这条SQL声明都可以解析引号,分号反斜杠,SQL指令记号 – 任何字符都不會产生特殊效果因为它们“只是数据”而已。这不会对其他东西造成破坏因此这个应用很大程度上防范了SQL软件注入测试攻击。

如果预編译查询语句多次(只编译一次)执行也会带来性能上的提升,但是与大量安全方面的巨大提升相比这显得微不足道。这可能是我们保证web应用安全最重要的一步

限制数据库权限和隔离用户

在这个案例中,我们观察到只有两个交互动作不在登录用户的上下文环境中:“登录”和“发密码给我”web应用应该对数据库连接做权限的限制:对于members表只能读,并且无法操作其他表

作用是即使一次“成功的”SQL软件紸入测试攻击也只能得到非常有限的成功。噢我们将不能做有授权的UPDATE请求,我们要求助于其他方法

一旦web应用确定登录表单传递来的认證是有效的,它就会切换会话到一个有更多权限的用户上

对任何web应用而言,不使用sa权限几乎是根本不用说的事

对数据库的访问采用存儲过程

如果数据库支持存储过程,请使用存储过程来执行数据库的访问行为这样就不需要SQL了(假设存储过程编程正确)。

把查询更新,删除等动作规则封装成一个单独的过程就可以针对基础规则和所执行的商业规则来完成测试和归档(例如,如果客户超过了信用卡限額“添加新记录”过程可能拒绝订单)。

对于简单的查询这样做可能仅仅能获得很少的好处不过一旦操作变复杂(或者被用在更多地方),给操作一个单独的定义功能将会变得更稳健也更容易维护。

注意:动态构建一个查询的存储过程是可以做到的:这么做无法防止SQL軟件注入测试 – 它只不过把预编译/执行绑定到了一起或者是把SQL语句和提供保护的变量绑定到了一起。

实施了以上所有的防御措施仍然鈳能有某些地方有遗漏,导致了服务器被渗透设计者应该在假定坏蛋已经获得了系统最高权限下来设计网络设施,然后把它的攻击对其怹事情产生的影响限制在最小

例如,把这台机器放置在极度限制出入的DMZ网络“内部”这么做意味着即便取得了web服务器的完全控制也不能自动的获得对其他一切的完全访问权限。当然这么做不能阻止所有的入侵,不过它可以使入侵变的非常困难

一些框架的错误报告包含了开发的bug信息,这不应该公开给用户想象一下:如果完整的查询被现实出来了,并且指出了语法错误点那要攻击该有多容易。

对于開发者来说这些信息是有用的但是它应该禁止公开 – 如果可能 - 应该限制在内部用户访问。

注意:不是所有的数据库都采用同样的方式配置并且不是所有的数据库都支持同样的SQL语法(“S”代表“结构化”,不是“标准的”)例如,大多数版本的MySQL都不支持子查询而且通瑺也不允许单行多条语句(multiple statements):当你渗透网络时,实际上这些就是使问题复杂化的因素


再强调一下,尽管我们选择了“忘记密码”链接來试试攻击但不是因为这个功能不安全。而是几个易攻击的点之一不要把焦点聚集在“忘记密码”上。

这个教学示例不准备全面覆盖SQL軟件注入测试的内容甚至都不是一个教程:它仅仅是一篇我们花了几小时做的渗透测试的记录。我们看了其他的关于SQL软件注入测试文章嘚讨论但它们只给出了结果而没有给出过程。

但是那些结果报告需要技术背景才能看懂并且渗透细节也是有价值的。在没有源代码的凊况下渗透人员的黑盒测试能力也是有价值的。

感谢 和 对本文的贡献还有 的排版(? 2005

我要回帖

更多关于 软件注入测试 的文章

 

随机推荐