来源:自学PHP网 时间:2015-04-17 13:03 作者: 阅读:次
[导读] 实际上到目前为止,你在网上大部分搜索SQL注入文章 基本都可以归类到一阶(first-order)SQL注入中,因为这些例子涉及的事件均发生在单个HTTP请求和响应中,如下所示:(1) 攻击者在HTTP请求...
实际上到目前为止,你在网上大部分搜索SQL注入文章 基本都可以归类到"一阶(first-order)"SQL注入中,因为这些例子涉及的事件均发生在单个HTTP请求和响应中,如下所示:
(1) 攻击者在HTTP请求中提交某种经过构思的输入。 (2) 应用处理输入,导致攻击者注入的SQL查询被执行。 (3) 如果可行的话,会在应用对请求的响应中向攻击者返回查询结果。 另一种不同的SQL注入攻击是"二阶(second-order)"SQL注入,这种攻击的事件时序通常如下所示: (1) 攻击者在HTTP请求中提交某种经过构思的输入。 (2) 应用存储该输入(通常保存在数据库中)以便后面使用并响应请求。 (3) 攻击者提交第二个(不同的)请求。 (4) 为处理第二个请求,应用会检索已经存储的输入并处理它,从而导致攻击者注入的SQL查询被执行。 (5) 如果可行的话,会在应用对第二个请求的响应中向攻击者返回查询结果。 二阶SQL注入跟等价的一阶SQL注入一样功能强大。不过它是一种更细微的漏洞,通常更难被检测到。 开发人员在考虑受感染和经过验证的数据时犯下的简单错误通常会引发二阶SQL注入。在直接从用户获取输入的位置点,很明显,该输入会潜在地受到感染。收到提示信息的开发人员会努力去防御一阶SQL注入,比如将单引号双重编码或(更倾向于)使用参数化查询。不过,如果该输入是持久的且以后会重用,则不容易看出该数据已受到感染,这会导致部分开发人员错误地对数据做不安全的处理。 请思考一个通讯簿应用,用户可以保存朋友的联系信息。创建一个联系人时,用户可以输入姓名、e-mail和地址等明细信息。应用使用INSERT语句为该联系人创建一条新的数据库记录,并将输入中的引号双重编码以防止SQL注入攻击 如下图:
该应用还允许用户修改选中的已存在联系人的明细信息。用户修改已存在的联系人时,应用将先使用SELECT语句检索该联系人的当前细节信息并将其保存到内存中;然后使用用户提供的新细节信息更新相关的数据项,并再次对该输入中的引号进行双重编码,用户没有更新的数据项在内存中将保持不变;最后使用UPDATE语句将内存中的所有数据项回写到数据库中 请参见下图:
假设将示例中的引号双重编码可以有效防止一阶SQL注入。尽管如此,应用仍然易受到二阶SQL注入攻击。要想利用该漏洞,我们首先需要使用某个字段中的攻击净荷创建一个联系人。假设数据库为Microsoft SQL Server,使用下列名称创建一个联系人:
输入中的引号被双重编码,最终的INSERT语句如下所示:
使用提交的字面值将联系人姓名安全地保存到数据库中。 接下来转向更新新创建联系人的功能,只需为地址字段提供一个新值(可以是任何能被接收的数据)即可。进行这些操作时,应用首先使用下列语句检索已经存在的联系人的细节信息:
检索出来的细节信息被保存在内存中。当然,根据姓名字段检索出来的值与最开始提交的字面值相同,因为它就是保存在数据库中的内容。应用使用新提供的值替换内存中的地址值,注意将引号标识双重编码。接下来执行下列UPDATE语句,将新信息保存到数据库中:
到目前为止,攻击已成功执行并颠覆了应用的查询。从数据库检索出来的名称被做了非安全处理,您可以摆脱查询中的数据语境并修改查询的结构。在这种概念验证攻击中,我们将数据库版本字符串复制给了联系人姓名。当查看更新过的联系人的细节信息时,它会显示在屏幕上:
要是想执行更有效的攻击,则需要使用前面介绍注入UPDATE语句时经常使用的技术(请参见第8章),将攻击先放到一个联系人字段中,然后再通过更新一个不同的字段来触发该漏洞。 寻找二阶漏洞 二阶SQL注入比一阶漏洞更难检测,因为在一个请求中提交利用后,需要在应用对另一个请求的处理中执行该利用。二阶SQL注入不适合使用那些发现大多数基于输入的漏洞时所使用的核心技术,这些技术使用各种构造好的输入来重复提交独立的请求并监视响应中的异常。与上述技术不同,我们需要在一个请求中提交构思好的输入,然后逐步跟踪应用中其他可能使用该输入的功能以便寻找异常。某些情况下,相关输入只有一个实例(例如,用户的显示名称),这时逐步跟踪应用所有的功能可能需要测试每个净荷。 当今的自动扫描器无法很有效地发现二阶SQL注入。它们通常使用不同的输入来将每个请求提交多次并监视每个请求的响应。如果接下来搜索应用的其他区域并遇到数据库错误消息,它们便会将这些消息显示给用户,希望用户能够调查并诊断存在的问题。不过,它们无法将某个位置返回的错误消息与其他位置提交的一些构思好的输入关联起来。有时不存在错误消息,二阶条件的效果可能被盲目处理。如果只存在单个相关的持久项实例或者让数据项持久存在于应用中需要多个步骤(例如,用户注册操作),那么此时问题更严重。所以,当今的扫描器无法执行一套严格的寻找二阶漏洞的系统方法。 如果无法理解应用中数据项的含义和用法,那么检测二阶SQL注入涉及的工作量会随应用功能的增加呈指数级增长。不过,手动测试人员可以凭借对功能的理解和对经常出错位置的直觉判断来降低任务的复杂度。大多数情况下,可以使用下面的系统方法来识别二阶漏洞: (1) 筹划好应用的内容和功能后进行复查,寻找所有用户能够控制的数据项,这些数据项会被应用持久保存并被后面的功能重用。单独操作每个数据项并为每个实例执行接下来的步骤。 (2) 在数据项中提交一个简单的值,数据项在SQL查询中被不安全地使用时很可能会引发问题,例如,单引号或者使用单引号引起来的字母数字型字符串。如有必要,请快速检查所有包含多个阶段的过程(比如用户注册)以保证数据值完全持久地存在于应用中。 (3) 如果发现应用的输入过滤器阻止了输入,请使用编码大小写等等绕过过滤器,网上有相关文章 (4) 快速检查应用中所有存在显式使用数据项的功能以及可能存在隐式使用的功能。寻找所有能够表明是由输入引发了问题的异常行为,比如数据库错误消息、HTTP 500状态代码、更隐秘的错误消息、受损的功能、丢失或毁坏的数据等。 (5) 对于识别出来的每个潜在问题,尝试开发一个概念验证攻击来确认是否存在SQL注入漏洞。请注意,有缺陷的持久数据可能以间接受到攻击的方式(例如,整型转换错误或后续数据验证失败)来引发异常条件。尝试使用两个引号标识来提供相同的输入并查看异常是否消失。尝试使用数据库专用的结构(比如字符串连接函数和版本标识)来确认正在修改SQL查询。如果异常条件是盲的(例如,不返回查询结果或任何错误消息),则请尝试使用时间延迟技术来确认漏洞的存在。 应该意识到,有些二阶SQL注入漏洞是纯盲的,它们不会对应用响应的任何内容产生可识别的影响。例如,如果应用的一个函数以不安全方式编写登录的持久数据并且优雅地处理所有异常,那么使用我们刚刚介绍的步骤可能就无法发现该漏洞。要想检测到这种类型的缺陷,需要先使用步骤(1)中的各种输入(在SQL查询中不安全地使用这些输入时会触发时间延迟)来重复上述步骤,之后再监视应用所有的功能以发现异常延迟。要想有效实现该目标,需要使用一种语法,而该语法是当前正在使用的数据库类型和当前正在执行的查询(SELECT、INSERT等)所专用的。实际上这是一种需要长期练习才能掌握的技能。 工具与陷阱…… 二阶漏洞的产生原因 二阶SQL注入很常见,这有点儿出人意料。本书作者曾经在很成熟且安全性至关重要的应用(比如在线银行使用的程序)中遇到过该漏洞。这类漏洞可以隐藏数年,因为检测到它们相对比较困难。 现在很多(甚至可能是大多数)开发人员已经意识到SQL注入的威胁,他们知道如何使用参数化查询来将受感染的数据安全地集成到SQL查询中。不过,他们也同样知道写参数化查询比构造简单的动态查询要花费更多精力。许多开发人员仍然对感染的概念存在误解,认为在收到用户提供的数据后只需安全地处理即可将它们看作受信任的数据。 编写SQL查询的常见方法是为明显受到感染的数据(比如从当前HTTP请求收到的内容)使用参数化查询,此外,针对每种情况对该数据是否可以在动态查询中安全地使用作出判断。这种方法很危险,因为它很容易引发疏忽,错误地对受感染数据进行不安全处理。受信任的数据源将来可能因为基础代码中其他地方的变化而受到感染,从而在不知情的情况下引入二阶漏洞。这种错误的感染观念(即只有在收到数据后才需进行安全处理)会导致数据项看起来是值得信任的,但实际上不可信。 要防御二阶漏洞,最健壮的方法是为所有数据库访问使用参数化查询并正确地参数化集成到查询中的每个可变数据项。使用这种方法来寻找真正值得信任的数据虽然需要花费少量多余的精力,但却可以避免上述错误。采用这种策略还可以使与SQL注入相关的代码安全性复查更加简单迅速。 请注意,在将数据项分配给它们的占位符之前,有些SQL查询的子部分(比如列和表名)无法被参数化,因为定义好查询之后由这些子部份构成的结构是固定的。如果要将用户提供的数据集成到查询的这些子部份中,则应该确定是否可以使用不同的方法来实现自己的功能。例如,通过将映射的索引号传递给服务器端的表和列名。如果这样不可行,则应该按照白名单原则(在使用之前)仔细验证用户数据
摘自 FUCK 1T! |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com