利用信息泄露

第4章介绍了可用于解析目标应用程序并初步了解其运行机制的各种技巧,包括以大体上不会对应用程序造成危害的方法与其交互,将应用程序的内容与功能进行分类,判定它使用的技术并确定主要的攻击面。

本章介绍如何在实际攻击的应用程序中提取出更多信息,主要包括以出人意料和恶意的方式与应用程序进行交互,利用应用程序的反常行为提取出有价值的信息。如果取得成功,攻击者就可以通过这种攻击获取用户证书之类的敏感数据,深入了解某种错误条件并据此调整攻击方向,或者发现应用程序所使用技术的更多细节,同时解析应用程序的内部结构与功能。

利用错误消息

发生意外事件时,许多Web应用程序返回详尽的错误消息。从仅仅披露错误类型的简单内置消息到泄露许多应用程序状态细节的详细调试信息都涵盖在错误消息中。

在部署之前,大多数应用程序都接受了各种可用性测试。通常,这种测试能够发现在正常使用应用程序过程中出现的大部分错误条件。因此,一般情况下,应用程序会对这些条件进行合理地处理,而不会向用户返回任何技术消息。但是,如果应用程序正在遭受攻击,很可能就会出现各种各样的错误条件,导致应用程序向用户返回更加详细的信息。如果出现极不平常的错误条件,即使是最注重安全的应用程序(如电子银行使用的应用程序),也会向用户返回非常详细的调试消息。

错误消息脚本

如果在解释型Web脚本语言(如VBScript)中出现错误,应用程序通常会返回一条简单的错误消息,以揭示错误的本质,并且还可能会有发生错误的文件的行号。例如:

这种消息中并不包含任何与应用程序状态或被处理的数据有关的敏感信息。但是,渗透测试员可以利用它从各方面缩小攻击范围。例如,当为探查常见的漏洞在一个特殊的参数中插入各种攻击字符串时,可能会遇到以下消息:

这条消息指出,修改的值被赋给了一个数字式参数,但是,由于提交的输入中包含非数字字符,因而不能赋给上述参数。在这种情况下,向这个参数提供非数字攻击字符串可能达不到任何目的,也不会发现各种类型的漏洞,因此,最好选择其他的参数。

此外,这种类型的错误消息还有助于更好地理解服务器端应用程序的逻辑。因为消息披露了发生错误的行号,所以能够确定两个不同的畸形请求是触发同一个错误,还是不同的错误。通过在几个参数中提交不良的输入并确认错误发生的位置,还可以确定应用程序处理不同参数的顺序。系统性地修改不同的参数,渗透测试员就可以解析出服务器执行的各种代码路径。

栈追踪

大多数Web应用程序用比简单脚本更复杂、但仍然在一种托管执行环境(managed execution environment)下运行的语言编写,例如,Java、C#和Visual Basic. NET。如果这些语言中出现无法处理的错误,浏览器往往会显示完整的栈追踪。

栈追踪是一种结构化的错误消息。它首先说明具体的错误,接着在后面的许多行中描述错误发生时调用栈的执行状态。调用栈的首行显示生成错误的函数,第二行显示调用前一个函数的函数,以此类推,直到显示所有被调用的函数。

下面是一个由ASP.NET应用程序生成的栈追踪:

这种错误消息提供大量有用的信息,可帮助攻击者优化针对应用程序的攻击。

通常,它会说明错误发生的准确原因。攻击者可以根据这些信息调整输入内容,避开错误条件,从而继续实施攻击。

调用栈经常会引用应用程序使用的大量库和第三方代码组件。可以查阅这些组件的文档资料,了解它们的预期行为与假设。还可以创建这些组件的本地应用,并对它进行测试,了解应用程序如何处理出人意料的输入,并确定潜在的漏洞。

调用栈中包含用于处理请求的所有权代码组件的名称。了解这些组件的命名方案及其相互关系有助于推断应用程序的内部结构与功能。

