本章介绍一种详细的进阶方法论,渗透测试员在攻击Web应用程序时可将其作为指导思想。它涵盖了本书描述的所有漏洞与攻击技巧。虽然执行这个方法论中的所有步骤并不能确保发现某个应用程序中的所有漏洞,但是,它可以帮助探查应用程序受攻击面的所有必要区域,并利用有效的资源发现尽可能多的漏洞,这就为实现渗透测试目的提供了保证。
这种方法论探查的主要区域如图21-1所示。根据这张图,我们将深入分析每一个区域,并举例说明其中的每一项任务。图中的数字与后文中该方法论使用的分级数字目录相互对应,方便读者找到相关内容。
图21-1 本章讨论的方法论中包含的主要区域
这个方法论中的一系列任务根据它们之间的逻辑依赖关系组织和排序。我们将尽可能在任务描述中重点介绍这些依赖关系。但是,实际上,渗透测试员往往需要发挥自己的想象,思考应采取的攻击方向,并根据所发现的有关目标应用程序的信息指导攻击方向,如下所示。
在某一个阶段收集到的信息有助于返回到前一个阶段,以设计更有针对性的攻击。例如,渗透测试员可以利用访问控制漏洞获得所有用户的列表,针对验证功能实施更有效的密码猜测攻击。
在应用程序的某个区域发现的一个关键漏洞可简化对另一个区域的攻击。例如,渗透测试员可以利用文件泄露漏洞对应用程序的关键功能进行代码审查,而不是盲目地探查这些功能。
一些区域的测试结果有助于确定在其他区域可立即探查出的重复出现的漏洞模式。例如,渗透测试员可以利用应用程序输入确认过滤中的常见漏洞,迅速找到在几种不同的攻击中避开应用程序的防御机制的方法。
可以使用这个方法论中列出的步骤作为攻击指导,并把它作为避免疏忽的清单,但不一定要过于严格地遵守这些步骤。请记住以下要点:在很大程度上,我们描述的任务都属于标准的常规性任务;要对Web应用程序实施最有效的攻击,渗透测试员必须充分发挥自己的想象力。
当执行攻击Web应用程序所需的详细步骤时,应该始终记住以下注意事项。这些注意事项适用于所有必须测试的区域以及需要采用的各种技巧。
记住,一些字符在HTTP请求的不同部分具有特殊的含义。当修改请求中的数据时,应该对这些字符进行URL编码,以确保应用程序按照想要的方式解释这些字符。
&用于分隔URL查询字符串与消息主体中的参数。要插入一个字面量&字符,必须将其编码为%26。
=用于分隔URL查询字符串与消息主体中每个参数的名称与值。要插入一个字面量=字符,必须将其编码为%3d。
?用于标记URL查询字符串的起始位置。要插入一个字面量?字符,必须将其编码为%3f。
空格用于在请求的第一行标记URL的结束位置,并可用于在Cookie消息头中表示一个cookie值结束。要插入一个字面量空格字符,必须将其编码为%20或+。
因为+表示一个编码的空格,要插入一个字面量+字符,必须将其编码为%2b。
;用于在Cookie消息头中分隔单个的cookie。要插入一个字面量 ; 字符,必须将其编码为%3b。
#用于在URL中标记片段标识符。如果在浏览器的URL中输入这个字符,它会将传送给服务器的URL截短。要插入一个字面量#字符,必须将其编码为%23。
%在URL编码方案中作为前缀。要插入一个字面量%字符,必须将其编码为%25。
当然,空字节与换行符等非打印字符必须使用它们的ASCII字符代码进行URL编码。空字节与换行符的编码分别为%00和%0a。
此外,需要注意,在表单中输入URL编码的数据通常会导致浏览器执行另一层编码。例如,在表单中提交%00可能会导致向服务器发送值%2500。为此,通常最好是在拦截代理服务器中查看最终请求。
许多查找常见Web应用程序的测试需要发送各种专门设计的输入字符串,并监控应用程序的响应,从中搜索表示漏洞存在的反常现象。有时候,无论是否提交某个特定漏洞的触发器,应用程序对一个特殊请求的响应都将包含这个漏洞的签名。只要提交专门设计的特殊输入导致了与某个漏洞有关的行为(如一个特殊的错误消息),就应该重新核查,确定在相关参数中提交良性输入是否也会造成相同的行为。如果两种输入的行为相同,那么最初的发现可能是一个错误警报。
通常,应用程序会从前一个请求中收集一定量的状态,这会影响它们如何响应随后的请求。有时,当调查一个尚未确定的漏洞并隔离某一个反常行为的根源时,必须避免任何收集到的状态信息造成的影响。通常,使用一个新的浏览器进程开始另一个会话,再使用良性请求导航至观测到发生反常的位置,然后重新提交专门设计的输入,就足以达到这个目的。还可以对请求中包含的cookie和缓存信息进行调整,重复利用这种方法。此外,还可以使用Burp Repeater 等工具隔离一个请求,对它进行一些调整,然后根据需要重复多次发布这个请求。
一些应用程序使用一种负载平衡的配置,其中连续的HTTP请求可能会被不同的后端服务器在Web层、展现层、数据层或其他层处理。不同服务器在配置上的细微差异可能会影响到处理结果。另外,一些成功的攻击将改变处理请求的某一台服务器的状态,例如在Web根目录上创建一个新的文件。为隔离特殊操作造成的影响,可能需要连续提交几个相同的请求,测试每个请求的结果,直到请求被相关服务器处理。
假设需要在咨询工作中采用这种方法,渗透测试员应当首先确定测试范围,明确了解测试包含的主机名、URL与功能以及允许执行的测试类型是否存在任何限制。还应当向应用程序所有者告知对一个“黑盒”目标实施任何渗透测试包含的内在风险,并建议他们在开始测试前备份所有重要的数据。
(1)配置浏览器,使用首选集成代理/抓取工具。可以使用Burp与WebScarab监控和解析由代理服务器处理的Web内容,对站点实行被动抓取。
(2)如果有用,配置浏览器,使用一个扩展(如IEWatch)监控和分析被浏览器处理的HTTP与HTML内容。
图21-2 解析应用程序内容
(3)以常规方式浏览整个应用程序,访问发现的每一个链接和URL,提交每一个表单并执行全部多阶段功能。尝试在JavaScript激活与禁用、cookie激活与禁用的情况下浏览。许多应用程序能够处理各种浏览器配置,渗透测试员可以获得应用程序内的不同内容和代码路径。
(4)如果应用程序使用身份验证,并且渗透测试员已经拥有或可以建立一个登录账户,那么他就可以使用该账户访问被保护的功能。
(5)当浏览、监控通过拦截代理服务器的请求与响应时,了解被提交的数据种类,了解客户端如何控制服务器端应用程序的行为。
(6)检查被动抓取生成的站点地图,确定任何尚未使用浏览器访问到的内容或功能。根据抓取结果,确定发现每一项内容的位置(例如,在Burp Spider中,检查“链接自”的详细内容)。使用浏览器访问以上内容,以便爬虫解析服务器的响应,确定其他任何内容。重复执行上述步骤,直到无法再确定其他内容或功能。
(7)完成手动浏览和被动抓取后,可以用一组发现的URL作为种子,使用爬虫抓取应用程序。有时,这样可发现其他在手动浏览时忽略的内容。在进行自动抓取前,首先应确定任何危险的或可能会中断应用程序会话的URL,并配置爬虫,将它们排除在抓取范围之外。
(1)使用因特网搜索引擎和历史档案(例如,Wayback Machine)确定它们编入索引或保存的与目标应用程序有关的内容。
(2)使用高级搜索选项提高搜索的效率。例如,在Google中,可以使用site:获取所有与目标站点有关的内容;使用link:获取链接到目标站点的其他站点。如果在搜索过程中找到现有应用程序已经删除的内容,仍然可以从搜索引擎的缓存中查看这些内容。这些已被删除的内容中可能包含尚未删除的其他资源的链接。
(3)搜索在应用程序内容[如联系信息,包括并未在屏幕上显示的内容(如HTML注释)]中发现的任何姓名与电子邮件地址。除Web搜索外,还应进行新闻和分组搜索。在因特网论坛上寻找与目标应用程序及其支持基础架构有关的所有技术信息。
(4)检查已发布的任何WSDL文件,以生成应用程序可能采用的功能名称和参数值列表。
(1)确定应用程序如何处理访问不存在的资源的请求。手动提出一些请求,访问已知有效和无效的资源,比较应用程序对这些请求的响应,找到一种确定资源并不存在的简单方法。
(2)获取常见文件与目录名以及常见的文件扩展名列表。将这些列表添加到已经确定的应用程序内容以及通过这些内容推断出的其他内容中。设法了解应用程序开发者采用的命名方案。例如,如果有页面被命名为AddDocument.jsp和ViewDocument.jsp,就可能有名为EditDocument.jsp和RemoveDocument.jsp的页面存在。
(3)审查所有客户端代码,确定任何与服务器端内容(包括HTML注释和禁用的表单元素)有关的线索。
(4)使用第14章描述的自动化技巧,根据目录名、文件名及文件扩展名列表提出大量请求。监控应用程序的响应,确定存在的可访问的内容。
(5)以刚刚枚举出的内容和模式作为用户指导的抓取以及自动化深入搜索的基础,重复进行这些内容查找操作。
(1)针对Web服务器运行Nikto,探查所有默认或已知存在的内容。使用Nikto的选项提高探查的效率。例如,使用–root选项指定查找默认内容的目录,或者使用-404选项指定一个标识定制化“文件未发现”页面的字符串。
(2)手动核查所有可能有用的发现,减少探查结果中的错误警报。
(3)请求服务器的根目录,在Host消息头中指定IP地址,确定应用程序是否使用任何不同的内容做出响应。如果是,则针对该IP地址及服务器名称运行Nikto扫描。
(4)向服务器的根目录提出请求,指定一系列User-Agent消息头,如www.useragentstring.com/pages/useragentstring.php所示。
(1)确定任何通过在请求参数中提交一个功能标识符(例如,/admin.jsp?action=editUser或/main.php?func=A21)访问特殊应用程序功能的情况。
(2)对用于访问单项功能的机制,应用21.1.3节中使用的内容查找技巧。例如,如果应用程序使用一个包含功能名称的参数,首先应该确定指定无效功能时应用程序的行为,设法找到一个确定被请求的功能确实有效的简单方法。列出常用的功能名称或遍历所使用的标识符的语法范围。使枚举有效功能的操作自动化,使其尽可能迅速高效地完成。
(3)如果适用,根据功能路径而非URL编制一幅应用程序内容地图,列出所有枚举出的功能和逻辑路径以及它们之间的依赖关系。(相关实例请参阅第4章。)
(1)选择一个或几个使用隐藏调试参数(如debug=true)的应用程序页面或功能。它们最有可能出现在登录、搜索、文件上传或下载等关键功能中。
(2)使用常用调试参数名(如debug、test、hide和source)与常用参数值(如true、yes、on和1)列表,排出这些名称与值的全部组合,向每一个目标功能提交每个名/值对。对于POST请求,在URL查询字符串和请求主体中提交参数。使用第14章描述的技巧自动完成这项操作。例如,可以使用Burp Intruder中的“集束炸弹”攻击类型将两组有效载荷的全部组合结合起来。
(3)在应用程序的响应中查找任何表示添加的参数对应用程序的行为造成影响的反常现象。
图21-3 分析应用程序
(1)确定为使应用程序正常运行而建立的核心功能以及每项功能旨在执行的操作。
(2)确定应用程序采用的核心安全机制以及它们的工作机制。重点了解处理身份验证、会话管理与访问控制的关键机制以及支持它们的功能,如用户注册和账户恢复。
(3)确定所有较为外围的功能和行为,如重定向使用、站外链接、错误消息、管理与日志功能。
(4)确定任何与应用程序在其他地方使用的标准GUI外观、参数命名或导航机制不一致的功能,然后将其挑选出来以进行深入测试。
(1)确定在应用程序中引入用户输入的所有进入点,包括URL、查询字符串参数、POST数据、cookie与其他由应用程序处理的HTTP消息头。
(2)分析应用程序使用的所有定制数据传输或编码机制,如非常规的查询字符串格式。了解被提交的数据是否包含参数名与参数值,或者是否使用了其他表示方法。
(3)确定所有在应用程序中引入用户可控制或其他第三方数据的带外通道,例如,处理和显示通过SMTP收到的消息的Web邮件应用程序。
(1)确定客户端使用的各种不同技术,如表单、脚本、cookie、Java applet、ActiveX控件与Flash对象。
(2)尽可能确定服务器端使用的技术,包括脚本语言、应用程序平台以及与数据库和电子邮件系统等后端组件的交互。
(3)检查在应用程序响应中返回的HTTP Server消息头,查找定制HTTP消息头或HTML源代码注释中出现的其他任何软件标识符。注意,有时候,不同的应用程序区域由不同的后端组件处理,因此渗透测试员可能会收到不同的标识符。
(4)运行Httprint工具,为Web服务器做“指纹标识”。
(5)检查内容解析过程中获得的结果,确定所有有助于了解服务器端所使用技术的文件扩展名、目录或其他URL序列。检查所有会话令牌和其他cookie的名称。同时,使用Google搜索与这些内容有关的技术。
(6)分确定任何看似有用的、属于第三方代码组件的脚本名称与查询字符串参数。在Google中使用inurl:限定词搜索这些内容,查找所有使用相同脚本与参数、并因此使用相同第三方组件的应用程序。对这些站点进行非入侵式的审查,这样做可能会发现其他在攻击的应用程序中没有明确链接的内容和功能。
(1)设法确定服务器端应用程序的内部结构与功能以及用于实现客户端可见行为的后台机制。例如,获取客户订单的功能可能与数据库进行交互。
(2)确定各种与每一项功能有关的常见漏洞。例如,文件上传功能可能易于受到路径遍历攻击;用户间通信可能易于受到XSS攻击;“联络我们”功能可能易于受到SMTP注入攻击。请参阅第4章了解与特定功能和技术有关的常见漏洞实例。
(3)制订一个攻击计划,优先考虑最有用的功能以及与它有关的最严重的潜在漏洞。使用这份计划作为指导,决定应对本章讨论的方法的其他区域投入多少时间和精力。
图21-4 测试客户端控件
(1)在应用程序中,确定隐藏表单字段、cookie和URL参数明显用于通过客户端传送数据的所有情况。
(2)根据以上数据出现的位置及其名称与值,尝试确定它在应用程序逻辑中发挥的作用。
(3)修改数据在应用程序相关功能中的值。确定应用程序是否处理字段中提交的任意值,以及是否可以通过这样做干扰应用程序的逻辑或破坏任何安全控件。
(4)如果应用程序通过客户端传送模糊数据,渗透测试员可以以各种方式攻击这种传输机制。如果数据被模糊处理,渗透测试员可以破译所使用的模糊算法,从而在模糊数据中提交任意数据。即使它进行了安全加密,仍然可以在其他情况下重新提交这个数据,干扰应用程序的逻辑。请参阅第5章了解有关这些和其他攻击的更多详情。
(5)如果应用程序使用ASP.NET ViewState,对其进行测试,确定是否可以破坏它,或者其中是否包含任何敏感信息。请注意,不同应用程序页面使用ViewState的方式可能有所不同。
(a)使用Burp Suite中的ViewState分析器确定EnableViewStateMac选项是否被激活,该选项表示ViewState的内容不能被修改。
(b)审查解码后的ViewState,确定它包含的所有敏感数据。
(c)修改一个被解码的参数值,重新对其编码,然后将它提交给ViewState。如果应用程序接受修改后的参数值,那么应当把ViewState当做在应用程序中引入任意数据的一个输入渠道,并对它包含的数据执行与其他请求参数相同的测试。
(1)在将用户输入提交给服务器之前,确定使用长度限制和JavaScript检查等客户端控件对其进行确认的任何情况。当然,这些客户端控件可被轻易避开,因为渗透测试员可以向服务器发送任意请求。例如:
(2)通过提交通常被客户端控件阻止的输入,轮流测试每一个受影响的字段,确定服务器是否使用相同的输入确认。
(3)能够避开客户端确认并不表示存在任何漏洞。因此,应该仔细审查应用程序实施的确认机制,弄清应用程序是否依赖客户端控件保护自身,阻止畸形输入,以及这些输入是否可触发任何可被利用的条件。
(4)检查每一个HTML表单,确定所有禁用的元素,如灰色提交按钮,例如:
如果发现任何禁用的元素,就与其他表单参数一起提交这些元素,确定该元素是否会对应用程序的处理逻辑造成影响,渗透测试员可在攻击过程中利用这些影响。或者使用自动化代理服务器规则,自动启用禁用的字段,如Burp Proxy的“HTML修改”规则。
(1)为正在测试的客户端技术设置一个本地拦截代理服务器,并监视客户端与服务器之间的所有流量。如果数据被序列化,可以使用某种去序列化工具,如Burp的内置AMF支持工具或用于Java的DSer Burp插件。
(2)浏览在客户端中呈现的所有功能。使用拦截代理服务器中的标准工具重新提出关键请求或修改服务器响应,以确定任何可能的敏感功能或强大功能。
(1)确定应用程序使用的任何applet。通过拦截代理服务器查找以下请求的任何文件类型:
还可以在应用程序页面的HTML源代码中查找applet标签。例如:
(2)分析HTML源代码对applet方法的全部调用情况,并确定applet返回的数据是否被提交到服务器。如果这个数据为模糊数据(即经过模糊处理或加密),那么要想对其进行修改,可能需要反编译applet,获得它的源代码。
(3)在浏览器中输入URL,下载applet字节码,并将文件保存在本地计算机中。字节码文件的名称在applet标签的code属性中指定,该文件将位于codebase属性(如果此属性存在)指定的目录中;否则,它将保存在applet标签出现的页面所在的目录中。
(4)使用适当的工具将字节码反编译成源代码。例如:
以下是一些适用于反编译不同浏览器扩展组件的工具:
Java——Jad
Flash——SWFScan,Flasm/Flare
Silverlight——.NET Reflector
如果applet被压缩成JAR、XAP或SWF文件,可以使用WinRar或WinZip等标准档案读取工具将其解压。
(5)分析相关源代码(从执行返回模糊数据的方法的源代码开始),了解应用程序执行了何种处理。
(6)确定applet中是否包含任何可用于对任意输入进行相关模糊处理的公共方法。
(7)如果其中没有这类方法,修改applet的源代码,以达到令其执行的任何确认失效或允许模糊处理任意输入的目的。然后可以使用供应商提供的编译工具将源代码重新编译成最初的文件格式。
(1)对于大型客户端应用程序,要反编译、修改并重新打包整个应用程序往往非常困难,这时会遇到各种错误。通常,对于这些应用程序,在处理时附加运行时调试器会更加容易。JavaSnoop可对Java应用程序执行上述操作。Silverlight Spy是一款免费工具,可对Silverlight客户端进行运行时监视。
(2)找到应用程序用于实现安全相关的业务逻辑的关键功能和值,并在调用目标功能时放置断点。根据需要修改参数或返回值,以破坏其安全防御。
(1)确定应用程序使用的所有ActiveX控件。寻找通过拦截代理服务器请求的所有.cab文件类型,或者在应用程序页面的HTML源代码中寻找对象标签。例如:
(2)通常,可以通过在进程上附加调试器并直接修改被处理的数据,或者改变程序的执行路径,破坏ActiveX控件实施的所有输入确认。请参阅第5章了解这种攻击的更多详情。
(3)通常,可以根据ActiveX控件导出的各种方法的名称及提交给它们的参数,猜测这些方法的作用。使用COMRaider工具可枚举出ActiveX控件导出的各种方法。测试是否可以操纵这些方法,从而影响控件的行为并避开它执行的所有确认机制。
(4)如果控件的作用是收集或核实某些与客户端计算机有关的信息,就可以使用Filemon与Regmon工具监控控件收集到的信息。通常,可以在系统注册表和文件系统中创建适当的数据项,修改控件使用的输入,从而影响其行为。
(5)在任何ActiveX控件中探查可用于攻击应用程序其他用户的漏洞。渗透测试员可以修改用于调用控件的HTML代码,向它的方法提交任意数据,并监控处理结果;可以寻找看似危险的方法名称,如LaunchExe,还可以使用COMRaider对ActiveX控件进行基本的模糊测试,确定缓冲区溢出之类的漏洞。
图21-5 测试验证机制
(1)确定应用程序使用的验证技术(如表单、证书或多元机制)。
(2)确定所有与验证有关的功能(如登录、注册、账户恢复等)。
(3)如果应用程序并未采用自动自我注册机制,确定是否可以使用任何其他方法获得几个用户账户。
(1)在应用程序中查找有关用户密码最小强度规则的说明。
(2)尝试使用所有自我注册或密码修改功能,设定各种脆弱密码,确定应用程序实际应用的密码强度规则。尝试使用短密码、仅包含字母字符的密码、全部大写或全部小写字符的密码、单词型密码以及将当前用户名作为密码。
(3)测试不完整的证书确认。设定一个强大并且复杂的密码(例如,密码长度为12个字符,其中包含大小写字母、数字和印刷字符)。尝试用这个密码的各种变化形式登录,如删除最后一个字符,改变字符的大小写,或者删除任何特殊字符。如果其中一些尝试取得成功,继续系统性地尝试,了解完整的证书确认过程。
(4)了解最小密码强度规则以及密码确认的程度后,再设法确定密码猜测攻击所需要使用的密码值范围,以提高攻击成功的可能性。尝试找出所有的内置账户,它们可能并不满足标准密码复杂度要求。
(1)确定各种验证功能通过在屏幕上显示的输入字段、隐藏表单字段或cookie提交用户名的每一个位置。这些位置通常存在于登录、自我注册、密码修改、退出与账户恢复功能中。
(2)向每个位置提交两个请求,其中分别包含一个有效和一个无效的用户名。分析服务器对每一个请求的响应的各方面细节,包括HTTP状态码、任何重定向、屏幕上显示的信息、任何隐藏在HTML页面源代码中的差异以及服务器做出响应的时间。请注意,其中一些差异可能极其细微(例如,看似相同的错误消息可能包含排版方面的细小差异)。可以使用拦截代理服务器的“历史记录”功能分析进出服务器的所有流量。WebScarab的一项功能可对两个响应进行比较,以迅速确定它们之间的任何差异。
(3)如果从提交有效和无效用户名返回的响应中发现任何差异,那么使用另外一组用户名重复进行测试,确定响应之间是否存在相同模式的差异,以此作为自动化用户名枚举的基础。
(4)检查应用程序中任何其他可帮助获得一组有效用户名的信息泄露源,例如,日志功能、注册用户列表以及在源代码注释中直接提及姓名或电子邮件地址的情况。
(5)定位任何接受用户名的附属验证机制,并确定是否可以将其用于用户名枚举。特别注意允许指定用户名的注册页面。
(1)确定应用程序提交用户证书的每一个位置。通常,用户主要在主登录功能和密码修改功能中提交证书。如果用户可提交任意用户名,密码修改功能才会成为密码猜测攻击的有效目标。
(2)在每一个位置,使用一个受控制的账户手动提出几个包含有效用户名但证书无效的请求。监控应用程序的响应,确定它们之间的所有差异。如果应用程序经过大约10次登录失败后还没有返回任何有关账户锁定的消息,再提交一个包含有效证书的请求。如果这个请求登录成功,应用程序可能并未采用任何账户锁定策略。
(3)如果没有控制任何账户,那么尝试枚举或猜测一个有效的用户名,并使用它提交几个无效的请求,监控任何有关账户锁定的错误消息。当然,应该意识到,这种测试可能会导致其他用户的账户被冻结或禁用。
(1)确定如果用户忘记他们的证书,应用程序是否允许他们重新控制自己的账户。通常,在主登录功能附近有一个“忘记密码”链接即表示应用程序采用了密码恢复功能。
(2)使用一个受控制的账户完成整个密码恢复过程,了解账户恢复功能的运作机制。
(3)如果该功能使用机密问题之类的质询,确定用户是否可以在注册时设定或选择他们自己的质询。如果可以,使用一组枚举出的或常见的用户名获取一组质询,并对其进行分析,找出任何很容易猜测出答案的质询。
(4)如果该功能使用密码“暗示”,采取和上个步骤相同的操作获得一组密码暗示,确定任何可轻易猜测出答案的暗示。
(5)对账户恢复质询进行与主登录功能相同的测试,确定可对其实施自动猜测攻击的漏洞。
(6)如果该功能要求向用户发送一封电子邮件才能完成整个恢复过程,寻找任何可帮助控制其他用户账户的弱点。确定是否有可能控制接收以上电子邮件的地址。如果邮件内容中包含一个唯一的恢复URL,使用受控制的一个电子邮件地址获得若干邮件,尝试确定任何可帮助预测发布给其他用户的URL模式。应用21.5.3节描述的方法确定所有可预测的序列。
(1)如果主登录功能或它的支持逻辑包含“记住我”功能,激活这项功能并分析它的作用。如果该功能允许用户随后不输入任何证书即可登录,那么应该仔细分析这项功能,查找其中存在的所有漏洞。
(2)仔细检查激活“记住我”功能时设定的所有持久性cookie。寻找任何明确标识出用户身份或明显包含可预测的用户标识符的数据。
(3)即使其中保存的数据经过严密编码或模糊处理,也要仔细分析这些数据,并比较“记住”几个非常类似的用户名和密码的结果,找到任何可对原始数据进行逆向工程的机会。应用21.5.2节描述的方法确定所有有用的数据。
(4)根据以上结果,适当修改cookie的内容,尝试伪装成其他应用程序用户。
(1)如果应用程序包含任何明确的功能,允许一名用户伪装成另一名用户,那么仔细审查这项功能,查找所有允许未经正确授权即可伪装成任意用户的漏洞。
(2)寻找所有用户提交的、用于确定伪装目标的数据。尝试修改这个数据,伪装成其他用户,特别是可帮助提升权限的管理用户。
(3)当针对其他用户账户实施自动密码猜测攻击时,寻找所有明显使用多个有效密码的账户,或者几个使用相同密码的账户。这表示应用程序提供后门密码,以便管理员使用它时以任何用户的身份访问应用程序。
(1)如果应用程序提供自我注册功能,允许指定想要的用户名,那么尝试使用不同的密码注册同一个用户名。
(2)如果应用程序阻止第二个注册尝试,就可以利用这种行为枚举出注册用户名。
(3)如果应用程序注册以上两个账户,深入分析这种情况,确定用户名与密码发生冲突时应用程序的行为。尝试修改一个账户的密码,使其与另一个密码相同。同时,尝试使用完全相同的用户名与密码注册两个账户。
(4)如果在用户名与密码发生冲突时,应用程序发出警报或产生一个错误,就可以利用这种行为实施自动化猜测攻击,确定其他用户的密码。针对一个枚举出的或猜测到的用户名,尝试使用这个用户名与不同的密码创建账户。应用程序拒绝某个特殊的密码即表示它可能是目标账户的现有密码。
(5)如果应用程序接受相互冲突的用户名与密码,并且不产生错误,那么使用相互冲突的证书登录,确定应用程序的行为,以及是否可以利用这种行为不经授权即可访问其他用户的账户。
(1)如果用户名或密码由应用程序自动生成,设法获得几个紧密相连的用户名或密码,确定任何可探测的顺序或模式。
(2)如果用户名以可预测的方式生成,那么向后推导,获得一组可能有效的用户名。这些用户名可作为自动密码猜测与其他攻击的基础。
(3)如果密码以可预测的方式生成,那么推导这种模式,获取应用程序向其他用户发布的一组密码。渗透测试员可以将这些密码与获得的用户名进行组合,实施密码猜测攻击。
(1)遍历所有需要传输证书、与验证有关的功能,包括主登录功能、账户注册功能、密码修改功能以及允许查看或更新用户个人信息的页面。使用拦截代理服务器监控客户端与服务器之间的所有流量。
(2)确定在来回方向传输证书的每一种情况。可以在拦截代理服务器中设置拦截规则,标记包含特殊字符串的消息。
(3)如果证书在URL查询字符串中传输,那么这些证书可能会通过浏览器历史记录、屏幕、服务器日志以及Referer消息头(如果访问第三方链接)泄露。
(4)如果证书被保存在cookie中,可能会通过XSS攻击或本地隐私攻击泄露。
(5)如果证书被从服务器传送回客户端,攻击者就可以利用会话管理或访问控制漏洞,或者通过XSS攻击获取这些证书。
(6)如果证书通过未加密连接传送,它们很可能被窃听者拦截。
(7)如果使用HTTPS提交证书,但使用HTTP加载登录表单,那么应用程序就容易遭受中间人的攻击,攻击者也可能使用这种攻击手段获取证书。
(1)如果应用程序通过某种带外通道创建账户,或者它提供的自我注册功能本身并不决定用户使用的全部初始证书,那么应该确定应用程序采用什么方法向新用户分配证书。常用的方法包括发送电子邮件,或者向邮政地址寄送信件。
(2)如果应用程序生成以带外方式分配的账户激活URL,尝试注册几个紧密相连的新账户,并确定收到的URL中的顺序。如果能确定某种模式,努力预测应用程序发送给最近与后续用户的URL,并尝试使用这些URL占有他们的账户。
(3)尝试多次重复使用同一个激活URL,看看应用程序是否允许这样做。如果遭到拒绝,尝试在重复使用URL之前锁定目标账户,看看URL是否仍然可用。确定使用这种方法是否可以给一个已经激活的账户设定一个新密码。
(1)如果可以访问散列密码,应检查共享同一散列密码值的账户。尝试以采用最常用的散列值的密码登录。
(2)使用相关散列算法的离线彩虹表查找明文值。
(1)对于要求应用程序检查用户证书的每一项功能(包括登录与密码修改功能),使用受控制的账户以正常方式访问这些功能。注意它们提交给应用程序的每一个请求参数。
(2)连续多次重复以上过程,以各种无法预料的方式轮流修改每一个参数,破坏应用程序的逻辑。对每一个参数进行以下修改。
提交一个空字符串值。
完全删除名/值对。
提交非常长和非常短的值。
提交字符串代替数字或提交数字代替字符串。
以相同和不同的值,多次提交同一个命名参数。
(3)仔细检查应用程序对上述请求的响应。如果出现任何无法预料的差异,对这个结果进行进一步测试。如果某个修改造成行为改变,设法将这个修改与其他更改组合在一起,推动应用程序的逻辑达到其限制。
(1)如果任何与验证有关的功能需要在一系列不同的请求中提交证书,确定每个阶段的主要目的,同时注意每个阶段提交的参数。
(2)连续多次重复以上过程,修改提交请求的顺序,破坏应用程序的逻辑。相关测试包括:
以不同的顺序完成所有阶段,到达想要的那个阶段;
轮流直接进入每一个阶段,然后按正常的顺序访问后续步骤;
几次访问上述功能,轮流省略每一个阶段,然后在后一个阶段继续按正常的顺序访问;
根据观察到的结果及每个功能阶段的主要目的,尝试通过其他方式修改访问这些阶段的顺序,并访问开发者没有预料到的阶段。
(3)确定是否有任何一项信息(如用户名)在几个阶段被提交,或者是因为用户提交了它几次,或者是因为它通过客户端在隐藏表单字段、cookie或预先设置的查询字符串参数中传送。如果是这样,尝试在不同的阶段提交不同的值(包括有效和无效的值),并观察其后果。设法确定提交的数据是否是多余的,或者在一个阶段确认,随后即被应用程序信任,或者在不同的阶段通过不同的检查进行确认。尝试利用应用程序的行为获得未授权访问,或者降低多阶段机制实施的控制的效率。
(4)寻找所有通过客户端传送的数据。如果应用程序使用隐藏参数在各个功能阶段中追踪进程的状态,那么攻击者就可以修改这些参数,从而破坏应用程序的逻辑。
(5)如果进程的任何部分要求应用程序采用一个随机变化的质询,对它进行测试,查找以下两种常见的缺陷。
如果一个指定质询的参数与用户的响应一起提交,确定是否可以修改这个值,选择自己的质询。
多次使用相同的用户名处理上述不断变化的质询,确定每次是否出现一个不同的质询。如果每次的质询各不相同,那么就可以重复进入这个阶段,直到应用程序显示希望的质询,以这种方式选择想要的质询。
(1)分析在各种验证功能中发现的所有漏洞,确定所有可在攻击应用程序过程中用于实现自己的目标的漏洞。通常,这包括尝试以另一名用户的身份进行验证;如有可能,以拥有管理权限的用户身份验证。
(2)在实施自动攻击之前,留意已经确定的所有账户锁定防御。例如,当对登录功能实施用户名枚举攻击时,在请求中提交一个常用的而不能完全随机的密码,以免在每一个发现的用户名上浪费一次登录失败尝试。同样,应以广度优先而非深度优先的方式实施密码猜测攻击。首先使用单词列表中最常用的脆弱密码,然后使用其他值,对每一个枚举出的用户名实施密码猜测攻击。
(3)构建在密码猜测攻击中使用的单词列表时,应考虑密码强度规则以及密码确认机制的完整性,避免使用不可能的或多余的测试密码值。
(4)使用第14章描述的技巧实施尽可能多的自动攻击,提高攻击的速度与效率。
图21-6 测试会话管理机制
(1)分析应用程序用于管理会话与状态的机制。确定应用程序是否使用会话令牌或其他方法处理每一名用户提交的各种请求。请注意,用户通过验证后,一些验证技术(如HTTP验证)并不需要使用完整的会话机制重新确认用户的身份。同时,一些应用程序采用一种无会话状态机制,通常使用一个加密或模糊处理的表单,通过客户端传送所有状态信息。
(2)如果应用程序使用会话令牌,确定它到底使用哪些数据重新确认用户的身份。HTTP cookie、查询字符串参数以及隐藏表单字段均可用于传送令牌。可使用不同的数据共同重新确认用户的身份,不同的数据可能被不同的后端组件使用。有时,看似为会话令牌的数据实际并未被应用程序使用,例如,Web服务器生成的默认cookie。
(3)为确定应用程序到底使用哪些数据作为令牌,找到一个确信依赖会话的页面(如某一名用户的“用户资料”页面)或功能,并向它提出几个请求,系统性地删除怀疑被用作令牌的数据项。如果删除某个数据项后,应用程序不再返回依赖会话的页面,即可确定该数据项为会话令牌。Burp Repeater是执行这些测试的有用工具。
(4)确定应用程序使用哪些数据重新确认用户的身份后,确定它是否对每个令牌进行完整的确认,或者是否忽略令牌的某些组成部分。修改令牌的值,一次修改一字节,并确定修改后的值是否仍然被应用程序接受。如果发现令牌的某些部分并未被用于保持会话的状态,就不必再深入分析它们。
(1)在不同时间以几个不同的用户登录,记录服务器发布的令牌。如果应用程序允许自我注册,就可以选择自己的用户名,用一系列存在细微差别的相似用户名登录,如A、AA、AAA、AAAA、AAAB、AAAC、AABA等。如果其他与某一名用户有关的数据(如电子邮件地址)在登录阶段提交或保存在用户资料中,对其进行与前面类似的系统化修改,并截获收到的令牌。
(2)分析收到的令牌,查找所有与用户名和其他用户可控制的数据有关的内容。
(3)分析令牌,查找所有明显的编码或模糊处理方案。查找用户名长度与令牌长度之间的所有相互关系;这种关系表示应用程序明显使用了某种模糊处理或编码方案。如果用户名包含一组相同的字符,在令牌中寻找表示可能使用XOR模糊处理的对应字符序列;在令牌中寻找仅包含十六进制字符的序列,它表示应用程序可能对ASCII字符串进行了十六进制编码处理,或者披露其他信息。寻找以等号(=)结尾的字符序列或仅包含其他有效Base64字符的序列,如a–z、A–Z、0–9、+和/。
(4)如果可以从会话令牌样本中获得任何有意义的数据,确定这些信息是否足以帮助发动攻击,猜测出最近发布给其他应用程序用户的令牌。找到一个依赖会话的应用程序页面,使用第14章描述的技巧自动生成和测试可能的令牌。
(1)使用一个可使服务器返回一个新令牌的请求(例如一个成功登录请求),生成并截获大量紧密相连的会话令牌。
(2)设法确定令牌样本中的所有模式。在所有情况下,都应使用Burp Sequtncer对应用程序令牌的随机特性进行详细的统计测试,如第7章所述。然而,根据自动扫描结果,仍然需要进行一些手动分析。
理解应用程序重新确认用户身份的令牌和子序列。忽略并未用于确定用户身份的所有数据,即使样本中的这些数据发生了变化。
如果不清楚令牌或者令牌的所有组成成分使用何种类型的数据,尝试使用各种解码方法(例如Base64),看能否得到更有意义的数据。有时可能有必要连续使用几种解码方法。
设法确定解码后的令牌或组成成分数据中存在的所有模式。计算连续值之间的差距。即使这些值看似杂乱无章,但是它们之间仍然可能存在固定的差距,允许渗透测试员显著缩小蛮力攻击的范围。
等待几分钟后,截取类似的一组令牌样本,重复进行上述分析。设法确定令牌的内容是否具有时间依赖性。
(3)如果已经确定了所有模式,使用一个不同的IP地址与用户名截获另一组令牌样本,确定是否可以探查到相同的模式,或者是否可以对第一组令牌进行推导,猜测出第二组令牌。
(4)如果能够确定可利用的序列或时间依赖关系,考虑这些信息是否足以帮助发动攻击,猜测出最近发布给其他应用程序用户的令牌。使用第14章描述的技巧自动生成和测试可能的令牌。除最简单的序列外,可能需要在攻击中使用某些定制脚本。
(5)如果会话ID似乎是定制编写的,可以使用Burp Intruder中的“位翻转”有效载荷源继续轮流修改会话令牌中的每个位。同时,在响应中查找表明修改令牌是否会导致会话无效,或会话是否属于其他用户的字符串。
(1)以正常方式访问应用程序,从“起始”URL中的未通过验证的内容开始,到登录过程,再到应用程序的全部功能。留意发布新会话令牌的每一种情况,确定哪些部分使用HTTP通信,哪些部分使用HTTPS通信。可以使用拦截代理器的日志功能记录这些信息。
(2)如果应用程序使用HTTP cookie传送会话令牌,应确认其是否设置了安全标记,防止通过HTTP连接传送令牌。
(3)在正常使用应用程序的情况下,确定会话令牌是否通过HTTP连接传送。如果是这样,它们就很容易被拦截。
(4)如果应用程序在未通过验证的区域使用HTTP,然后在登录或通过验证的区域转换到HTTPS,那么确认应用程序是否为HTTPS通信发布一个新的令牌,或者应用程序在转换到HTTPS后是否仍然使用HTTP阶段的令牌。如果是这样,它们就很容易被拦截。
(5)如果应用程序的HTTPS区域包含指向HTTP URL的链接,访问这些链接,确认在访问过程中是否有会话令牌被提交;如果是这样,该令牌或者继续有效,或者立即被服务器终止。
(1)如果在应用程序解析过程中能确定任何日志、监控或诊断功能,应仔细检查这些功能,确定它们是否泄露任何会话令牌。确定在正常情况下哪些人有权访问这些功能;如果只有管理员能够使用这些功能,那么确认低权限用户是否可以利用任何其他漏洞访问它们。
(2)确定所有在URL中传送会话令牌的情况。可能应用程序通常以更加安全的方式传送令牌,而开发者在特定情况下使用URL来解决特殊难题。如果是这样,当用户访问站外链接时,这些令牌将在Referer消息头中传送。确定所有允许在其他用户可查看的页面中插入任意站外链接的功能。
(3)如果能够收集到发布给其他用户的有效会话令牌,就对每个令牌进行测试,确定它是否属于管理用户(例如,尝试使用令牌访问某个特权功能)。
(1)用同一个用户账户从不同的浏览器进程或从不同的计算机两次登录应用程序。确定这两个会话是否都处于活动状态。是就表示应用程序支持并行会话,可让攻破其他用户证书的攻击者能够利用这些证书,而不会有被检测出来的风险。
(2)使用同一个用户账户从不同的浏览器进程或从不同的计算机登录并退出应用程序几次。确定应用程序在每次登录时是发布一个新会话令牌,还是发布相同的令牌。如果每次发布相同的令牌,那么应用程序根本没有正确使用令牌,而是使用唯一持久性字符串重新确认用户身份。在这种情况下,应用程序就没有办法防止并行登录或正确实施会话超时。
(3)如果令牌明显包含某种结构和意义,设法将标识用户身份的成分与无法辨别的成分区分开来。尝试修改与用户有关的所有令牌成分,使其指向其他已知的应用程序用户,并确定修改后的令牌是否被应用程序接受,以及能够让攻击者伪装成该用户。请参阅第7章了解这种细微漏洞的示例。
(1)当测试会话超时与退出漏洞时,主要测试服务器如何处理会话与令牌,而不是客户端发生的任何事件。在客户端浏览器内对令牌执行的操作并不能终止会话。
(2)检查服务器是否执行会话终止。
登录应用程序获得一个有效令牌。
不使用这个令牌,等待一段时间后,用这个令牌提交一个访问受保护页面(如“我的资料”页面)的请求。
如果该页面正常显示,那么令牌仍然处于活动状态。
使用反复试验的方法确定会话终止超时时间为多久,或者一个令牌在前一次使用它提交请求几天后是否仍被使用。可配置Burp Intruder递增连续请求之间的时间间隔,自动完成这项任务。
(3)检查退出功能是否存在。如果应用程序使用退出功能,测试它是否能够在服务器上有效确认用户的会话。退出后,尝试重新使用原有的令牌,使用它请求一个受保护的页面,确定其是否仍然有效。如果令牌仍然有效,那么即使用户已经“退出”,他们依然易于受到会话劫持攻击。可以使用Burp Repeater从代理历史记录中不断发送一个特殊的请求,观察退出后应用程序是否做出不同的响应。
(1)如果应用程序向未通过验证的用户发布令牌,获取令牌并登录。如果应用程序在登录后并不发布一个新令牌,就表示它易于受到会话固定攻击。
(2)即使应用程序并不向未通过验证的用户发布会话令牌,也可通过登录获得一个令牌,然后返回登录页面。如果应用程序“愿意”返回这个页面,即使已经通过验证,也可使用相同的令牌以另一名用户的身份提交另一次登录。如果应用程序在第二次登录后并不发布一个新令牌,就表示它易于受到会话固定攻击。
(3)确定应用程序会话令牌的格式。用一个捏造的、格式有效的值修改令牌,然后尝试使用它登录。如果应用程序允许使用一个捏造的令牌建立通过验证的会话,就表示它易于受到会话固定攻击。
(4)如果应用程序并不支持登录功能,但处理敏感数据(如个人信息和支付细节),并在提交后显示这些信息(如在“确认订单”页面上),那么可以使用前面的三种测试方法尝试访问显示敏感数据的页面。如果在匿名使用应用程序期间生成的令牌可用于获取用户的敏感信息,那么应用程序就易于遭受会话固定攻击。
(1)如果应用程序完全依靠HTTP cookie传送会话令牌,它很可能容易受到跨站点请求伪造(CSRF)攻击。
(2)分析应用程序的关键功能,确定用于执行敏感操作的特定请求。如果这些请求中的参数完全可由攻击者事先决定(也就是说,其中并不包含任何会话令牌、无法预测的数据或其他机密),那么几乎可以肯定应用程序易于受到攻击。
(3)创建一个HTML页面,它不需要进行任何用户交互,即可提出想要的请求。对于GET请求,可以使用一个<img>标签,并通过src参数设置易受攻击的URL。对于POST请求,可以建立一个表单,其中包含实施攻击所需全部相关参数的隐藏字段,并将其目标设为易受攻击的URL。可以使用JavaScript在页面加载时自动提交该表单。登录应用程序后,使用同一个浏览器加载前面创建的HTML页面。确认应用程序是否执行想要的操作。
(4)如果应用程序为阻止CSRF攻击,在请求中使用其他令牌,则应以与测试会话令牌相同的方式测试这些令牌的可靠性。还应测试应用程序是否易于受到UI伪装攻击,以突破反CSRF防御(请参阅第13章了解相关详情)。
(1)如果应用程序使用HTTP cookie传送会话令牌(或任何其他敏感数据),那么检查相关的Set-Cookie消息头,寻找用于控制cookie范围的所有“域”或“路径”属性。
(2)如果一个应用程序明确放宽它的cookie范围限制,将其设定为一个父域或父目录,那么攻击者可以通过以上父域或父目录中的其他Web应用程序向该应用程序发动攻击。
(3)如果一个应用程序以它自己的域名为它的cookie域范围(或并未指定“域”属性),那么它仍然可能受到在子域上运行的应用程序的威胁。这是设定cookie范围造成的后果,只有不在安全敏感的应用程序的子域上运行其他应用程序,才能避免这种后果。
(4)确定对按路径(如/site/main和/site/demo)隔离的任何依赖情况,跨站点脚本攻击能够破坏这种隔离。
(5)确定所有可能收到应用程序发布的cookie的域名和路径。确定是否可通过这些域名或路径访问其他Web应用程序,以及是否可利用它们获得发布给目标应用程序用户的cookie。
图21-7 测试访问控制
(1)根据应用程序的核心功能,了解访问控制在垂直隔离(拥有不同权限的用户可访问不同类型的功能)与水平隔离(拥有相同权限的用户可访问不同的数据)方面的主要要求,通常,应用程序会使用两种权限隔离,例如,普通用户能够访问自己的数据,而管理员则能够访问每个人的数据。
(2)检查应用程序解析过程得到的结果,确定最可能成为权限提升攻击目标的功能区域与数据资源类型。
(3)为提高测试访问控制漏洞的效率,渗透测试员应该获得大量拥有不同垂直权限与水平权限的账户。如果应用程序允许自我注册,渗透测试员就可以直接获得大量拥有不同水平权限的账户。为获得拥有不同垂直权限的账户,需要得到应用程序所有者的帮助(或利用某个漏洞访问一个高权限账户)。如后文所述,能否获得各种不同的账户将会对能够进行的测试产生直接影响。
(1)如果应用程序实施垂直权限隔离,那么首先使用一个高权限账户确定它能访问的所有功能,然后再使用一个低权限账户尝试访问上述每一项功能。
(a)使用Burp在一个用户的权限下浏览应用程序的所有内容。
(b)复查Burp的站点地图内容,确保已确定要测试的所有功能。然后,注销应用程序并使用另一个用户账户登录;使用上下文菜单选择“比较站点地图”(compare site maps)功能,确定较低权限的用户可以访问哪些高权限请求。请参阅第8章了解这种技巧的更多详情。
(2)如果应用程序实施水平权限隔离,那么使用两个拥有相同权限的不同账户进行同等测试,尝试使用一个账户访问属于另一个账户的数据。通常,这需要替换请求中的一个标识符(如一个文档ID),以指定属于其他用户的资源。
(3)手动检查关键访问控制逻辑。
对于每个用户权限,复查用户可用的资源。尝试通过使用未授权用户的会话令牌,从未授权用户账户重新提交请求来访问这些资源。
(4)进行访问控制测试时,一定要分别测试多阶段功能的每一个步骤,确定每一个阶段是否正确实施了访问控制;或者应用程序是否认为访问后一个阶段的用户一定通过了前面阶段实施的安全检查。例如,如果一个包含表单的管理页面受到恰当保护,检查提交表单的过程中是否同样实施了合理的访问控制。
(1)如果不能优先访问不同权限的账户,或者优先访问几个能够访问不同数据的账户,那么测试不完善的访问控制机制可能相当困难。由于并不知道利用各种缺陷所需的URL名称、标识符和参数,因此许多常见的漏洞将更加难以确定。
(2)在使用低权限账户解析应用程序的过程中,渗透测试员可能已经确定了访问管理接口等特权功能的URL。如果这些功能没有得到充分保护,渗透测试员可能已经了解了这一点。
(3)反编译现有的所有已编译客户端,并提取对服务器端功能的任何引用情况。
(4)大多数受到水平访问控制保护的数据可使用一个标识符(如一个账号或订单号)访问。为了使用一个账户测试访问控制是否有效,需要尝试、猜测或发现与其他用户的数据有关的标识符。如有可能,生成一系列紧密相连的标识符(例如,通过建立几个新订单),尝试确定所有可帮助预测发布给其他用户的标识符的模式。如果无法生成新的标识符,就只能分析已经确定的标识符,并根据这些标识符猜测其他标识符。
(5)如果能够预测出发布给其他用户的标识符,使用第14章描述的技巧实施自动攻击,获取属于其他用户的有用数据。可使用Burp Intruder的Extract Grep功能从应用程序的响应中截获相关信息。
(1)一些应用程序根据请求参数以一种内在不安全的方式实施访问控制。在所有关键请求中寻找edit=false或access=read之类的参数,根据它们的主要作用修改这些参数,尝试破坏应用程序的访问控制逻辑。
(2)一些应用程序根据HTTP Referer消息头做出访问控制决策。例如,一个应用程序可能对/admin.jsp实施严格的访问控制,并接受在Referer中显示它的所有请求。为测试这种行为,尝试执行一些获得授权的特权操作,并提交一个其中缺少Referer消息头或Referer消息头被修改的请求。如果这种改变导致应用程序阻止请求,应用程序很可能以不安全的方式使用Referer消息头。尝试使用一个未通过验证的用户账户执行相同的操作,但提交原始的Referer消息头,看这时是否能够成功执行操作。
(3)如果站点允许HEAD方法,则应测试针对URL的不安全的容器托管访问控制。使用HEAD方法提出请求,确定应用程序是否允许该方法。
许多重要的漏洞由无法预测的用户输入触发,并可能出现在应用程序的任何位置。用一组攻击字符串模糊测试每个请求的每一个参数,是在应用程序中探查这种漏洞的有效方法。
图21-8 测试基于输入的漏洞
(1)检查应用程序解析过程中获得的结果,确定所有提交由服务器端应用程序处理的参数的特殊客户端请求。相关参数分别位于URL查询字符串、请求主体及HTTP cookie中。它们还包括所有给应用程序行为造成影响的用户提交的数据,如Referer或User-Agent消息头。
(2)要对这些参数进行模糊测试,可以使用自己的脚本,或者现成的模糊测试工具。例如,如果使用Burp Intruder,可轮流在工具中加载每一个请求。一个简单的方法是在Burp Proxy中拦截一个请求,然后选择“发送至Intruder”操作;或者在Burp Proxy历史记录中单击一个请求,再选择这个选项。使用这个选项将在Burp Intruder中配置请求的内容、正确的目标主机和端口,然后Burp Intruder自动将所有请求参数的值标记为有效载荷位置,准备进行模糊测试。
(3)使用“有效载荷”选项卡,配置一组适当的攻击有效载荷,在应用程序中探查漏洞。可以手动输入有效载荷,从一个文件中加载它们,或者选择一个预先设定的有效载荷列表。模糊测试应用程序中的第一个请求参数往往需要发布数目庞大的请求,并在结果中查找反常现象。如果设定的攻击字符串过多,这样反而达不到预期的目标,甚至生成无数的输入,以致很难对其进行分析。因此,较为明智的做法是,测试一系列可在特定的专门设计的输入的反常响应中轻易确定的常见漏洞,以及出现在应用程序的所有位置而非某些特殊功能中的漏洞。可以使用以下一组有效载荷测试一些常见的漏洞。
SQL注入
XSS 与消息头注入
OS 命令注入
路径遍历
脚本注入
文件包含
(4)前面所有的有效载荷均以字面量形式显示,?、;、&、+ 空格与=字符因为在HTTP请求中有特殊含义,需要进行URL编码。默认情况下,Burp Intruder会对这些字符进行必要的编码,因此,必须确保该选项没有被禁用。(如果想要在定制后将所有选项恢复到它们的默认值,可从Burp菜单中选择“恢复默认值”选项。)
(5)在Burp Intruder的Grep功能中,配置一组合适的字符串,标记响应中的一些常见的错误消息。例如:
请注意,其中的字符串111111用于测试成功的脚本注入攻击;21.7.1节第3步中的有效载荷要求将这个值写入服务器的响应中。
(6)同时,选择“有效载荷Grep”选项,标记包含有效载荷自身的响应,该响应表示可能存在XSS或消息头注入漏洞。
(7)在通过第一个文件包含有效载荷指定的主机上建立一个Web服务器或netcat监听器,监控服务器由于远程文件包含攻击而发出的连接尝试。
(8)实施并完成攻击后,在结果中查找表示存在漏洞的反常响应。检查HTTP状态码、响应长度、响应时间、其中是否出现配置的表达式以及是否出现有效载荷本身。可以单击结果表的每一个列标题,对列中的值进行分类(按下Shift键的同时单击鼠标可对结果进行反向排序),这样做可迅速确定所有不同于其他结果的反常响应。
(9)参考本章后文对每一类问题的详细描述,对模糊测试结果表明可能存在的每一个潜在的漏洞进行确认,同时考虑如何成功地利用这些漏洞。
(10)一旦配置Burp Intruder对某个请求进行模糊测试后,就可以迅速地对应用程序中的其他请求进行相同的测试。在Burp Proxy中选定目标请求,再选择“发送至Intruder”选项,就可以立即使用现有的测试选项在Intruder中进行测试。这样,就可以同时在单独的窗口中进行大量测试,在测试完成后手动检查测试结果。
(11)如果在解析应用程序的过程中确定了带外输入通道,可通过它们向应用程序提交用户可控制的输入。渗透测试员应当通过提交各种旨在触发常见的Web应用程序漏洞的专门设计的数据,对这些输入通道进行类似的模糊漏洞。根据输入通道的特点,可能需要建立一个定制脚本或其他工具。
(12)除了手动对应用程序请求进行模糊测试外,如果拥有一个自动化Web应用程序漏洞扫描器,还应当运行该扫描器,对目标应用程序进行自动测试,并比较两方面的测试结果。
(1)如果发现21.7.1节第3步中列出的SQL攻击字符串导致任何反常响应,那么应该手动探查,观察应用程序如何处理相关参数,确定其中是否存在SQL注入漏洞。
(2)如果提交上述字符串返回错误消息,分析这些消息的意义。可以根据9.2.13节提供的信息了解错误消息在常用数据库平台中的含义。
(3)如果在请求中提交一个单引号导致错误或出现其他反常行为,可尝试提交两个单引号;如果这种输入使错误或异常行为消失,应用程序可能易于受到SQL注入。
(4)设法使用常用的SQL字符串连接符函数构建一个等同于良性输入的字符串。如果提交这个字符串得到与提交原始的良性输入相同的响应,那么应用程序可能易于受到攻击。例如,如果原始输入为表达式FOO,可以使用下面的输入测试:
同样,应对在HTTP请求中具有特殊意义的字符(如+和空格)进行URL编码。
(5)如果原始输入为数字字符,尝试使用一个其结果等于原始值的数学表达式。例如,如果原始值为2,尝试提交1+1或3-1。如果应用程序做出相同的响应,表示它易于受到攻击;如果数字表达式的值对应用程序的行为造成系统性的影响,那么应用程序就特别容易受到攻击。
(6)如果前面的测试取得成功,可以通过使用针对SQL的数学表达式构造一个特殊的值,进一步确定SQL注入漏洞是否存在。如果可以通过这种方式系统性地控制应用程序的逻辑,那么几乎可以肯定应用程序易于受到SQL注入攻击。例如,下面两个表达式的结果都等于2:
(7)如果使用waitfor命令进行的模糊漏洞测试导致应用程序在进行响应时出现反常的时间延迟,那么所使用的数据库为MS-SQL,且应用程序易于受到SQL注入攻击。手动重复测试,在waitfor参数中指定不同的值,确定响应时间是否随着这个值而发生系统性的变化。请注意,可以在几个SQL查询中插入攻击有效载荷;这时观察到的时间延迟为指定值的固定倍数。
(8)如果应用程序易于受到SQL注入攻击,渗透测试员要考虑可以实施哪些攻击,以及如何利用它们实现自己的目的。请参考第9章了解实施以下攻击的详细步骤。
修改WHERE子句中的条件,改变应用程序的逻辑(例如,注入or 1=1--避开登录)。
使用UNION操作符注入任意一个SELECT查询,将它的结果与应用程序的原始查询的结果组合在一起。
使用针对数据库的SQL语法“指纹标识”数据库类型。
如果使用的数据库为MS-SQL,且应用程序在响应中返回ODBC错误消息,利用这些信息枚举数据库结构,获取任意数据。
如果无法获得一个任意输入的查询的结果,可以使用以下攻击技巧提取数据。
获取数字格式的字符串数据,一次一个字节。
使用带外通道。
如果能够根据任意一个条件引发不同的应用程序响应,可使用Absinthe提取任意数据,一次一比特。
如果能够根据一个任意的条件触发时间延迟,利用它们获取数据,一次一比特。
如果应用程序阻止实施特殊攻击所需的某些字符或表达式,尝试使用第9章描述的各种技巧避开输入过滤。
如有可能,利用漏洞或强大的数据库函数,将攻击范围扩大到数据库与基础服务器中。
(1)单击“有效载荷Grep”列,分类模糊漏洞测试的结果,确定任何与21.7.1节第3步中列出的XSS有效载荷相匹配的字符串。这些是在应用程序响应中按原样返回的XSS测试字符串。
(2)对于上述每一个字符串,检查应用程序的响应,查找用户提交的输入的位置。如果该字符串出现在响应主体中,应测试应用程序中是否存在XSS漏洞。如果它出现在HTTP消息头中,应测试应用程序中是否存在消息头注入漏洞。如果它被用在302响应的Location消息头中,或者用于以某种方式指定重定向,应测试应用程序中是否存在重定向漏洞。请注意,同一个输入可能会被复制到响应中的几个位置,因此应用程序中可能存在几种类型的反射型漏洞。
(1)对于在响应主体中出现的所有请求参数,检查它周围的HTML代码,确定是否可以提交专门设计的输入,从而执行任意JavaScript脚本。例如,通过注入<script>标签,注入一段现有代码,或在一个标签属性中插入精心设计的值,执行任意JavaScript脚本。
(2)将第12章讲述的攻破签名过滤器的各种方法作为参考,了解如何利用专门设计的输入执行任意JavaScript脚本。
(3)尝试向应用程序提交各种可能的输入,监控它的响应,确定应用程序是否对输入进行任何过滤或净化。如果攻击字符串被原样返回,使用浏览器确认成功执行了任意JavaScript脚本(例如,通过生成一个警报对话框)。
(4)如果发现应用程序阻止需要使用的某些字符串或表达式,或者对某些字符进行URL编码,尝试使用第12章描述的各种技巧避开过滤。
(5)如果在一个POST请求中发现了XSS漏洞,仍然可以通过一个包含表单的恶意Web站点,由必要的请求参数和一段脚本自动提交该表单,对这个漏洞加以利用。但是,如果可以通过GET请求利用漏洞,就可以使用大量的攻击传送机制。尝试在GET请求中提交相同的参数,看攻击是否仍然取得成功。可以使用Burp Proxy的“改变请求命令”(Change Request Method)操作转换请求类型。
(1)对于在响应消息头中出现的每一个请求参数,确认应用程序是否接受URL编码的回车(%0d)与换行(%0a)符,以及它们是否按原样在响应中返回。请注意,在服务器的响应中寻找的是换行符本身,而不是它们的URL编码形式。
(2)如果在提交专门设计的输入后,服务器的响应消息头新增了一行,那么应用程序易受HTTP消息头注入攻击。如第13章所述,攻击者可以利用这种漏洞实施各种攻击。
(3)如果服务器的响应中仅返回两个换行符中的一个,根据实际情况,仍可以设计出有效的攻击方法。
(4)如果发现应用程序阻止包含换行符的输入,或者净化出现在响应中的这些字符,尝试使用下面的输入测试过滤的效率:
(1)如果反射型输入用于指定某类重定向的目标,测试是否可以提交专门设计的输入,生成指向一个外部Web站点的任意重定向。如果可以,渗透测试员就可以利用这种行为提高钓鱼攻击的可信度。
(2)如果应用程序以参数值的形式传送绝对URL,那么修改URL中的域名,测试应用程序是否重定向到不同的域。
(3)如果参数中包含一个相对URL,将这个URL修改成指向另一个域的绝对URL,并测试应用程序是否重定向到这个域。
(4)如果应用程序为防止外部重定向,在进行重定向前对参数进行某种形式的确认,通常仍然可以轻易避开这种确认。尝试使用第13章描述的各种攻击测试过滤的效率。
(1)如果应用程序保存用户提交的输入,并随后在屏幕上显示这些输入,那么,在模糊测试整个应用程序后,可能会发现攻击字符串在本身并未包含这些字符串的请求的响应中返回。留意这种情况,确定被保存数据的原始进入点。
(2)有时,只有完成一个多阶段过程,用户提交的数据才被成功保存。如果在应用程序解析过程中确定这种功能,那么手动完成相关过程,并在被保存的数据中查找XSS漏洞。
(3)如果拥有足够的访问权限,应仔细审查可在更高权限的用户会话中显示低权限用户的数据管理功能。管理功能中存在的任何保存型XSS漏洞往往会直接导致权限提升。
(4)测试用户提交的数据被保存且向该用户显示的每一种情况。测试这些情况,从中查找上述XSS和其他响应注入漏洞。
(5)如果发现一个漏洞将一名用户提交的输入显示给其他用户,渗透测试员要确定可用于实现目标的最佳攻击有效载荷,如会话劫持或请求伪造。如果被保存的数据仅向提交该数据的用户显示,那么设法找出办法,链接已经发现的所有漏洞(如不完善的访问控制),从而在其他用户的会话中注入一个攻击。
(6)如果应用程序允许文件上传与下载,应始终探查这种功能是否易于受到保存型XSS攻击。如果应用程序允许HTML. JAR或文本文件,且并不确认或净化它们的内容,那么几乎可以肯定它们易于受到攻击。如果它允许JPEG文件且并不确认其中是否包含有效的图像,那么它可能易于受到针对Internet Explorer 用户的攻击。测试应用程序如何处理它支持的每种文件类型,并弄清浏览器如何处理包含HTML而非正常内容的响应。
(7)在一名用户提交的数据被显示给其他用户的每一个位置,如果应用程序实施的过滤阻止发动保存型XSS攻击,确定应用程序的行为是否使它易于受到本站点请求伪造攻击。
(1)如果在21.7.1节第3步中列出的任何命令注入攻击字符串导致应用程序在做出响应时出现反常的时间延迟,那么应用程序易于受到OS命令注入攻击。手动重复进行测试,在-i或-n参数中指定不同的值,确定响应时间是否随着这个值而发生系统性的变化。
(2)使用所发现的任何一个可成功实施攻击的注入字符串,尝试注入另一个更加有用的命令(如ls或dir),确定是否能够将命令结果返回到浏览器上。
(3)如果不能直接获得命令执行结果,还可以采用其他方法。
可以尝试打开一条通向自己计算机的带外通道。尝试使用TFTP上传工具至服务器,使用telnet或netcat建立一个通向自己计算机的反向shell,并使用mail命令通过SMTP发送命令结果。
可以将命令结果重定向到Web根目录下的一个文件,然后使用自己的浏览器直接获取结果。例如:
(4)一旦找到注入命令的方法并能够获得命令执行结果,就应当确定自己的权限(通过使用whoami或类似命令,或者尝试向一个受保护的目录写入一个无害文件)。然后就可以设法提升自己的权限,进而秘密访问应用程序中的敏感数据,或者通过被攻破的服务器测试其他主机。
(5)如果知道自己的输入被提交给某个OS命令,但提交前面列出的攻击字符串无法成功实施攻击,那么观察是否可以使用<或>字符将一个文件的内容指向命令的输入,或者将命令的输出指向一个文件。可以使用这种方法读取或写入任意文件的内容。如果知道或能够猜测出被执行的命令,尝试注入与该命令有关的命令行参数,以有利的方式修改它的行为(例如,指定Web根目录中的输入文件)。
(6)如果发现应用程序对实施命令注入所需的某些字符进行转义,可尝试在这些字符串中插入转义字符。如果应用程序并不对转义字符本身进行转义,就可以利用这种行为避开应用程序的防御机制。如果发现空白符被阻止或净化,就可以使用$IFS替代在UNIX平台中出现的空格。
(1)对于执行的每次模糊测试,检查在21.7.1节第3步中列出的路径遍历攻击字符串生成的结果。可以在Burp Intruder中单击有效载荷列的顶部,按有效载荷对结果表进行分类,从而将这些字符串生成的结果分组。如果收到一个不常见的错误消息,或者长度不正常的响应,手动检查响应,确定其中是否包含特定文件的内容或其他表示执行了反常文件操作的证据。
(2)在解析应用程序的受攻击面的过程中,应该已经注意到了一些专用的功能,使用它们可根据用户提交的输入读取和写入文件。除了对所有参数进行模糊测试外,还应极其仔细地手动测试这项功能,确定所有路径遍历漏洞。
(3)如果某个参数中包含一个文件名、文件名的一部分或一个目录,修改这个参数的值,并在其中插入任意一个子目录和一个遍历序列。例如,如果应用程序提交参数:
那么可以尝试提交以下值:
如果两种情况下应用程序的行为完全相同,那么它易于受到攻击,渗透测试员应该继续以下步骤。如果在上述两种情况下应用程序的行为有所不同,那么应用程序可能阻止、删除或净化遍历序列,致使文件路径失效。尝试使用第10章描述的编码与其他攻击避开过滤。
(4)如果前面在基础目录中使用遍历序列的测试取得成功,尝试使用其他序列上溯到基础目录,并访问服务器操作系统中的已知文件。如果这些尝试失败,应用程序可能在许可文件访问前实施了各种过滤或检查,应当进行深入分析,了解应用程序实施的控制以及是否可以避开这些控制。
(5)应用程序可能会检查被请求的文件扩展名,只允许用户访问特殊类型的文件。尝试使用空字节或换行符攻击,并在后面连接已知的、应用程序接受的文件扩展名,设法避开过滤。例如:
(6)应用程序可能会检查用户提交的文件路径是否以一个特定的文件名或词根开头。尝试将遍历序列附加在一个已知应用程序接受的词根后面,避开过滤。例如:
(7)如果这些攻击无法取得成功,尝试组合使用几种测试技巧,首先对基础目录进行全面的测试,了解应用程序实施的过滤以及它如何处理无法预料的输入。
(8)如果能够读取服务器上的任意文件,尝试获取以下任何一个文件,进而扩大攻击范围。
操作系统与应用程序的密码文件。
服务器与应用程序配置文件,发现其他漏洞或优化另一次攻击。
可能含有数据库证书的包含文件。
应用程序使用的数据源,如MySQL数据库文件或XML文件。
服务器可执行页面的源代码,以执行搜索漏洞的代码审查。
可能包含用户名和会话令牌的应用程序日志文件等。
(9)如果能够写入服务器上的任意文件,分析是否可以实施以下攻击,进而扩大攻击范围。
在用户的启动文件夹中创建脚本。
当用户下一次连接时,修改in.ftpd等文件执行任意命令。
在一个拥有执行许可的Web目录中写入脚本,从浏览器调用它们。
(1)对于执行的每一次模糊测试,在测试结果中搜索字符串111111本身(即它前面没有其他测试字符串)。在Burp Intruder中,按住Shift键的同时单击111111 Grep字符串标题,对所有包含这个字符串的结果进行分类,即可迅速确定这些字符串。确定的任何结果都可能易于受到脚本命令注入攻击。
(2)检查使用脚本注入字符串的所有测试,确定所有包含脚本错误消息的测试;这些错误消息表示输入被执行,但造成一个错误,因而可能需要对测试进行优化,以成功实施脚本注入。
(3)如果应用程序似乎易于受到攻击,通过注入其他专门针对应用程序所使用的脚本平台的命令,确认漏洞是否存在。例如,可以使用类似于模糊测试OS命令注入时使用的攻击有效载荷:
(1)如果在模糊测试时收到任何由目标应用程序的基础架构提出的HTTP连接,那么几乎可以肯定应用程序易于受到远程文件包含攻击。以单线程的方式在有限的时间内重复相关测试,确定到底是哪些参数致使应用程序提出HTTP请求。
(2)检查文件包含测试结果,确定在应用程序的响应中造成反常延迟的所有测试。在这些情况下,可能应用程序本身易于受到攻击,但HTTP请求可能因为网络级过滤而超时。
(3)如果发现一个远程文件包含漏洞,部署一台包含恶意脚本(专门针对所攻击的语言而编写)的Web服务器,使用和测试脚本注入类似的命令确定脚本是否被执行。
除了前面介绍的基于输入的漏洞外,还有一系列漏洞只有在特殊功能中才会表现出来。在实践下面的测试步骤之前,渗透测试员首先应当对应用程序的受攻击面的评估结果进行分析,确定可能出现这些漏洞的应用程序功能,并集中精力测试这些功能。
图21-9 测试功能方面的输入漏洞
(1)对于与电子邮件有关的功能使用的每一个请求,轮流提交以下每个测试字符串作为每一个参数,并在相关位置插入电子邮件地址。如步骤21.7.1所述,可以使用Burp Intruder自动完成这项任务。这些测试字符串已经将特殊的字符进行了URL编码,因此不需要再对它们进行编码。
(2)检查测试结果,确定应用程序返回的所有错误消息。如果这些错误与电子邮件功能中的问题有关,确定是否有必要调整输入,以利用漏洞。
(3)应该监控指定的电子邮件地址,看是否收到任何电子邮件。
(4)仔细检查生成相关请求的HTML表单。它们可能提供与服务器端软件有关的线索。其中可能包含一个用于指定电子邮件收件人(To)地址的隐藏或禁用字段,可以直接对其进行修改。
(1)向每一个目标数据提交一系列稍大于常用缓冲区大小的长字符串。一次针对一个数据实施攻击,最大程度地覆盖应用程序中的所有代码路径。可以使用Burp Intruder中的字符块有效载荷来源自动生成各种大小的有效载荷。可以对下面的缓冲区大小进行测试:
(2)监控应用程序的响应,确定所有反常现象。任何无法控制的溢出几乎可以肯定会在应用程序中造成异常,虽然远程诊断问题的本质可能非常困难。寻找以下反常现象。
HTTP 500状态码或错误消息,这时其他畸形(而非超长)输入不会产生相同的结果。
内容详细的消息,表示某个外部本地代码组件发生故障。
服务器收到一个局部或畸形响应。
服务器的TCP连接未返回响应,突然关闭。
整个Web应用程序停止响应。
应用程序返回出人意料的数据,表示内存中的一个字符串可能“丢失”了它的空终止符。
(1)当测试本地代码组件时,确定所有基于整数的数据,特别是长度指示符,可以利用它触发整数漏洞。
(2)向每一个目标数据提交旨在触发漏洞的适当有效载荷。轮流向每一个目标数据发送一系列不同的值,分别表示不同大小的有符号与无符号整数值的边界情况,如下所示。
0x7f与0x80(127与128)
0xff与0x100(255与256)
0x7ffff与0x8000(32 767与32 768)
0xffff与0x10000(65 535与65 536)
0x7fffffff与0x80000000(2 147 483 647与2 147 483 648)
0xffffffff与0x0(4 294 967 295与0)
(3)当被修改的数据以十六进制表示时,应该发送每个测试字符串的little-endian 与big-endian版本,例如,ff7f以及7fff。如果十六进制数字以ASCII形式提交,应该使用应用程序自身使用的字母字符,确保这些字符被正确编码。
(4)如21.8.2节第1步的(2)所述,监控应用程序的响应,查找所有反常事件。
(1)轮流向每一个参数提交包含一长串不同格式说明符的字符串。例如:
记得将%字符URL编码成%25。
(2)如21.8.2节第1步的(2)所述,监控应用程序的响应,查找所有反常事件。
(1)轮流测试怀疑通过SOAP消息处理的参数。提交一个恶意XML结束标签,如</foo>。没有发生错误就表示该输入可能没有插入SOAP消息中,或者以某种方式被净化。
(2)出现错误就提交一对有效的起始与结束标签,如<foo></foo>。如果这对标签使错误消失,应用程序很可能易于受到攻击。
(3)如果提交的攻击字符串在应用程序的响应中原样返回,轮流提交下面两个值。如果发现其中一个值的返回结果为另一个值,或者只是返回test,那么可以确信该输入被插入到了XML消息中。
(4)如果HTTP请求中包含几个可放入SOAP消息中的参数,尝试在一个参数中插入起始注释字符<!--,在另一个参数中插入结束注释字符!-->。然后,轮换在参数中插入这两个字符(因为无法知道参数出现的顺序)。这样做可能会把服务器SOAP消息的某个部分作为注释处理,从而改变应用程序的逻辑,或者形成一个可能造成信息泄露的错误条件。
(1)在任何使用用户提交的数据从一个目录服务中获取信息的功能中,针对每一个参数,轮流测试是否可以注入LDAP查询。
(2)提交*字符。返回大量结果就明确表示针对的是LDAP查询。
(3)尝试输入大量闭括号:
这个输入会使查询语法失效,因此,如果它导致错误或其他反常行为,那么应用程序易于受到攻击(许多其他应用程序功能和注入情况也会造成相同的结果)。
(4)尝试输入干扰不同查询的各种表达式,看是否影响返回的结果。在查询目录未知的情况下cn非常有用,因为所有的LDAP实现都支持这个特性。
(5)尝试在输入结尾增加其他属性,并用逗号分隔这些属性。轮流测试每一个属性,返回错误消息就表示该属性当前无效。以下属性常用在由LDAP查询的目录中:
(1)尝试提交下面的值,并确定它们是否会使应用程序的行为发生改变,但不会造成错误:
(2)如果参数为数字,尝试提交下面的测试字符串:
(3)如果上面的任何字符串导致应用程序的行为发生改变,但不会造成错误,很可能可以通过设计测试条件,一次提取一字节的信息,从而获取任意数据。使用一系列以下格式的条件确定当前节点的父节点的名称:
(4)提取出父节点的名称后,使用一系列下列格式的条件提取XML树中的所有数据。
(1)确定在参数中指定内部服务器名称或IP地址的任何情况。提交任意服务器和端口,监视应用程序是否出现超时。还可以提交localhost,然后提交自己的IP地址,之后在指定端口上监视传入连接。
(2)针对根据特定值返回特定页面的请求参数,尝试使用以下各种语法附加新的注入参数:
如果应用程序的行为与未修改原始参数时相同,说明其中可能存在HTTP参数注入漏洞。这时,可通过注入可能更改后端逻辑的已知参数的名/值对来攻击后端请求(如第10章所述)。
如果用户正向服务器提交XML,则可以实施外部实体注入攻击。如果已知会向用户返回某个字段,可以尝试指定一个外部实体,如下所示:
如果找不到已知字段,可以将“http://192.168.1.1:25”指定为外部实体,并监视页面响应时间。如果页面响应的时间明显增长或页面超时,则说明应用程序易于受到攻击。
图21-10 测试逻辑缺陷
(1)逻辑缺陷的形式多种多样,并且可能存在于应用程序功能的每一方面。为确保探查逻辑缺陷的效率,首先应该将受攻击面缩小到一个适当的范围,以方便手动测试。
(2)检查应用程序解析过程中获得的结果,确定以下情况。
多阶段过程。
重要的安全功能,如登录。
信任边界的转换(例如,登录时由匿名用户转变为自我注册用户)。
检查和调整交易价格或数量。
(1)如果一个多阶段过程需要按预定的顺序提交一系列请求,尝试按其他顺序提交这些请求。尝试完全省略某些阶段,几次访问同一个阶段,或者推后访问前一个阶段。
(2)这些阶段可能通过一系列指向特殊URL的GET或POST请求进行访问,或者需要向同一个URL提交不同的参数。被访问的阶段可通过在被请求的参数中提交功能名称或索引来指定。确保完全了解应用程序访问不同阶段所使用的机制。
(3)除了打乱操作步骤的顺序外,尝试提取在一个过程阶段提交的参数,并在另一个阶段提交这些参数。如果相关数据被应用程序更新,应当确定是否可以利用这种行为破坏应用程序的逻辑。
(4)如果在一个多阶段过程中,不同的用户对同一组数据进行操作,提取某一名用户提交的每一个参数,再由另一名用户提交这些参数。如果应用程序接受并处理这些参数,如前面所述,探索这种行为的衍生效果。
(5)根据执行功能的情形,了解开发者做出的假设以及主要受攻击面位于何处。设法找到违反这些假设以在应用程序中造成反常行为的方法。
(6)如果不按顺序访问多阶段功能,应用程序常常表现出一系列异常现象,如变量值为空字符或未被初始化,状态仅部分定义或相互矛盾,以及其他无法预料的行为。寻找有用的错误消息和调试结果,可以通过它们进一步了解该功能的内部机制,从而调整当前攻击,或者发动另一次攻击。
(1)应用程序的重要安全功能需要处理大量用户提交的输入,并根据这些输入做出决策。因此,应测试这些功能对不完整输入的适应性。
(2)轮流测试每一个参数,从请求中删除参数的名称与值。监控应用程序的响应,查找所有行为异常或错误消息,它们可能提供与应用程序逻辑有关的信息。
(3)如果所操纵的请求属于一个多阶段过程,应测试整个过程,因为应用程序可能将前一个阶段的数据保存在会话中,然后在后一个阶段处理。
(1)了解应用程序如何处理不同用户信任状态之间的转换。寻找功能,帮助一名拥有特定信任地位的用户累积一定量与其身份有关的状态,例如,匿名用户在自我注册过程中提供个人信息,或者完成旨在确认其身份的账户恢复过程。
(2)寻找办法,通过在一个区域积累相关状态,在信任边界之间进行不恰当的转换,然后以正常不被允许的方式切换到另一个区域。例如,完成部分账户恢复过程后,尝试切换到与某一名用户有关的通过验证的页面。当进行这种转换时,测试应用程序是否分配了一个不相称的信任级别。
(3)确定是否可利用更高权限的功能直接或间接访问或者猜测某些信息。
(1)如果应用程序设置交易限额,测试提交负值会造成什么影响。如果应用程序接受负值,就可以通过从反方向进行大额交易来规避这种限额。
(2)分析是否可以使用一连串的交易达成一种状态,然后利用它达到目的。例如,测试是否可以在账户之间进行几次低额转账,就可以产生一种应用程序的逻辑将会阻止的较大余额。
(3)如果应用程序根据用户控制的数据或操作确定的标准调整价格或其他敏感价值,首先应了解应用程序使用的算法以及需要调整的逻辑。确定这些调整是一次性行为,还是需要根据用户执行的其他操作进行修改。
(4)努力想办法操纵应用程序的行为,使应用程序进行的调整与开发者最初设定的标准相互矛盾。
图21-11 测试共享主机漏洞
(1)如果应用程序在一个共享基础架构中运行,分析它为共享环境中的客户端提供的用于更新和管理其内容与功能的访问机制。考虑以下问题。
远程访问机制是否使用一个安全的协议与经过适当强化的基础架构?
客户端是否能够访问他们正常情况下不能访问的文件、数据及其他资源?
客户端是否能够在主机环境中获得一个交互式的shell,并执行任意命令?
(2)如果使用一个所有权应用程序,以方便客户端配置和定制共享环境,考虑是否能够以这个应用程序为攻击目标,攻破该环境本身以及其中运行的所有应用程序。
(3)如果能够在某个应用程序中执行命令、注入SQL脚本或访问任意文件,仔细研究,看是否能够以此扩大攻击范围,攻破其他应用程序。
(1)如果使用ASP主机的应用程序由许多共享与定制组件构成,确定其中的任意共享组件,如日志机制、管理功能以及数据库代码组件,尝试利用这些组件攻破应用程序的共享部分,进而攻破其他应用程序。
(2)如果共享环境使用一个常用的数据库,使用NGSSquirrel之类的数据库扫描工具,全面审查数据库配置、补丁版本、表结构以及许可。数据库安全模型中存在的任何缺陷都可加以利用,将攻击范围由一个应用程序扩大到另一个应用程序。
图21-12 测试Web服务器漏洞
(1)检查应用程序解析过程中获得的结果,确定应用程序使用的、可能包含可访问的管理接口的Web服务器与其他技术。
(2)对Web服务器进行端口扫描,确定在指向主目标应用程序的不同端口上运行的所有管理接口。
(3)对于确定的接口,查阅制造商文档资料与常用默认密码表,获得默认证书。
(4)如果默认证书无效,使用21.4节描述的技巧尝试猜测有效的证书。
(5)如果能够访问管理接口,审查可用的功能,确定是否可以利用这项功能进一步攻破主机与主应用程序。
(1)分析Nikto扫描结果(21.1.4节中的第1步),确定服务器上存在的、但并不属于应用程序的默认内容。
(2)使用搜索引擎与其他资源(如www.exploit-db.com)确定已知应用程序所使用的技术的默认内容与功能。如有可能,在本地安装这些技术,并在其中查找可在渗透测试中利用的所有默认功能。
(3)检查默认内容,从中查找任何可用于攻击服务器或应用程序的功能或漏洞。
(1)使用OPTIONS方法列出服务器使用的HTTP方法。请注意,不同目录中激活的方法可能各不相同。可以使用Paros进行漏洞扫描,帮助完成这个检查。
(2)手动测试每一种方法,确认其是否可用。
(3)如果发现一些WebDAV方法被激活,使用一个激活WebDAV的客户端进行深入调查,如Microsoft FrontPage或Internet Explorer中的 Open as Web Folder(以Web文件夹打开)选项。
(1)使用GET与CONNECT请求,尝试使用Web服务器作为代理服务器,连接因特网上的其他服务器,并获取其中的内容。
(2)尝试使用前面描述的两种技巧连接主机基础架构中的不同IP地址与端口。
(3)尝试使用前面描述的两种技巧,在请求中指定127.0.0.1为目标主机,连接Web服务器上的常用端口号。
(1)使用以下方式向根目录提交GET请求:
正确的Host消息头;
恶意Host消息头;
Host消息头中的服务器IP地址;
无Host消息头(仅使用HTTP/1.0)。
(2)比较对这些请求的响应。常见的结果是,在Host消息头中使用服务器的IP地址获得目录列表。还可以获得各种默认内容。
(3)如果观测到应用程序表现出不同的行为,使用生成不同结果的主机名称重复21.1节描述的应用程序解析过程。一定要使用-vhost选项进行一次Nikto扫描,确定在最初的应用程序解析过程中忽略的默认内容。
(1)使用Nessus与所拥有的所有其他类似的扫描器,确定所测试的Web服务器软件中存在的所有已知漏洞。
(2)同时,浏览Security Focus、Bugtraq和Full Disclosure等资源,在攻击目标中查找最近发现的、尚未修复的漏洞信息。
(3)如果应用程序由第三方开发,确定它是否自带Web服务器(通常为一个开源服务器);如果是,在这个服务器中查找所有漏洞。请注意,在这种情况下,服务器的标准版本信息可能已被修改。
(4)如有可能,应该考虑在本地安装所测试的软件,并自己进行测试,查找尚未发现或广泛流传的新漏洞。
(1)在参数值中使用明确的攻击有效载荷向应用程序(最好是响应中包含名称和/或值的某个应用程序位置)提交任意参数名称。如果应用程序阻止该攻击,这可能是由于外部防御机制所致。
(2)如果可以提交在服务器响应中返回的变量,则提供一系列模糊测试字符串及这些字符串的编码形式可以确定应用程序的用户输入防御行为。
(3)对应用程序中的变量实施相同的攻击来确认这一行为。
(4)对于所有模糊测试字符串和请求,使用标准签名数据库中不可能存在的有效载荷字符串。根据定义,我们不可能提供这些字符串的示例。但是,在进行文件检索时,应避免将/etc/passwd或/windows/system32/config/sam作为有效载荷。此外,应在XSS攻击中避免使用<script>,并避免将alert()或xss用作XSS有效载荷。
(5)如果特定请求被阻止,可以尝试在其他位置或上下文中提交相同的参数。例如,在GET请求的URL中、在POST请求主体中,以及在POST请求的URL中提交相同的参数。
(6)此外,应尝试在ASP.NET上将参数作为cookie提交。如果在查询字符串或消息主体中找不到参数foo,API Request.Params[“foo”]会检索名为foo的cookie的值。
(7)回顾第4章中介绍的引入用户输入的所有其他方法,选择其中任何不受保护的方法。
(8)确定以非标准格式(如序列化或编码)或可能以此类格式提交用户输入的位置。如果找不到此类位置,可以通过串联字符串和/或将字符串分布到多个参数中来构建攻击字符串。(注意,如果目标是ASP.NET,可以使用HPP通过同一变量的各种变体来串联攻击字符串。)
图21-13 其他检查
(1)对应用程序中包含的每一段JavaScript脚本进行简单的代码审查,确定可通过任何一个专门设计的URL、在相关页面的DOM中引入恶意数据而触发的XSS或重定向漏洞。审查内容包括HTML页面(无论静态或动态生成的页面)中的所有单独的JavaScript文件和脚本。
(2)确定使用以下API的所有情况,使用这些API可访问通过一个专门设计的URL控制的DOM数据:
(3)在代码中追踪相关数据,确定应用程序对它执行何种操作。如果数据(或它的一个被操纵的表单)被提交给下列API中的一个,那么应用程序可能易于受到XSS攻击:
(4)如果数据被提交给下列API中的一个,那么应用程序可能易于受到重定向攻击:
(1)检查拦截代理服务器生成的日志,确定测试过程中应用程序送出的所有Set-Cookie指令。如果发现有任何Set-Cookie指令包含一个将来日期的expires属性,用户的浏览器会将该cookie保持到这个日期。检查传送敏感数据的持久性cookie的所有内容。
(2)如果一个持久性cookie中包含敏感数据,那么本地攻击者就能够截获这些数据。即使这些数据被加密,截获它们的攻击者仍然可以将这个cookie重新提交给应用程序,访问该cookie访问的任何数据或功能。
(3)如果包含敏感数据的页面通过HTTP访问,在服务器响应中寻找缓存指令。如果其中没有下列指令(在HTTP消息头或HTML元标签中),那么相关页面可能被一个或几个浏览器存入缓存:
(4)确定应用程序中通过URL参数传送敏感数据的所有情况。如果存在这样的情况,检查浏览器的历史记录,证实这些数据已经保存在那里。
(5)对于用户提交敏感数据(如信用卡信息)的所有表单,审查其中的HTML源代码。如果没有在表单标签或输入字段的标签中设置autocomplete=off属性,输入的数据将保存在激活自动完成的浏览器中。
(1)如果应用程序使用SSL进行通信,使用THCSSLCheck工具列出它支持的加密算法和协议。
(2)如果SSL支持脆弱或过时的加密算法和协议,处在适当位置的攻击者就可以实施攻击,降级或破译应用程序用户的SSL通信,访问他们的敏感数据。
(3)一些Web服务器声称它支持某些脆弱加密算法和协议,但如果客户提出请求,它实际上拒绝使用这些算法和协议完成握手。在使用THCSSLCheck工具时,这种情况可能会造成错误警报。可以使用Opera浏览器,尝试通过指定的脆弱协议完成一次握手,确定是否可使用这些协议访问应用程序。
(1)检查/crossdomain.xml文件。如果应用程序允许无限制访问(通过指定<allow-access-from domain=“*” />),来自其他站点的Flash对象可以“叠置”应用程序用户的会话,以进行双向交互。这导致任何其他域可以检索所有数据,并执行任何用户操作。
(2)检查/clientaccesspolicy.xml文件。与Flash类似,如果<cross-domain-access>配置过于宽泛,其他站点将可以与接受测试的站点进行双向交互。
(3)通过添加指定其他域的Origin消息头并检查返回的任何Access-Control消息头,使用XMLHttpRequest测试应用程序如何处理跨域请求。允许任何域、或指定的其他域进行双向交互的安全隐患与Flash跨域策略造成的安全隐患相同。
(1)在探查目标应用程序的整个过程中,监控它的响应,查找可能包含与错误原因、所使用技术以及应用程序的内部结构与功能有关的错误消息。
(2)如果收到不常见的错误消息,使用标准的搜索引擎检查这些消息。可以使用各种高级搜索特性缩小搜索范围。例如:
(3)检查搜索结果,寻找关于错误消息的所有讨论以及其他出现相同消息的所有站点。其他应用程序生成的同一条错误消息可能更详细,有助于渗透测试员更好地了解错误条件。使用搜索引擎缓存获取不再出现在当前应用程序中的错误消息。
(4)使用Google代码搜索查找生成特定错误消息的、公开发布的所有代码。搜索可能被硬编码到应用程序源代码中的错误消息代码段。还可以使用各种高级搜索特性指定代码语言及其他已知的细节。例如:
(5)如果获得包含库与第三方代码组件名称的栈追踪错误消息,在上述两种搜索引擎中搜索这些名称。
Copyright ©2010-2022 比特日记 All Rights Reserved.