栈追踪中通常包含行号。和前面描述的简单错误消息脚本一样,可以利用这些行号探查并理解每个应用程序组件的内部逻辑。

错误消息中常常包含与应用程序及其运行环境有关的其他信息。在前面的示例中,可以确定应用程序所使用的 ASP.NET 平台的版本,因此就可以研究这个平台,查找任何已知或新出现的漏洞、反常行为、常见的配置错误等。

详尽的调试消息

一些应用程序生成自定义的错误消息,其中包含大量的调试信息。在开发与测试阶段,这些消息有助于开发者对应用程序进行调试,其中常常包含大量与应用程序运行状态有关的信息。例如:

详尽的调试消息中通常包含以下信息。

可通过用户输入操纵的关键会话变量值。

数据库等后端组件的主机名称与证书。

服务器中的文件与目录名称。

嵌入在有意义的会话令牌中的信息(请参阅第7章了解相关内容)。

用于保护通过客户端传送的数据的加密密钥(请参阅第5章了解相关内容)。

在本地代码组件中出现的异常调试信息,包括CPU寄存器的值、栈的内容、加载的DLL列表及其基本地址(请参阅第16章了解相关内容)。

如果在实际的生产代码中出现这种泄露功能的错误,那么应用程序就存在严重的安全缺陷。渗透测试员应该对它进行仔细检查,确定任何可用于扩大攻击范围的数据,并且可以通过提交专门设计的输入操纵应用程序的状态,控制其获取信息的情况。

服务器与数据库消息

不仅应用程序自身,数据库、邮件服务器或SOAP服务器等后端组件也会返回详尽的错误消息。如果发生完全无法处理的错误,应用程序通常会返回一个HTTP 500状态码,而且响应主体中也包括其他与错误有关的信息。其他情况下,应用程序会对错误进行适当处理,并向用户返回一条定制消息,其中有时还包括后端组件生成的错误信息。在某些情况下,信息披露本身可能被攻击者当做攻击手段。应用程序通常会在调试消息或异常错误中无意披露信息,因此组织的安全规程可能会完全忽略这种信息披露。

我们将在以下几节中讲到,利用应用程序返回的消息,攻击者可以实施一系列其他攻击。

利用信息披露扩大攻击范围

在针对服务器后端组件实施特定攻击时,这些组件在遇到错误时常常会提供直接反馈。渗透测试员可以利用这些反馈对攻击进行调整。数据库错误消息中通常包含有用的信息。例如,它们通常会披露造成错误的查询,渗透测试员可以将其用于优化SQL注入攻击。

请参阅第9章了解如何实施数据库攻击,并根据错误消息提取信息的详细方法。

错误消息中的跨站点脚本攻击

如第12章所述,针对跨站点脚本的安全防御是一个艰巨的任务,需要确定用户提交的数据的每一个输出位置。虽然大多数框架在报告错误时都会对数据进行HTML编码,但并不是所有框架都这样做。错误消息常常在HTTP响应中的非常规位置多次出现。在Tomcat使用的HttpServlet-Response.sendError()调用中,错误数据还是响应消息头的一部分:

如果拥有对输入字符串Doc10083011的控制权,攻击者就可以提交换行字符并实施HTTP消息头注入攻击,或在HTTP响应中实施跨站点脚本攻击。有关详细信息,请访问以下链接:

http://www.securityfocus.com/archive/1/495021/100/0/threaded

通常,定制错误消息主要发送到控制台等非HTML目标,但有时用户可以在HTTP响应中发现这类错误显示的消息。在这些情况下,攻击者就可以轻松实施跨站点脚本攻击。

信息披露中的解密提示

我们在第11章中的示例讲到,利用应用程序意外显示的“加密提示”,可以解密以加密格式向用户显示的字符串。信息披露也会导致同样的问题。在第7章的示例中,某应用程序提供一个用于文件访问的加密下载链接。如果某个文件已被移走或删除,应用程序会报告无法下载该文件。当然,错误消息中包含了该文件的解密值,因此,可以向该下载链接提供任何加密的“文件名”,从而导致错误。

在这种情况下,信息披露是由刻意滥用反馈造成的。如果对参数进行解密,然后将其用在各种函数中,只要其中的任何函数会记录数据或生成错误消息,则这时导致的信息披露往往更具偶发性。例如,笔者曾遇到一个复杂的工作流程应用程序,该应用程序使用通过客户端传送的加密参数。如果将dbid和grouphome的默认值互换,应用程序将返回以下错误:

这段消息提供了相当重要的信息。具体来说,dbid实际上是Oracle数据库的连接的加密SID(连接描述符采用“服务器:端口:SID”的形式),grouphome则为加密的文件路径。

在以下与许多其他信息披露攻击类似的攻击中,了解文件路径为攻击者提供了实施文件路径操纵攻击所需的信息。在文件名中提供3个路径遍历字符,并向上导航类似的目录结构,就可以直接向其他组的工作空间上传包含恶意代码的文件:

渗透测试步骤

(1)当通过在不同的参数中提交专门设计的攻击字符串,探查应用程序中是否存在常见的漏洞时,应始终监控应用程序的响应,以确定任何可能包含有用信息的错误消息。

尝试通过在错误的情况下提交加密数据字符串,或通过对未处于处理操作的正确状态的资源执行操作,强制应用程序返回错误响应。

(2)注意,在服务器响应中返回的错误消息可能不会在浏览器中显示。因此,确定错误条件的有效方法,是在每一个原始响应中查找经常出现在错误消息中的关键字。例如:

error

exception

illegal

invalid

fail

stack

access

directory

file

not found

varchar

ODBC

SQL

SELECT

(3)在基本请求中发送一系列修改参数的请求时,为避免错误警报,应检查最初的请求是否已经包含任何正在寻找的关键字。

(4)可以使用Burp Intruder中的Grep函数迅速确定在由某个攻击生成的任何响应中出现的有用的关键字(请参阅第14章了解相关内容)。如果发现匹配的关键字,应手动检查相关响应,确定应用程序是否返回任何有用的错误信息。

 提示 查看浏览器中的服务器的响应时要注意,默认情况下,Internet Explorer会隐藏许多错误消息,并用一个常规页面代替它们。可以选择“工具”→“Internet选项”(Tools→Internet Options),然后在“高级”(Advanced)选项卡中禁用这种行为。

使用公共信息

由于Web应用程序通常会采用大量各不相同的技术与组件,因此渗透测试员经常会遇到一些以前从未见过的错误消息,它们可能不会立即揭示应用程序中出现的错误的本质。在这种情况下,可以从各种公共资源获得更多与错误消息有关的信息。

通常,不常见的错误消息往往是由某个特定的API故障造成的。对消息文本进行搜索就可以找到这个API的文档资料或开发者论坛,以及讨论这个问题的其他位置。

许多应用程序采用第三方组件执行一些常见的任务,如搜索、购物篮和站点反馈功能。这些组件生成的任何错误消息可能已经出现在其他应用程序中,并被人们在其他地方讨论。

一些应用程序中合并了公开发布的源代码。通过搜索出现在不常见错误消息中的一些特殊的表达式,就可以找到实际执行相关功能的源代码。然后检查这些代码,了解它们对输入执行了何种处理以及如何操纵应用程序,从而对某个漏洞加以利用。

渗透测试步骤

(1)使用标准搜索引擎搜索任何不常见的错误消息的文本。可以使用各种高级搜索特性缩小搜索范围,例如:

(2)检查搜索结果,寻找所有关于错误消息的讨论以及其他出现相同消息的站点。其他应用程序生成的同一条错误消息可能更详细,有助于更好地了解错误条件。使用搜索引擎缓存获取不再出现在当前应用程序中的错误消息。

(3)使用Google代码搜索查找任何生成特定错误消息的、公开发布的代码。搜索可能被硬编码到应用程序源代码中的错误消息代码段。还可以使用各种高级搜索特性指定代码语言及其他已知的细节,例如:

(4)如果获得了包含库与第三方代码组件名称的栈追踪,在上述两种搜索引擎中搜索这些名称。

制造详尽的错误消息

有些情况下渗透测试员可以系统性地制造错误条件,以获取错误消息中的敏感信息。

假如能让应用程序对一个特殊的数据执行某种无效的操作,就可能出现上述情况。如果生成的错误消息揭示该数据的值,就可以让应用程序以这种方式处理有用的信息,然后利用这种行为从应用程序中提取任意数据。

可以在SQL注入攻击中利用详尽的开放式数据库连接(ODBC)错误消息检索任意数据库查询的结果。例如,如果将以下SQL注入WHERE子句中,将导致数据库将用户表中第一个用户的密码转换为整数,以执行求值操作:

这会导致以下详细的错误消息:

尝试访问:

http://mdsec.net/addressbook/32

此外,如果某个应用程序错误生成一个包含错误描述的栈追踪,就可以利用这种技巧制造一种情形,让应用程序将有用的信息合并到错误描述中。

一些数据库允许用户创建用Java编写的自定义函数。在这种情况下,渗透测试员可以利用一个SQL注入漏洞创建自己的函数,执行任意任务。如果应用程序向浏览器返回错误消息,就可以让创建的函数生成一个包含任何想要的数据的异常。例如,下面的代码将运行操作系统命令ls,然后生成一个包含命令输出结果的异常。它将向浏览器返回一个栈追踪,其中第一行包含一个目录列表:

收集公布的信息

除在错误消息中泄露有用的信息外,Web应用程序直接公布的信息也是它披露敏感数据的另一个主要源头。由于以下原因,应用程序可能会公布对攻击者有利的信息。

公布的信息在设计上属于应用程序核心功能的一部分。

公布的信息会无意中给其他功能造成负面影响。

由仍然存在于当前应用程序中的调试功能泄露信息。

由于某个漏洞(如访问控制不完善)而导致信息泄露。

应用程序可能向用户公布的敏感信息通常包括以下几项。

有效用户名、账号与文档 ID 列表。

用户个人资料,包括用户角色与权限、最后登录日期与账户状态。

用户当前使用的密码(该密码在屏幕上隐藏显示,但却出现在页面源代码中)。

包含在日志文件中的信息,如用户名、URL、执行的操作、会话令牌与数据库查询。

客户端HTML源代码中与应用程序有关的细节,如作为注释处理的链接或表单字段以及关于漏洞的注释。

渗透测试步骤

(1)检查应用程序解析过程中得到的结果(请参阅第 4 章了解相关内容),确定可用于获取有用信息的所有服务器端功能与客户端数据。

(2)在应用程序中确定服务器向浏览器返回密码或信用卡资料等敏感数据的所有位置。即使这些信息在屏幕上隐藏显示,但仍然可以在服务器的响应中看到这些信息。如果发现其他适当的漏洞,例如访问控制或会话处理方面的漏洞,就可以利用这种行为获取属于其他应用程序用户的信息。

(3)如果已经确定任何提取敏感信息的方法,请使用第14章描述的技巧自动攻击解析过程。

使用推论

有些情况下,应用程序可能不会直接泄露任何数据,但可以根据它的行为准确推断出有用的信息。

在探查其他类型漏洞的过程中,我们已经遇到过许多以这种方式泄露信息的情况,如下所示。

注册功能允许在选择已经存在的用户名时根据出现的错误消息枚举出已注册的用户名。

搜索引擎允许推断出未获授权就可直接查看的编入索引的文档内容(请参阅第11章了解相关内容)。

在盲目SQL注入漏洞中,可以通过给一个现有的查询增加一个二进制条件,一次一位地提取信息(请参阅第9章了解相关内容)。

.NET中的“填充提示”攻击,在这种攻击中,攻击者可以通过向服务器发送一系列请求,并观察哪些请求在解密期间导致错误,从而解密任何字符串(请参阅第18章)。

另外,根据某种对攻击者有利的事实,如果应用程序执行不同操作所用的时间各不相同,那么,应用程序行为上的这种细微差异也会导致信息泄露。这种差异由以下原因造成。

许多复杂的大型应用程序需要从数据库、消息队列与大型主机等后端系统中提取数据。为提高性能,一些应用程序缓存频繁使用的信息。同样,一些应用程序采用一种延迟加载(lazy load)模式,仅在需要时加载对象和数据。在这种情况下,应用程序会从服务器的本地缓存中迅速提取出最近访问的数据,而从相关后端系统中相对缓慢地提取出其他数据。

电子银行应用程序常常以这种方式运作,与活动账户相比,访问一个休眠账户通常需要更长的时间;这时,技巧熟练的攻击者就可以利用这种行为枚举出其他用户最近访问的账户。

有些时候,应用程序处理某个特殊请求所花的时间取决于用户提交的数据是否有效。例如,如果向登录机制提交一个有效的用户名,应用程序就会执行各种数据库查询,获取账户信息并更新审计日志,同时执行需要进行大量计算的操作,根据保存的散列确认用户提交的密码。如果攻击者能够探测到这种时间差异,他就能利用它枚举有效的用户名。

一些应用程序可能会根据用户输入执行一项操作。如果用户提交的某个数据无效,就会造成超时。例如,如果某应用程序使用cookie保存一个前端负载均衡器(load balancer)之内的主机地址,攻击者就可以操纵这个地址,扫描组织内部网络中的Web服务器。如果提交的服务器地址不属于应用程序基础设施的范围,应用程序就会立即返回一个错误。如果提交一个不存在的地址,那么尝试连接这个地址就会造成超时,然后应用程序再返回与上一种情况相同的常规错误。攻击者可以利用Burp Intruder 结果表中的响应计时器进行这种测试。注意,默认情况下这些列隐藏不可见,但可通过Columns菜单显示。

渗透测试步骤

(1)应用程序响应时间上的差异可能非常微小,难以探测。通常,只有在向关键区域提交重要的数据以及所执行的处理很可能会导致时间差异时,才值得在应用程序中探查这种行为。

(2)为测试某个特殊的功能,编辑两个列表,其中分别包含几个已知有效(或最近被访问)的数据和已知无效(或休眠状态)的数据。以可控制的方式提出包括这两个列表中的每一个数据的请求,一次仅提出一个请求,然后监控应用程序响应每个请求所用的时间。确定数据的状态与响应时间之间是否存在任何关联。

(3)可以使用Burp Intruder自动完成这项任务。对于每一个生成的请求,Intruder将自动记录应用程序响应前所用的时间以及完成响应所用的时间。还可以按这些属性对结果表进行分类,迅速确定明显关联。

防止信息泄露

虽然我们不可能或无法完全阻止泄露对攻击者有用的信息,但可以采取各种相对简单的措施,最大限度地减少信息泄露,防止将最敏感的数据泄露给攻击者,避免应用程序的安全造成严重破坏。

使用常规错误消息

应禁止应用程序向用户的浏览器返回详尽的错误消息或调试信息。如果发生无法预料的错误(如数据库查询错误、磁盘文件读取故障或外部API调用异常),应用程序应返回相同的常规消息,通知用户出现错误。如果因为支持或诊断目的而有必要记录调试信息,那么将这些信息保存在一个用户无法公开访问的服务器端日志中,并在必要时向用户返回相关日志记录的索引号,方便他们在联系服务台时报告这个错误。

可以配置大多数应用程序平台与Web服务器,使其拦截错误消息,不将它返回给浏览器。

在ASP.NET中,可以使用Web.config文件的customErrors元素,通过设置mode属性为On或 RemoteOnly,并在defaultRedirect节点指定一个定制错误页面,从而阻止详尽的错误消息。

在Java Platform中,可以使用web.xml文件的error-page元素配置定制错误消息。exception-type节点可用于指定一个 Java 异常类型,或者使用error-code节点指定一个HTTP状态码;使用location节点可设定发生错误时显示的定制页面。

在Microsoft IIS中,可以使用一个Web站点属性页面的“定制错误”(Custom Errors)选项卡,为不同的HTTP状态码指定定制错误页面。如有必要,可在每个目录的基础上为每个状态码设置一个不同的定制页面。

在Apache 中,可以使用httpd.conf中的ErrorDocument指令配置定制错误页面。例如:

保护敏感信息

只要有可能,应禁止应用程序公布对攻击者有用的信息,包括用户名、日志记录或用户个人资料。如果某些用户需要访问这些信息,应使用访问控制对它们进行有效保护,并且只有在完全必要时才提供这些信息。

如果必须向授权用户透露敏感信息(例如,以便用户更新他们的账户信息),那么在不必要时也不得披露现有数据。例如,应以截短的形式显示保存的信用卡号,绝不能预先填写密码字段,即使它在屏幕上隐藏显示。这些防御措施有助于减轻验证、会话管理与访问控制等应用程序核心安全机制中存在的严重漏洞造成的影响。

尽量减少客户端信息泄露

只要有可能,应删除或修改服务旗标,避免泄露特定软件版本等信息。执行这种防御所需的步骤依应用程序所使用的技术而定。例如,在Microsoft IIS中,可以使用IISLockDown工具中的URLScan删除Server消息头。在最新版本的Apache 中,使用mod_headers模块可达到相同的目的。由于这些信息会随时改变,建议在进行任何修改之前查阅服务器上的文档资料。

另外,还应删除部署在当前生产环境中的客户端代码(包括全部HTML与 JavaScript 代码)中的所有注释。

还要特别注意任何厚客户端组件,如 Java applet 和 ActiveX 控件。不得在这些组件中包含任何敏感信息。技术熟练的攻击者能够破译或逆向制造这些组件,恢复它们的源代码(请参阅第 5章了解相关内容)。

小结

泄露不必要的信息通常不会对应用程序的安全造成严重影响。有时,即使是非常详细的栈追踪与其他调试消息,也不会为攻击应用程序提供很大帮助。

然而,在其他情况下,渗透测试员可能会发现非常有利于实施攻击的信息来源,例如,它们披露了用户名列表、软件组件的准确版本,或者泄露服务器端应用程序逻辑的内部结构与功能。

为此,要对应用程序实施严重的攻击,渗透测试员必须对应用程序自身及公开资源进行仔细的核查,收集有助于发动攻击的信息。有些时候攻击者能够以这种方式收集的信息为起点,攻破泄露信息的应用程序。

问题

欲知问题答案,请访问http://mdsec. net/wahh。

(1)当探查SQL注入漏洞时,如果请求以下URL:

将会收到如下错误消息:

从中可以得出什么结论?应用程序中包含任何可被利用的条件吗?

(2)当对各种参数进行模糊测试时,应用程序返回以下错误消息:

从中可以获得哪些有用的信息?

(3)在解析应用程序的过程中,在服务器上发现了一个激活目录列表的隐藏目录,其中似乎保存着大量以前用过的脚本。请求其中一个脚本返回以下错误消息:

是什么原因造成了这个错误?可以立即发现哪些常见的Web应用程序漏洞?

(4)在探查一个请求参数的功能并试图确定它在应用程序中的作用时,如果请求以下URL:

https://wahh-app.com/agents/checkcfg.php?name=admin&id=13&log=1

应用程序将返回以下错误消息:

这条错误消息是由什么原因造成的?为此应探查什么漏洞?

(5)当模糊测试一个请求,看其中是否存在各种漏洞时,测试员轮流在每个请求参数中提交了一个单引号。其中一个请求的响应包含了一个HTTP 500状态码,表示应用程序可能存在SQL注入漏洞。消息的全部内容如下:

该应用程序是否易于受到攻击?

浙ICP备11005866号-12