攻击用户其他技巧

在前一章中,我们介绍了针对其他应用程序用户的主要攻击——跨站点脚本(XSS)。在这一章中,我们将介绍一系列针对用户的其他攻击。其中的一些攻击与XSS攻击具有很大的相似性。许多时候,这些攻击比XSS更加复杂,或者隐藏性更强,因此,在单纯的XSS攻击无法奏效的情况下,它们往往能够取得成功。

针对其他应用程序用户的攻击形式各异,它们之间的微妙之处与细微差别常常被人们忽略。通常,与主要的服务器端攻击相比,人们对它们也知之甚少,即使经验丰富的渗透测试员也会混淆或忽略各种不同的漏洞。我们将在本章中介绍各种常见的漏洞,并说明确认并利用这些漏洞所需采取的步骤。

诱使用户执行操作

在上一章中,我们介绍了如何利用XSS攻击诱使用户在不知情的情况下在应用程序中执行操作。如果受害用户拥有管理权限,使用这种技巧就可以迅速完全侵入应用程序。在这一节中,我们将介绍另外一些可用于诱使其他用户执行操作的方法。这些方法甚至可以用在已防范XSS攻击的应用程序中。

请求伪造

这种类型的攻击也称为会话叠置(session riding),它们与会话劫持攻击密切相关,在攻击过程中,攻击者截获一名用户的会话令牌,因而能够“作为”该用户使用应用程序。但是,通过请求伪造,攻击者根本不需要知道受害者的会话令牌。相反,攻击者利用Web浏览器的正常行为劫持用户的令牌,并通过它提出用户并不打算提出的请求。

请求伪造漏洞分为两种类型:本站点和跨站点。

本站点请求伪造

本站点请求伪造(On-Site Request Forgery,OSRF)是一种利用保存型XSS漏洞的常见攻击有效载荷。在上一章介绍的MySpace蠕虫示例中,一位名叫Samy的用户在自己的用户资料中插入一段脚本,致使任何查看其资料的用户在不知情的情况下执行各种操作。另外,即使在XSS漏洞并不存在的地方,保存型OSRF漏洞仍有可能存在,这点常被人们忽视。

以消息公告牌应用程序为例,它允许用户提交可被其他用户查看的数据。该应用程序使用以下请求提交消息:

这个请求将以下内容添加到消息页面中:

在这种情况下,测试员当然会测试其中是否存在XSS漏洞。但是,假设应用程序对插入页面中的任何“、<和>字符进行了正确地HTML编码。如果对这种防御方法感到满意,觉得攻击者无论如何也无法避开它,测试员就会继续进行下一步测试。

但是,稍等。我们控制的仅仅是<img>标签目标的一部分内容。虽然我们无法破坏引用字符串,但是可以修改URL,使得查看消息的任何用户提出任意一个本站点GET请求。例如,在type参数中提交下面的值将会使任何查看消息的用户提出一个尝试创建新的管理用户的请求:

如果一名普通用户被诱使提出攻击者专门设计的请求,攻击当然不会成功。但是,如果管理员查看消息,攻击者就可以建立一个秘密账户。上面的示例证明,即使无法实施XSS攻击,但攻击者仍然能够成功执行OSRF攻击。当然,即使管理员采取了防范措施,禁用了JavaScript,攻击依然能够成功。

注意,在前面的攻击字符串中,#符终止了.gif后缀前面的URL。但是,只需在后缀前插入一个&,构成另外一个请求参数,即可解决以上问题。

尝试访问

在以下示例中,可以将OSRF有效载荷放在最近的搜索列表中,即使其并不易于受到XSS攻击:

http://mdsec.net/search/77/

渗透测试步骤

(1)如果一名用户提交的数据在某个位置显示给其他用户,但测试员仍然无法实施保存型XSS攻击,那么在每个这样的位置,检查应用程序的行为是否使得它易于受到OSRF攻击。

(2)用户提交的数据被插入到超链接目标或返回页面中的其他URL等位置时往往会出现漏洞。除非应用程序特别阻止要求的任何字符(通常包括点、斜线及查询字符串中的分隔符),否则它肯定易于受到攻击。

(3)如果发现OSRF漏洞,则应寻找一个适当的请求作为利用目标,如下一节“跨站点请求伪造”所述。

在将其合并到响应中之前,尽可能严格地确认用户提交的输入,即可防止OSRF漏洞。例如,在前面的示例中,应用程序可能会检查type参数中是否有一组值中的某一个特殊的值。如果应用程序必须接受无法预料的其他值,那么应阻止任何包含/ . \ ? &与 = 的请求。

注意,对这些字符进行HTML编码并不能有效防止OSRF攻击,因为浏览器在请求目标URL字符串之前,会首先对其进行解码。

根据插入点与周围环境的不同,使用与下一节描述的防止CSRF攻击时使用的同种防御方法,也可以防止OSRF攻击。

跨站点请求伪造

在跨站点请求伪造(CSRF)攻击中,攻击者只需创建一个看似无害的网站,致使用户的浏览器直接向易受攻击的应用程序提交一个请求,执行某种有利于攻击者的“无意”操作。

如前所述,同源策略并不阻止一个网站向另一个域提出请求。但是,它确实阻止提出请求的网站处理跨域请求的响应。因此,正常情况下,CSRF攻击只是一种“单向”攻击。所以,在纯粹的CSRF攻击中,要想实施如Samy XSS蠕虫中的多阶段操作,从响应中读取数据并将其合并到随后的请求中,将很难实现。(我们将在本章后面部分介绍如何对利用CSRF技巧的某些方法进行扩展,以执行有限的双向攻击,跨域获取数据。)

以某个允许管理员使用以下请求创建新用户账户的应用程序为例:

此请求有3个主要特点导致它易于受到CSRF攻击。

该请求执行特权操作。在上述示例中,该请求使用管理员权限创建了一个新用户。

应用程序仅仅依靠HTTP cookie来追踪会话。请求中的任何其他位置均未传送会话相关的令牌。

攻击者可以确定执行操作所需的所有参数。除cookie中的会话令牌外,请求中不需要包含任何无法预测的值。

针对这些特点表现出的缺陷,攻击者可以构建一个Web页面,向易受攻击的应用程序提出一个跨域请求,在其中包含执行特权操作所需的所有步骤。以下为这种攻击的一个示例:

该攻击将所有请求参数放入隐藏表单字段中,并包含一段用于自动提交表单的脚本。用户的浏览器提交此表单时,将自动添加用户的目标域的cookie,并且应用程序会正常处理生成的请求。如果管理用户登录到易受攻击的应用程序,并访问攻击者的包含此表单的Web页面,该请求将在管理员的会话中处理,攻击者的账户因此得以创建。

尝试访问

http://mdsec.net/auth/390/

2004年,Dave Armstrong在eBay应用程序中发现了一个典型CSRF漏洞。攻击者可以设计一个URL,使得请求这个URL的用户对某个拍卖品给出任意标价。某个第三方网站可以诱使访问者请求这个URL,以致于任何访问这个网站的eBay用户都会报出一个标价。而且,进行调整后,我们还可以在同一eBay应用程序的一个保存型OSRF攻击中利用这个漏洞。应用程序允许用户在拍卖品描述中插入<img>标签。为防止攻击,应用程序确认标签目标返回了真正的图像文件。但是,攻击者也可以在上述位置插入一个指向站外服务器的链接(它在创建拍卖品时返回一幅合法的图像),并随后用一个返回他专门设计的CSRF URL的HTTP重定向代替这个链接。因此,任何查看拍卖品的用户都会在不知情的情况下给出一个标价。欲知攻击详情,请查阅最初在Bugtraq上发表的文章:

http://archive.cert.uni-stuttgart.de/bugtraq/2005/04/msg00279.html

 注解 应用程序确认站外图像方面的漏洞称为“检查时间,使用时间”(TOCTOU)漏洞。因为某个数据在一个时间确认,却在另一个时间使用,导致攻击者能够在这两个时间的间隔内修改该数据的值。

利用CSRF漏洞

CSRF漏洞主要出现在应用程序仅依赖HTTP cookie追踪会话令牌的情况下。一旦应用程序已经在用户的浏览器中设定了cookie,浏览器会自动在随后的每个请求中将这个cookie提交给应用程序。无论请求是源自某个链接、应用程序本身中的表单或任何其他地方(如外部网站或在电子邮件中单击的链接),它都会这样做。如果应用程序未采取防范措施来阻止攻击者以这种方式“叠置”它的用户的会话,它就易于受到CSRF攻击。

渗透测试步骤

(1)根据在应用程序解析过程中得到的结果(请参阅第4章了解相关内容),检查应用程序的关键功能。

(2)找到一项可用于代表不知情的用户执行某种敏感操作的应用程序功能,该功能仅依赖cookie来追踪用户会话,并且使用攻击者能够提前决定的请求参数,也就是说,其中并不包含任何会话令牌或其他无法预测的数据。

(3)创建一个HTML页面,它不需要进行任何用户交互即可提出所需请求。对于GET请求,可以使用<img>标签,并通过src参数设置易受攻击的URL。对于POST请求,可以建立一个表单,其中包含实施攻击所需全部相关参数的隐藏字段,并将其目标设置为易受攻击的URL。可以使用JavaScript在页面加载时自动提交该表单。

(4)登录应用程序后,使用同一个浏览器加载专门设计的HTML页面。确认应用程序是否执行所需操作。

 提示 由于引入了其他攻击向量,CSRF攻击的可能性改变了许多其他类型的漏洞的影响范围。例如,如果某项管理功能接受参数中的用户标识符,然后显示与指定用户有关的信息。该功能受到严格的访问控制,但它的uid参数中包含SQL注入漏洞。由于应用程序管理员为可信用户,并且在任何情况下都能够完全控制数据库,因此,这种SQL注入漏洞被认为风险较低。但是,由于该功能并不执行任何管理操作(根据最初的设计),因此其并未采取防范CSRF的措施。从攻击者的角度看,该功能与专门供管理员执行任意SQL查询的功能一样重要。如果可以注入一个执行某种敏感操作,或通过带外通道检索数据的查询,那么即使是非管理用户也可以通过CSRF实施这种攻击。

验证与CSRF

由于实施CSRF攻击需要在受害用户的会话中执行某种特权操作,因此,在实施攻击时,用户需要登录到应用程序。

一个存在大量危险的CSRF漏洞的位置,是家庭DSL路由器使用的Web界面。这些设备大多包含敏感功能,如打开面向互联网的防火墙上的所有端口。由于这些功能通常并未采取防范CSRF的措施,并且多数用户也没有修改设备的默认内部IP地址,因此,它们易于受到由恶意外部站点传送的CSRF攻击。但是,相关设备通常需要进行验证才能执行敏感操作,而且许多用户并未登录他们的设备。

如果设备的Web界面使用基于表单的验证,则可以通过首先使用户登录设备,然后执行经过验证的操作,从而实施两步攻击。由于大多数用户并未修改这类设备的默认证书(可能认为该Web界面只能通过内部家庭网络访问),因此,攻击者的网页可以首先提出包含默认证书的登录请求。然后,设备会在用户的浏览器中设置一个会话令牌,随后的任何请求,包括由攻击者生成的请求,将自动传送该令牌。

在其他情况下,攻击者可能需要受害用户以攻击者自身的用户账户登录应用程序才能实施特定的攻击。以一个允许用户上传并存储文件的应用程序为例。这些文件随后可以进行下载,但只能由上传它们的用户下载。假设由于没有对文件内容进行过滤,该功能可用于实施保存型XSS攻击(请参阅第12章了解相关内容)。该漏洞似乎并不会造成任何伤害,因为攻击者只能用它来攻击自己。但实际上,通过使用CSRF技巧,攻击者可以利用保存型XSS漏洞来攻破其他用户。如上文所述,攻击者的网页可以提出一个CSRF请求,强制受害用户使用攻击者的证书登录。然后,攻击者的网页可以提出另一个CSRF请求,以下载某个恶意文件。用户的浏览器处理该文件时,攻击者的XSS有效载荷将会执行,用户在易受攻击的应用程序中的会话将被攻破。虽然受害者当前是使用攻击者的账户登录的,但是,攻击并未就此结束。如第12章所述,XSS有效载荷可以在用户的浏览器中持续存在,并执行任意操作,因而可以让用户注销其在易受攻击的应用程序中的会话,并诱使其使用自己的证书登录。

防止CSRF漏洞

由于浏览器自动在随后的每个请求中将cookie返回给发布cookie的Web服务器,CSRF漏洞因此产生。如果某个Web应用程序主要依赖HTTP cookie传送会话令牌,那么它本身就易于受到这种攻击。

防范CSRF攻击的标准方法,是将HTTP cookie与其他追踪令牌的方法相结合。这类方法通常采用其他通过HTTP隐藏表单字段传输的令牌。在每次提交请求时,应用程序除确认会话cookie外,还核实表单是否传送了正确的令牌。如果攻击者无法确定该令牌的值,就无法构建跨域请求,也就无法执行所需的操作。

 注解 本章后面部分将介绍,即使使用CSRF令牌受到可靠保护的功能也可能易于受到用户界面(UI)伪装攻击。

以这种方式使用反CSRF令牌时,必须为这些令牌提供与正常的会话令牌相同的保护。如果攻击者能够预测发布给其他用户的令牌值,他就能够确定提出CSRF请求所需的所有参数,因而仍然能够实施攻击。此外,如果反CSRF令牌未与所属用户的会话相关联,攻击者就可以在自己的会话中获得一个有效令牌,并将此令牌用在针对其他用户的会话的CSRF攻击中。

尝试访问

http://mdsec.net/auth/395/

http://mdsec.net/auth/404/

 警告 一些应用程序使用相对较短的反CSRF令牌,可能因为认为这些令牌不会像较短的会话令牌一样受到蛮力攻击。任何向应用程序传送大量可能值的攻击都需要通过受害者的浏览器传送这些值,包括提交大量可能被轻易察觉的请求。此外,如果收到太多无效的反CSRF令牌,应用程序可能会防御性地终止用户的会话,从而阻止相关攻击。但是,这种防御忽略了纯粹在客户端实施的蛮力攻击,而不向服务器发送任何请求的可能性。在某些情况下,可以通过使用基于CSS的技巧来枚举用户的浏览历史记录,从而实施这种攻击。要想成功实施这类攻击,必须满足以下两个条件:

应用程序必须某些时候在URL查询字符串中传输CSRF令牌。这种情况经常发生,因为许多受保护的功能通过目标URL中包含令牌的简单超链接即可访问。

应用程序必须在整个用户会话中使用相同的反CSRF令牌,或者允许多次使用同一个令牌。这种情况也经常发生,一方面是为了改善用户的使用体验,另一方面是为了便于使用浏览器的“后退”和“前进”按钮。

如果满足这些条件,并且目标用户已访问某个包含反CSRF令牌的URL,攻击者就可以从自己的页面实施蛮力攻击。这时,攻击者页面上的一段脚本将动态创建指向目标应用程序上的相关URL的超链接,同时在每个链接中包括一个不同的反CSRF令牌值。然后,该脚本使用JavaScript API getComputedStyle测试用户是否访问了上述链接。确定某个被访问的链接后,即可发现一个有效的反CSRF令牌,然后,攻击者的页面将其用于代表用户执行敏感操作。

需要注意的是,要防范CSRF攻击,仅仅使用多阶段过程执行敏感操作并不够。例如,管理员在添加新用户账户时,他可能会在第一阶段输入相关信息,然后在第二阶段检查并确认这些信息。如果未使用其他反CSRF令牌,该功能将仍然易于受到CSRF攻击,因为攻击者只需要轮流提交两个所需的请求,或者直接提交第二个请求(极为常见)。

少数情况下,应用程序功能会采用另一个令牌;它在一个响应中设置该令牌,然后在接下来的请求中提交该令牌。但是,在这两个阶段之间转换需要进行重定向,因此应用程序采用的防御机制可能会失效。虽然CSRF属于单向攻击,并且无法从应用程序的响应中读取令牌,但如果CSRF响应包含重定向,而且该重定向指向其他包含令牌的URL,受害者的浏览器将自动访问该重定向,并自动在提出的请求中提交令牌。

尝试访问

http://mdsec.net/auth/398/

不要犯下错误,依靠HTTP Referer消息头来指示请求是源自站内还是站外。Referer消息头可以使用旧版Flash进行修改,或用元刷新标签(meta refresh tag)来伪装。通常而言,使用Referer消息头并不能为Web应用程序提供强大的安全防御。

通过XSS突破反CSRF防御

人们常称,如果应用程序中包含任何XSS漏洞,那么反CSRF防御机制就可以被突破。这种说法并不完全正确。但是,支持这种观点的思考方法是正确的;因为XSS有效载荷在本站执行,可以与应用程序进行双向交互,所以它们能够从应用程序的响应中获取令牌,并在随后的请求中提交这些令牌。

然而,如果某个本身受到反CSRF防御机制保护的页面也包含反射型XSS漏洞,那么这种漏洞并不能直接用于突破防御。记住,在反射型XSS攻击中,最初的请求为跨站点请求。这时,攻击者会设计一个URL或一个POST请求,其中包含随后被复制到应用程序的响应中的恶意输入。但是,如果易受攻击的页面实施了反CSRF防御,那么攻击者要想实施有效攻击,其专门设计的请求中必须已经包含必要的令牌。如果其中没有所需令牌,应用程序将会拒绝攻击者提出的请求,同时包含反射型XSS漏洞的代码路径也不会执行。这时,问题并不在于注入的脚本是否能够读取应用程序响应中的任何令牌(当然它能),而在于如何首先将脚本注入到某个包含那些令牌的响应中。

通常,在下面几种情况下,我们可以利用XSS漏洞突破反CSRF防御。

如果受保护的功能中存在任何XSS漏洞,那么攻击者总可以利用这些漏洞突破反CSRF防御。通过保存型攻击注入的JavaScript可直接读取脚本所在的应用程序响应中的令牌。

如果应用程序仅对一部分通过验证的功能实施反CSRF防御,并且某项未防御CSRF的功能中存在一个反射型XSS漏洞,那么攻击者就可以利用这个漏洞来突破反CSRF防御。例如,如果应用程序仅采用反CSRF令牌保护转账功能的第二个步骤,那么攻击者就可以利用反射型XSS攻击从其他步骤中突破防御。通过这个漏洞注入的一段脚本可以向第一个转账步骤提出一个站内请求,截取令牌,然后使用这个令牌进入第二个步骤。攻击之所以能够成功,是因为第一个没有采取CSRF防御的转账步骤返回了访问受保护页面所需的令牌。仅依赖HTTP cookie实现第一个步骤,意味着攻击者可以利用它访问保护第二个步骤的令牌,从而实施有效攻击。

在某些应用程序中,反CSRF令牌仅与当前用户相关联,而不是与用户的会话相关联。在这种情况下,如果登录表单未防范CSRF攻击,则应用程序仍有可能受到多阶段攻击。首先,攻击者使用自己的账户登录,获得一个与他的用户身份关联的有效反CSRF令牌。然后,攻击者对登录表单发动CSRF攻击,迫使受害用户使用他的证书登录,如上文介绍利用相同用户的保存型XSS漏洞时所述。一旦用户作为攻击者登录,攻击者将使用CSRF使用户提出相关请求,对XSS漏洞加以利用,同时使用他此前获得的反CSRF令牌。然后,攻击者的XSS有效载荷将在用户的浏览器中执行。由于用户仍然作为攻击者登录,XSS有效载荷可能需要使用户注销,然后诱使用户再次登录,最终,用户的登录证书和生成的应用程序会话都被完全攻破。

如果反CSRF令牌未与用户关联,而是与当前会话关联,且攻击者可以通过某种方法在用户的浏览器中注入cookie,则只需对以上攻击稍作修改即可(本章后面部分将介绍这种攻击)。这时,攻击者不是使用自己的证书针对登录表单实施CSRF攻击,而可以直接向用户传送他当前的会话令牌及与该会话关联的反CSRF令牌。然后,该攻击的剩余部分与之前所述的步骤相同。

除这些情形外,在许多时候,针对CSRF攻击的有效防御能够在很大程度上阻止(即使不能完全阻止)攻击者利用某些反射型XSS漏洞。但是,在任何情况下,无论我们采取了何种反CSRF防御来阻止攻击者试图利用XSS条件,我们都应始终修复应用程序中存在的任何这类XSS条件。

UI伪装

基本上,与页面中的令牌有关的反CSRF防御旨在确保请求是由应用程序中的用户操作本身提出的,而不是由某个第三方域诱发的。即使采用了反CSRF令牌,第三方站点仍然可以通过UI伪装攻击诱使其他域中的用户执行操作。在某种程度上,这类攻击之所以能够成功,是因为生成的请求实际上来自攻击者针对的应用程序。UI伪装技巧通常也称为“点击劫持”(clickjacking)、“键击劫持”(strokejacking)等其他常见说法。

基本上,在UI伪装攻击中,攻击者的网页会将目标应用程序加载到其页面上的iframe中。而实际上,攻击者会用其他界面覆盖目标应用程序的界面。攻击者的界面中包含吸引用户并诱使其执行各种操作(如在页面的特定区域单击鼠标)的内容。用户执行这些操作时,虽然看起来其单击的是攻击者的界面中显示的按钮和其他UI元素,但他实际上是在不知情的情况下与攻击者所针对的应用程序进行交互。

以一个分两步进行转账的银行功能为例。在第一步中,用户提交转账信息。对此请求的响应将显示这些信息,以及一个用于确认该操作并进行转账的按钮。此外,为防止CSRF攻击,响应中的表单还包含一个隐藏字段,其中提供了一个无法预测的令牌。此令牌在用户单击“确认”时提交,应用程序将在转账之前验证它的值。

在UI伪装攻击中,攻击者的页面在此过程中使用传统的CSRF提交第一个请求。提交过程在攻击者页面内的iframe中完成。和正常情况下一样,应用程序会作出响应,返回要添加的用户的详细信息,以及一个用于确认该操作的按钮。此响应将在攻击者的iframe中“显示”,该iframe已由攻击者的界面覆盖,该界面旨在诱使受害用户单击包含“确认”按钮的区域。如果用户在此区域单击,他将在不知情的情况下单击目标应用程序中的“确认”按钮,从而创建新用户。这种基本的攻击如图13-1所示。

图13-1 基本的UI伪装攻击

这种攻击之所以能够在纯粹的CSRF攻击无法奏效的情况下取得成功,是因为应用程序使用的反CSRF令牌以正常方式得到处理。虽然由于同源策略的原因,攻击者的页面无法读取该令牌的值,但攻击者的iframe中的表单包含了由应用程序生成的令牌,在受害用户不知情的情况下单击“确认”按钮时,这个令牌被返交给应用程序。在目标应用程序看来,一切都很正常。

要实施欺骗,即让受害用户虽然看到一个界面,但实际上却与另一个界面交互,攻击者可以采用各种CSS技术。加载目标应用程序的iframe可以为任意大小,位于攻击者页面中的任何位置,并显示目标页面的任意位置。使用适当的样式属性,可以令该iframe变得完全透明,从而使其对用户不可见。

尝试访问

http://mdsec.net/auth/405/

如果进一步扩展上述基本攻击,攻击者可以在其界面中使用复杂的脚本代码,以诱使受害用户执行更加复杂的操作,而不仅仅是单击按钮。比方说,要实施攻击,需要诱使用户在输入字段(如转账页面的“金额”字段)中输入一些文本。在这种情况下,攻击者可以在其用户界面中包含一些诱使用户输入文本的内容,如用于输入电话号码以赢得奖励的表单。然后,攻击者的页面中的脚本可以对进行键击选择性处理,在用户输入相关字符时,将键击操作有效传递到目标界面,从而填写所需的输入字段。如果用户输入攻击者不希望在目标界面中输入的字符,该键击将不会传递给目标界面,攻击者的脚本将等待下一次键击。

另外,攻击者的页面中可以包含诱使用户执行拖动鼠标操作(就像玩简单的游戏一样)的内容。随后,在攻击者的页面中运行的脚本将选择性地处理生成的操作,使用户在不知情的情况下选择目标应用程序界面中的文本,并将其拖动到攻击者的界面中的输入字段中(或相反)。例如,在针对Web邮件应用程序实施攻击时,攻击者可以诱使用户将电子邮件中的文本拖动到其能够读取的输入字段中。或者,攻击者可以诱使用户建立某种规则,向某转发所有电子邮件,并将所需电子邮件地址从攻击者的界面拖动到定义该规则的表单的相关输入字段中。此外,由于链接和图像均可以作为URL进行拖动,攻击者甚至可以通过诱发拖动操作从目标应用程序的界面中拦截敏感URL,包括反CSRF令牌。

有关这些和其他攻击向量,及其实施方法的详细说明,请参阅以下文档:

http://ui-redressing.mniemietz.de/uiRedressing.pdf

破坏框架防御

在UI伪装攻击最初受到广泛关注时,许多知名的Web应用程序寻求采用一种称为破坏框架(framebusting)的技术来防范这类攻击。在某些情况下,这种技术已用于防范其他基于框架的攻击。

破坏框架可以表现为各种形式,但基本上,它是指每个相关的应用程序页面都会运行一段脚本来检测自己是否被加载到iframe中。如果是,应用程序会尝试“破坏”该iframe,或执行其他防御性操作,如重定向到错误页面或拒绝显示应用程序自己的界面。

斯坦福大学2010年的一项研究表明,排名前500的网站均采用了“破坏框架”防御技术。同时,这项研究还发现,这些防御都可以通过某种方式突破。突破这种防御的方法因每种防御的实施细节而异,下面我们通过一段“破坏框架”示例代码来加以说明:

这段代码检查页面本身的URL与浏览器窗口中的顶部框架的URL是否匹配。如果不匹配,则说明页面已加载到子框架内。在这种情况下,脚本会尝试将页面重新加载到窗口内的顶层框架中,从而“逃离”该框架。

实施UI伪装攻击的攻击者可以通过各种方式避开这种防御,将目标页面成功嵌入框架。

由于攻击者的页面控制着顶层框架,因而可以重新定义top.location的含义,在子框架尝试引用它时导致异常。例如,攻击者可以在Internet Explorer中运行以下代码:

这段代码将location重新定义为顶层框架中的本地变量,在子框架中运行的代码无法访问该变量。

顶层框架可能会钩住window.onbeforeunload事件,从而在“破坏框架”代码尝试设置顶层框架的位置时运行攻击者的事件处理程序。这时,攻击者的代码可以对返回HTTP 204(无内容)响应的URL执行进一步的重定向。这会导致浏览器取消重定向调用链,使顶层框架的URL保持不变。

顶层框架可以在将目标应用程序加载到子框架中时定义sandbox属性。这会在子框架中禁用脚本,同时将其cookie保持为启用状态。

如第12章所述,顶层框架可以利用IE XSS过滤器在子框架中选择性的禁用“破坏框架”脚本。当攻击者的页面指定iframe目标的URL时,可以创建一个新参数,在参数值中包含一段适当的“破坏框架”脚本。IE XSS过滤器将标识该参数值及目标应用程序返回的响应中的脚本代码,并禁用响应中的脚本,设法为用户提供保护。

尝试访问

http://mdsec.net/auth/406/

防止UI伪装

目前,业界普遍认为,虽然一些类型的“破坏框架”代码可以在一定程度上阻止UI伪装攻击,但绝不能将这种技术作为防范UI伪装攻击的万全之策。

要防止攻击者将应用程序页面嵌入框架,一种更加可靠的方法是使用X-Frame-Options响应消息头。该消息头由Internet Explorer 8引入,随后,许多其他流行的浏览器也开始采用这种方法。X-Frame-Options消息头可以接受两个值。值deny指示浏览器防止页面被嵌入框架,值sameorigin指示浏览器防止第三方域执行“嵌入框架”操作。

 提示 在分析应用程序采用的任何反嵌入框架防御时,应始终检查适用于移动设备的界面的任何相关版本。例如,虽然wahh-app.com/chat/能够可靠地防范嵌入框架攻击,但wahh-app.com/mobile/chat/可能并不提供此类防御。在设计反嵌入框架防御时,应用程序开发者通常会忽略用户界面的移动版本,这可能是因为他们认为UI伪装攻击无法在移动设备上实施。但是,许多情况下,在使用标准(非移动)浏览器访问时,移动版本的应用程序仍然能够正常运行,并且用户会话可以在移动和非移动版本的应用程序之间共享。

跨域捕获数据

同源策略旨在防止在一个域中运行的代码访问由其他域提供的内容。因此,跨站点请求伪造攻击通常被称为“单向”攻击。虽然一个域可以向另一个域提供请求,但它很难读取这些请求的响应,从而从其他域中窃取用户数据。

实际上,在某些情况下,有各种攻击技巧可用于从其他域中捕获整个或部分响应。通常,这些攻击会对目标应用程序某方面的功能及常见浏览器的某个功能加以综合利用,从而突破同源策略防御,实现跨域捕获数据的目的。

通过注入HTML捕获数据

与利用XSS漏洞不同,攻击者可以利用许多应用程序提供的功能,在其他用户收到的响应中注入一段有限的HTML。例如,Web邮件应用程序可能会显示包含某个HTML标记的电子邮件,但会阻止可用于执行脚本代码的任何标签和属性。或者,动态生成的错误消息可能会过滤一系列表达式,但仍然允许有限使用HTML。

在这些情况下,就可以利用HTML注入条件向攻击者所在的域发送页面中的敏感数据。例如,在Web邮件应用程序中,攻击者或许可以捕获私人电子邮件的内容。或者,攻击者也许可以读取页面中使用的反CSRF令牌,从而实施CSRF攻击,将用户的电子邮件转发到任意地址。

以一个允许攻击者在以下响应中注入有限的HTML的Web邮件应用程序为例:

在注入点之后,页面包含了一个提供CSRF令牌的HTML表单。在这种情况下,攻击者可以在上述响应中注入以下文本:

这段HTML将打开一个指向攻击者域中的URL的图像标签。该URL包含在单引号内,但URL字符串并未终止,<img>标签也没有结束。这会导致浏览器将注入点之后的文本视为URL的一部分,直到遇到单引号,也就是响应中随后出现引用的JavaScript字符串的位置。浏览器接受各种插入字符,也允许URL跨越多行。

用户的浏览器处理攻击者注入的响应时,它会尝试提取指定的图像,并向以下URL提出请求,从而向攻击者的域中发送敏感的反CSRF令牌:

另一个攻击可以注入以下文本:

此攻击在应用程序本身使用的<form>标签之前注入一个指定攻击者域的<form>标签。在这种情况下,浏览器在遇到嵌入的<form>标签时,它们将忽略该标签,并在遇到第一个<form>标签的情况下处理表单。因此,如果用户提交表单,表单的所有参数,包括敏感的反CSRF令牌,将被提交到攻击者的服务器中:

由于上述第二个攻击仅注入了格式正常的HTML,因此能够更有效地避开那些旨在允许回显的输入中的HTML子集的过滤。但是这种攻击也需要用户干预,在某些情况下,这可能会降低它的效率。

通过注入CSS捕获数据

在上一节的示例中,攻击者需要在注入的文本中使用有限的HTML标记,才能跨域捕获部分响应。但是,许多时候,应用程序会阻止或对注入的输入中的<和>字符进行HTML编码,防止攻击者插入任何新的HTML标签。Web应用程序中大多存在此类纯文本注入条件,并且人们通常认为这种条件不会造成危险。

例如,在一个Web邮件应用程序中,攻击者可以通过电子邮件主题行在目标用户的响应中注入有限的文本。在这种情况下,攻击者可以通过在应用程序中注入CSS来跨域捕获敏感数据。

在上述示例中,假设攻击者发送带以下主题行的电子邮件:

由于其中不包含任何HTML元字符,大多数用户都接受并在收件人用户的响应中显示这段代码。这时,返回给用户的响应可能与以下内容类似:

很明显,此响应中包含HTML。但奇怪的是,浏览器将该响应加载为CSS样式表,将正常处理其中包含的任何CSS定义。在这段代码中,注入的响应定义了CSS font-family属性,并将一个引用的字符串作为属性定义。攻击者注入的文本并未终止该字符串,因此,该字符串会一直持续到响应的剩余部分,包括包含敏感的反CSRF令牌的隐藏表单字段。(请注意,CSS定义不需要被引用。但是,如果没有引用CSS定义,它们可能会在下一个分号位置终止,而该分号可能出现在攻击者希望捕获的敏感数据之前。)

要利用这种行为,攻击者需要在自己的域中创建一个页面,在其中包含CSS样式表形式的注入响应。这会在攻击者自己的页面中应用任何嵌入的CSS定义。然后,攻击者可以使用JavaScript来查询这些定义,从而检索捕获的数据。例如,攻击者可以创建一个包含以下内容的页面:

此页面包含来自Web邮件应用程序的表示为样式表的相关URL,并运行脚本来查询font-family属性,该属性已在Web邮件应用程序的响应中定义。然后,font-family属性的值,包括敏感的反CSRF令牌,将通过针对以下URL的、动态生成的请求传送到攻击者的服务器中:

此攻击可在当前版本的Internet Explorer上实施。为防止这种攻击,其他浏览器已修改了它们处理CSS的方式,将来IE也可能会这样做。

JavaScript劫持

JavaScript劫持提供了另一种跨域捕获数据的方法,从而将CSRF转换为一种有限的“双向”攻击。如第3章所述,同源策略允许一个域包含其他域的脚本代码,并且该代码可以在调用域、而不是发布域中运行。只要可执行的应用程序响应使用仅包含非敏感代码(可由任何应用程序用户访问的静态代码)的跨域脚本,这种规定就不会造成危险。但是,今天的许多应用程序都使用JavaScript来传输敏感数据,并且其传输方式并不受同源策略的限制。此外,随着浏览器技术的发展,许多语法都可以作为有效的JavaScript执行,这为跨域捕获数据提供了新的机会。

应用程序设计方面的变化(归于宽泛的“2.0”概念)也为使用JavaScript从服务器向客户端传输敏感数据提供了新的方法。许多时候,要通过向服务器提供异步请求更新用户界面,一种快速有效的方法,是动态插入脚本代码,并在其中以某种形式包含需要显示的特定的用户数据。

在这一节中,我们将介绍各种使用动态执行的脚本代码来传输敏感数据的方法。同时,我们还将说明如何劫持这类代码,以捕获其他域中的数据。

函数回调

以一个应用程序为例,它在当前用户单击相应的选项卡时,在用户界面中显示该用户的个人信息。为提供无缝的用户体验,应用程序使用异步请求提取用户信息。当用户单击“个人资源”选项卡时,某段客户端代码将动态包含以下脚本:

针对此URL的响应包含一个函数回调,该函数在UI中显示用户个人资料。

在这种情况下,攻击者可以创建一个执行showUserInfo函数的页面,并在其中包含传送个人信息的脚本,从而捕获用户的个人资源。一个简单的概念验证攻击如下所示:

如果用户在访问攻击者的页面的同时,还登录了某个易受攻击的应用程序,则攻击者的页面将动态插入包含用户个人信息的脚本。该脚本将调用showUserInfo函数,由攻击者实施时,它将接收用户的个人资料,包括用户的密码(如本例所示)。

尝试访问

http://mdsec.net/auth/420/

JSON

下面我们对上一个示例稍做修改,应用程序将不再在动态调用的脚本中执行函数回调,而是返回包含用户个人资料的JSON数组:

如第3章所述,JSON是一种灵活的数据表示形式,并且可以由JavaScript解释器直接处理。

在旧版本的Firefox中,攻击者可以执行一次跨域脚本包含攻击,通过覆盖JavaScript中的默认Array构造函数来捕获这些数据。例如:

此攻击修改默认的Array对象,并定义一个定制的setter函数(在为数组中的元素分配值时将调用该函数)。然后,它执行包含JSON数据的响应。JavaScript解释器将处理这些JSON数据,构造一个Array来保存它们的值,并对数组中的每个值调用攻击者定制的setter函数。

由于此类攻击已于2006年被发现,因而开发者已对Firefox进行了修改,以防止在数据初始化过程中调用定制的setter函数。此攻击无法在当前版本的浏览器中实施。

尝试访问

http://mdsec.net/auth/409/

要利用本示例,请下载2.0版本的Firefox。请从以下URL下载该版本的Firefox:

www.oldapps.com/firefox.php?old_firefox=26

变量分配

以一个社交网络应用程序为例,该应用程序大量使用异步请求来执行各种操作,如更新状态、添加好友和发布评论。为提供快速无缝的用户体验,一部分用户界面使用动态生成的脚本加载。

为防止标准的CSRF攻击,这些脚本中包含了反CSRF令牌,以便在执行敏感操作时使用。利用在动态脚本中插入这些令牌导致的漏洞,攻击者可以通过跨域包含相关脚本来捕获令牌。

例如,假设wahh-network.com上的应用程序返回包含以下代码的脚本:

一个用于跨域捕获nonce值的简单概念验证攻击如下所示:

在另一个示例中,令牌的值在函数中进行分配:

这时,攻击者可以实施以下攻击:

针对不同的变量分配情形,攻击者可以采用各种其他技巧。在某些情况下,攻击者可能需要在一定程度上模仿目标应用程序的客户端逻辑,才能包含该程序的部分脚本并捕获敏感数据。

E4X

就在不久之前,E4X成为一个快速发展的领域,为应对在各种实际应用程序中发现的各种可利用条件,开发者一直在对浏览器进行更新。

E4X是对ECMAScript语言(包括JavaScript)的扩展,后者可为XML语言添加本地支持。目前,当前版本的Firefox浏览器已实施了E4X。尽管其中的漏洞已经修复,但Firefox在E4X的处理方式上仍存在漏洞,可用于跨域捕获数据。

除了允许在JavaScript中直接使用XML语法外,用户还可以在E4X嵌入代码,以调用XML中的JavaScript:

E4X的这些特性导致了两个严重的后果,可用于实施跨域数据捕获攻击:

结构正确的XML标记将被视为不会分配给任何变量的值;

嵌入{…}块中的文本将作为JavaScript执行,用于对XML数据的相关部分进行初始化。

许多结构正确的HTML也是结构正确的XML,意味着它们可以由E4X进行处理。此外,许多HTML都在{…}块中包含提供敏感数据的脚本代码。例如:

在早期版本的Firefox中,攻击者可以对类似于上面的完整HTML响应执行跨域脚本包含,并在自己的域中执行一些嵌入式JavaScript代码。

此外,利用与之前所述的CSS注入攻击类似的技巧,攻击者有时可以在目标应用程序的HTML响应中的适当位置注入文本,在该响应中的敏感数据周围插入任意的{…}块。然后,攻击者可以跨域包含整个响应,将其作为脚本执行,以捕获其中包含的数据。

上述任何一种攻击都可以在当前版本的浏览器中实施。随着这个过程不断继续,浏览器对于最新语法结构的支持也进一步扩展,在新的浏览器功能推出之前,针对不易于受到上述攻击的应用程序,很可能会出现新型跨域数据捕获攻击。

防止JavaScript劫持

实施JavaScript劫持攻击必须满足几个前提条件。因此,要防止这种攻击,必须违反其中至少一个前提条件。要获得深层保护,我们建议在防御攻击时同时采用多种防范措施。

至于执行敏感操作的请求,应用程序应使用标准的反CSRF防御来阻止跨域请求返回任何包含敏感数据的响应。

当应用程序从它自己的域中动态执行JavaScript代码时,并不仅限于使用<script>标签来包含脚本。因为请求为本站请求,客户端代码可以使用XMLHttpRequest检索原始响应并进行其他处理,然后再将其作为脚本执行。这意味着,应用程序可以在响应的开始部分插入无效或有问题的JavaScript,客户端应用程序在处理脚本前,将会删除这些内容。例如,以下脚本在使用脚本包含执行时将导致无限循环,但如果使用XMLHttpRequest访问,则可以在执行之前删除:

由于应用程序可以使用XMLHttpRequest检索动态脚本,因此它也可以使用POST请求完成这个任务。如果应用程序仅接受使用POST请求访问可能易受攻击的脚本代码,它就能够阻止第三方站点将它们包含在<script>标签内。

同源策略深入讨论

在本章和前一章中,我们介绍了如何将同源策略应用于HTML和JavaScript的大量示例,以及利用应用程序漏洞和浏览器怪癖突破这种策略的各种方式。为进一步了解同源策略对于Web应用程序安全的重要性,我们将在这一节中介绍其他一些适用该策略的情形,以及这些情形如何会导致某些跨域攻击。

同源策略与浏览器扩展

各种广泛部署的浏览器扩展技术全都在域之间实施了某种隔离,这种隔离的实施方式与主要的浏览器同源策略所采用的基本原则相同。但是,每种实施方式的一些特点在某些情况下可能会导致跨域攻击。

同源策略与Flash

Flash对象的来源由加载这些对象的URL所在的域决定,而不是由加载这些对象的HTML页面的URL决定。和浏览器中的同源策略一样,默认情况下,将基于协议、主机名和端口号实施隔离。

除与同一来源进行完全双向交互外,Flash对象还可以通过浏览器使用URLRequest API提出跨域请求。与纯粹的浏览器技术相比,以这种方式提出请求可以对请求实施更进一步的控制,如能够指定任意的Content-Type消息头及在POST请求主体中发送任意内容。将对这些请求应用浏览器cookie,但默认情况下,提出这些请求的Flash对象并不能读取对跨源请求做出的响应。

Flash提供了一种机制,各种域可通过这种机制向来自其他域的Flash对象授予权限,以便于这些对象与它们进行完全双向的交互。通常,授予权限的域会在URL /crossdomain.xml处发布一个策略文件,从而完成这一任务。当某个Flash对象尝试提出双向跨域请求时,Flash浏览器扩展将检索所请求的域中的策略文件,并仅在所请求的域授权对提出请求的域的访问权限时,才允许上述请求。

由www.adobe.com发布的Flash策略文件如下所示:

渗透测试步骤

测试员应始终检查所测试的任何Web应用程序中的/crossdomain.xml文件。即使应用程序本身不使用Flash,但如果向另一个域授予权限,则由该域发布的Flash对象将可以与发布策略的域进行交互。

如果应用程序允许无限制访问(通过指定<allow-access-from domain=“*” />),则任何其他站点均可以执行双向交互,从而控制应用程序用户的会话。这样,其他域就可以检索全部数据,并执行任何用户操作。

如果应用程序可以访问同一组织使用的子域或其他域,则这些域当然可以与应用程序进行双向交互。这意味着,攻击者可以利用这些域上的XSS等漏洞来攻破授予权限的域。此外,如果攻击者能够在任何域上购买基于Flash的广告,就可以使用其部署的Flash对象来攻破授予权限的域。

一些策略文件会披露内联网主机名或其他可能对攻击者有用的敏感信息。

此外,需要注意的是,Flash对象可能会在应从中下载策略文件的目标服务器上指定一个URL。如果默认位置没有顶级策略文件,Flash浏览器会尝试从该指定的URL处下载策略文件。对此URL的响应必须包含格式有效的策略文件,并必须在Content-Type消息头中指定一种XML或基于文本的MIME类型,才能得到处理。当前,网络上的大多数域都没有在/crossdomain.xml位置发布Flash策略文件,这可能基于以下假设:在没有策略的情况下,默认行为是禁止任何跨域访问。但是,这一假设忽略了第三方Flash对象指定用于下载策略的定制URL的可能性。如果应用程序包含任何功能,可被攻击者用于在应用程序域上的URL中插入任意XML文件,则该应用程序可能就易于受到这种攻击。

同源策略与Silverlight

用于Silverlight的同源策略在很大程度上基于由Flash实施的策略。Silverlight对象的来源由加载这些对象的URL所在的域决定,而不是由加载这些对象的HTML页面的URL决定。

Silverlight与Flash的一个重要区别在于,Silverlight不会基于协议或端口隔离来源,因此通过HTTP加载的对象可以与同一域上的HTTPS URL交互。

Silverlight使用自己的跨域策略文件,地址为/clientaccesspolicy.xml。由www.microsoft.com发布的Silverlight策略文件如下所示:

上面介绍的针对Flash跨域策略文件的注意事项同样适用于Silverlight,但是,Silverlight不允许对象为策略文件指定非标准的URL。

如果服务器上没有Silverlight策略文件,Silverlight浏览器扩展会尝试从默认位置加载有效的Flash策略文件。不过,如果存在策略文件,则扩展会处理该文件。

同源策略与Java

Java在来源之间实施隔离,它实施隔离的方式在很大程度上基于浏览器的同源策略。和其他浏览器扩展一样,Java applet对象的来源由加载这些对象的URL所在的域决定,而不是由加载这些对象的HTML页面的URL决定。

Java同源策略的一个重要不同在于:某些情况下,与来源域共享IP地址的其他域将被视为“同源”。在某些共享主机的情况下,这可能会导致一定程度的跨域交互。

当前,Java并不限制一个域发布允许与其他域进行交互的策略。

同源策略与HTML5

按照最初的设计,XMLHttpRequest仅允许向与调用页面的来源相同的来源提出请求。随着HTML5的出现,这一技术已得以修改,从而可以与其他域进行双向交互,前提是被访问的域为交互提供权限。

跨域交互的权限通过一系列新的HTTP消息头来实现。如果某个脚本尝试使用XMLHttpRequest提出跨域请求,处理该请求的方式将因请求的具体内容而异。

对于“常规”请求,即可以使用现有的HTML结构跨域生成的请求,浏览器将提出请求,并检查生成的响应消息头,以确定是否应允许调用脚本访问该请求的响应。

其他无法使用现有的HTML生成的请求,如那些使用非标准HTTP方法或Content-Type、或添加了定制HTTP消息头的请求,将进行不同处理。浏览器会首先向目标URL提出一个OPTIONS请求,然后检查响应消息头,以确定是否应允许那些请求。

在上述两种情况下,浏览器都会添加一个Origin消息头,用于指示尝试提出跨域请求的域。

要确定可能执行双向交互的域,服务器的响应中应包含Access-Control-Allow-Origin消息头,其中包括以逗号分隔的允许的域列表和通配符:

在第二种情况下,如果已使用OPTIONS请求预先验证了跨域请求,则可以使用以下消息头来指示尝试提出的请求的具体内容:

为响应OPTIONS请求,服务器可以使用以下消息头来指定允许提出的跨域请求的类型:

渗透测试步骤

(1)要测试应用程序如何使用XMLHttpRequest处理跨域请求,测试员应尝试添加一个用于指定其他域的Origin消息头,并检查返回的任何Access-Control消息头。允许任何域或指定的其他域进行双向访问导致的安全隐患与上述Flash跨域策略导致的安全隐患相同。

(2)如果有任何跨域访问受到支持,则测试员还应使用OPTIONS请求来了解到底允许哪些消息头和其他请求。

除可能允许外部域进行双向交互外,XMLHttpRequest的新特性还可能导致利用Web应用程序的特定功能的新型攻击,或新型常规攻击。

如第12章所述,一些应用程序使用XMLHttpRequest向在URL参数中、或在片断标识符后指定的文件提出异步请求。检索到的文件动态加载到当前页面的<div>中。由于以前不可能使用XMLHttpRequest提出跨域请求,因此也没有必要验证所请求的项目是否在应用程序自身的域上。利用新版本的XMLHttpRequest,攻击者可以在其控制的域上指定一个URL,从而对应用程序用户实施客户端远程文件包含攻击。

更常见的是攻击者可以借助XMLHttpRequest的新特性,利用恶意或被攻破的网站,通过访问网站用户的浏览器来实施攻击,即使这时跨域访问已遭到禁止。跨域端口扫描表明,使用XMLHttpRequest尝试向任意主机和端口提出请求,并观察响应的时间差异,可以推断所请求的端口是否已打开、关闭或被过滤。此外,与传统的生成跨域请求的方法相比,使用XMLHttpRequest可以更快速地实施分布式拒绝服务攻击。如果目标应用程序禁止跨域访问,则需要在URL参数中增加一个值,以确保每个请求针对不同的URL,因此实际上由浏览器提出。

通过代理服务应用程序跨域

一些公开发布的Web应用程序提供高效的代理服务功能,允许从不同域检索内容,但服务于代理Web应用程序中的用户。Google翻译(GT)就是一个典型的例子,它可以请求指定的外部URL并返回其内容,如图13-2所示。(虽然翻译引擎可能会修改检索到的响应中的文本,但基本的HTML标记和任何脚本代码仍保持不变。)

图13-2 Google翻译可请求外部URL,并返回其内容,响应中的文本将被翻译成指定的语言

如果两个不同的外部域均通过GT应用程序访问,这时可能会一个有趣的问题。这种情况下,在浏览器看来,来自每个外部域的内容将驻留在GT域中,因为这是浏览器从中检索内容的域。虽然两组内容均驻留在同一个域中,它们之间可以进行双向交互(如果这种交互也通过GT域实施的话)。

当然,如果用户登录某个外部应用程序,然后通过GT访问该应用程序,则该用户的浏览器会正确地将GT视为其他域。因此,用户用于外部应用程序的cookie将不会通过GT在请求中发送,并且也不可能进行任何其他交互。同样,恶意网站也无法利用GT轻松攻破其他应用程序上的用户会话。

但是,网站可以利用GT等代理服务行为与位于其他域上的应用程序的公开、未授权的区域进行双向交互。Jikto就是这样的一种攻击。Jikto是一个概念验证蠕虫,通过在Web应用程序中查找并利用永久性XSS漏洞,从而在应用程序之间进行传播。Jikto代码的基本运行机制如下。

初次运行时,该脚本会检查其是否在GT域中运行。如果不是,它会通过GT域加载当前URL,从而将自己传送到GT域中。

该脚本通过GT请求外部域中的内容。由于该脚本自身在GT域中运行,它可以通过GT与任何其他域上的公开内容进行双向交互。

该脚本以JavaScript实现一个基本的Web扫描程序,在外部域中探查永久性XSS漏洞。公告牌等可以公开访问的功能中可能存在这类漏洞。

确定适当的漏洞后,该脚本将利用此漏洞将它的一个副本加载到外部域中。

其他用户访问被攻破的外部域时,该脚本开始执行,并且这个过程会不断自动重复。

Jikto蠕虫会设法利用XSS漏洞来传播自己。但是,这种通过代理服务合并域的基本攻击技巧并不取决于所针对的单个外部应用程序中的任何漏洞,也无法进行有效防御。此外,它还是一种有用的攻击技巧。测试员也可以通过它来了解如何在非常规情况下应用同源策略。

其他客户端注入攻击

到现在为止,我们介绍的许多攻击主要与利用某种应用程序功能向应用程序响应中注入专门设计的内容有关。这其中最主要的攻击为XSS攻击。我们还介绍了通过注入的HTML和CSS代码跨域捕获数据的技巧。在这一节中,我们将介绍其他一些客户端注入攻击。

HTTP消息头注入

如果用户控制的数据以不安全的方式插入到应用程序返回的HTTP消息头中,这时就会出现HTTP消息头注入漏洞。如果攻击者能够在他控制的消息头中注入换行符,他就能在响应中插入其他HTTP消息头、并在响应主体中写入任意内容。

这种漏洞最常见于Location与Set-Cookie消息头中,但也会出现在其他HTTP消息头中。前文已经讲到,应用程序提取用户提交的输入,并将它插入到响应码为3xx的Location消息头中。同样,一些应用程序提取用户提交的输入,并将其插入cookie值中。例如:

在上述任何一种情况下,攻击者都可以使用回车符(0x0d)或换行符(0x0a)构造一个专门设计的请求,在他们控制的消息头中注入一个换行符,从而在下面的行中注入其他数据。例如:

利用消息头注入漏洞

查找消息头注入漏洞的方法与查找XSS漏洞的方法类似,同样需要寻找用户控制的输入重复出现在应用程序返回的HTTP消息头中的情况。因此,在探查应用程序是否存在XSS漏洞的过程中,还应当确定应用程序可能易于受到消息头注入的全部位置。

渗透测试步骤

(1)在用户控制的输入被复制到HTTP消息头中的每个位置都可能存在漏洞,确认应用程序是否接受URL编码的回车符(%0d)与换行符(%0a),以及它们是否按原样在响应中返回。

(2)注意,是在服务器的响应中而不是换行符的URL编码形式中寻找换行符本身。如果通过拦截代理服务器查看响应,攻击成功的话,应该会在HTTP消息头中看到另外一个新行。

(3)如果服务器的响应中仅返回两个换行符中的一个,根据实际情况,仍然能够设计出有效的攻击方法。

(4)如果发现换行符被应用程序阻止或净化,那么应该尝试以下攻击方法:

 警告 有时,由于过分依赖HTML源代码或浏览器插件提供的信息(其中并不显示响应消息头),上述问题可能会被忽略。因此,应确保使用拦截代理服务器工具读取HTTP响应消息头。

如果能够在响应中注入任意消息头和消息主体内容,那么这种行为可通过各种方式攻击应用程序的其他用户。

尝试访问

http://mdsec.net/settings/12/

http://mdsec.net/settings/31/

注入cookie

攻击者可以建立一个URL,在请求它的任何用户的浏览器中设定任意cooike。例如:

如果进行适当配置,这些cookie可以访问不同的浏览器会话。这时,通过前面利用反射型XSS漏洞时使用的相同传送机制(电子邮件、第三方Web站点等),就可以诱使目标用户访问恶意URL。

传送其他攻击

因为HTTP消息头注入允许攻击者控制整个响应主体,所以几乎任何针对其他用户的攻击都可以使用它作为传送机制,包括虚拟Web站点置换、脚本注入、任意重定向、针对ActiveX控件的攻击等。

HTTP响应分割

这是一种试图通过恶意内容“毒害”代理服务器缓存,从而攻破通过代理服务器访问应用程序的其他用户的攻击技巧。例如,如果企业网络中的所有用户通过缓存代理服务器访问某个应用程序,那么,通过在代理服务器的缓存中注入恶意内容(显示给任何请求受影响页面的用户),攻击者就可以向这些用户实施攻击。

攻击者可以按以下步骤,利用消息头注入漏洞来实施响应分割攻击:

(1)攻击者在代理服务器缓存中选择一个他希望“毒害”的应用程序页面。例如,他可能会用一个木马登录表单(用于向攻击者的服务器提交用户证书)代替/admin/处的页面。

(2)攻击者确定某个消息头注入漏洞,构造一个请求,在服务器响应中注入一个完整的HTTP主体以及另一组响应消息头和另一个响应主体。第二个响应主体中包含他的木马登录表单的HTML源代码。这样,服务器的响应看起来就像是两个连接在一起的单独HTTP响应。因此,这种技巧叫做HTTP响应分割(HTTP response splitting),因为攻击者已经把服务器的响应“分割”成两个单独的响应。例如:

(3)攻击者与代理服务器建立TCP连接,传送这个专门设计的请求,后面紧跟着访问被“毒害”的页面的请求。在HTTP协议中,以这种方式连接请求是合法的。

(4)代理服务器与应用程序建立TCP连接,送出这两个以相同方式连接的请求。

(5)应用程序用攻击者注入的HTTP内容响应第一个请求,它看起来就像是两个单独的HTTP响应。

(6)代理服务器收到这两个看似单独的响应,并认为其中第二个响应与攻击者的第二个请求相对应,该请求指向URL:http://mdsec.net/admin/。代理服务器把第二个响应作为这个URL的内容保存在缓存中。(如果代理服务器已经在缓存中保存有该页面的副本,那么攻击者就可以在他的第二个请求中插入一个适当的If-Modified-Since消息头,并在注入的响应中插入一个Last-Modified消息头,使得代理服务器重新请求这个URL,用新的内容更新它的缓存。)

(7)应用程序发布它对攻击者的第二个请求的响应,其中包含URL http://mdsec.net/admin/的真实内容。代理服务器并不认为它是对它发布的请求的响应,因而抛弃这个响应。

(8)一名用户通过代理服务器访问http://mdsec.net/admin/,并收到这个URL保存在代理服务器缓存中的内容。这个内容实际上是攻击者的木马登录表单,因此用户的证书被攻破。

实施这种攻击的步骤如图13-3所示。

图13-3 用于毒害代理服务器缓存的HTTP响应分割攻击涉及的步骤

防止消息头注入漏洞

要防止HTTP消息头注入漏洞,最有效方法是杜绝将用户控制的输入插入到应用程序返回的HTTP消息头中。如我们在介绍任意重定向漏洞时所述,通常可以用一些较为安全的方法代替这种行为。

如果不可避免地要在HTTP消息头中插入用户控制的数据,那么应用程序应采取以下双重深层防御方法防止漏洞产生。

输入确认。应用程序应根据情形,对插入的数据进行尽可能严格的确认。例如,如果根据用户输入设定一个cookie值,那么应将这个值限制为仅包含字母字符,最大长度为6字节。

输出确认。应对插入到消息头中的所有数据进行过滤,检测可能的恶意字符。实际上,任何ASCII码小于0x20的字符都应被视为可疑的恶意字符,应用程序应拒绝包含这些字符的请求。

只有应用程序在其SSL终止符后未使用缓存反向代理服务器,它才能通过对所有应用程序内容使用HTTPS,防止攻击者利用任何残留的消息头注入漏洞“毒害”代理服务器缓存。

cookie注入

在cookie攻击中,攻击者利用应用程序功能或浏览器行为的某种特性,在受害用户的浏览器中设置cookie,或修改该cookie。

攻击者可以通过各种方式实施cookie注入攻击。

某些应用程序的功能在请求参数中使用一个名称和值,并在响应的cookie中设置该名称和值。保存用户首选项大多属于此类功能。

如前所述,如果存在HTTP消息头注入漏洞,就可以利用此漏洞注入任意Set-Cookie消息头。

可以利用相关域中的XSS漏洞在目标域上设置一个cookie。目标域的任何子域,以及目标域的父域及其子域,都可以通过这种方式加以利用。

可以利用主动中间人攻击(例如,针对公共无线网络中的用户)在任意域上设置cookie,即使目标应用程序仅使用HTTPS并且将其cookie标记为安全。我们将在本章后面部分详细介绍这种攻击。

如果攻击者可以设置任意cookie,他就可以利用该cookie以各种方式攻击目标用户:

在某些应用程序中,设置一个特殊的cookie可能会破坏应用程序的逻辑,给用户造成不利影响(例如,UseHttps=false)。

由于cookie通常仅由应用程序本身设置,因此它们会受客户端代码信任。该代码可能会以各种危险的方式(对攻击者可控制的数据而言)处理cookie值,导致基于DOM的XSS或JavaScript注入。

除将反CSRF令牌与用户会话关联外,一些应用程序还在cookie和请求参数中放置该令牌,然后对它们的值进行比较,以防止CSRF攻击。如果攻击者可以控制cookie和参数值,就能够避开这种防御。

如本章前面部分所述,攻击者可以利用某个永久性XSS漏洞,通过针对登录功能的CSRF攻击使用户登录攻击者的账户,并因此访问XSS有效载荷。如果登录页面能够有效防范CSRF,这种攻击将无法奏效。但是,如果攻击者能够在用户的浏览器中设置任意cookie,他就可以直接向用户传送自己的会话令牌,从而成功实施攻击,而不必实施针对登录功能的CSRF攻击。

设置任意cookie可以对会话固定漏洞加以利用(将在下一节介绍)。

会话固定

如果应用程序在用户首次访问它时为每一名用户建立一个匿名会话,这时往往就会出现会话固定漏洞。如果应用程序包含登录功能,这个匿名会话将在用户登录前创建,然后,一旦用户登录,该会话即升级为通过验证的会话。最初,会话令牌并未被赋予任何访问权限,但当用户通过验证后,这个令牌也具有了该用户的访问权限。

在标准的会话劫持攻击中,攻击者必须使用某种方法截获一名应用程序用户的会话令牌。另一方面,在会话固定攻击中,攻击者首先从应用程序中直接获得一个匿名令牌,然后使用某种方法将这个令牌“固定”在受害者的浏览器中。用户登录后,攻击者就可以使用该令牌劫持这名用户的会话。

成功实施这种攻击所需的步骤如图13-4所示。

图13-4 实施会话固定攻击所需的步骤

当然,在这个攻击中,最关键的阶段应该是攻击者向受害者传送他获得的会话令牌,并令受害者的浏览器使用这个令牌。实现这一目标的方法因传送会话令牌所采用的机制而异。

如果使用HTTP cookie,攻击者可以尝试使用上一节介绍的某种cookie注入技巧。

如果在URL参数中传送会话令牌,则攻击者只需向受害者传递应用程序向其发布的同一URL:

一些应用程序服务器接受在URL中使用它们以分号分隔的会话令牌。一些应用程序默认这样做,而其他应用程序则直接以这种方式使用令牌,即使这并非服务器的默认行为:

如果应用程序使用HTML表单中的隐藏字段来传送会话令牌,攻击者可以利用CSRF攻击在用户的浏览器中插入他的令牌。

并不提供登录机制的应用程序中也可能存在会话固定漏洞。例如,某应用程序可能允许匿名用户浏览产品目录、在购物篮中添加商品、通过提交个人数据与支付细节进行结算,然后在“确认订单”页面上审核这些信息。在这种情况下,攻击者就可以将一个匿名会话令牌固定到受害者的浏览器中,等待该用户提交订单并输入敏感信息,然后使用该令牌访问“确认订单”页面,截获该用户的信息。

一些Web应用程序与Web服务器接受用户提交的任意令牌,即使这些令牌并不是由服务器在此前发布的。如果收到一个不被认可的令牌,服务器会直接为这个令牌建立一个新会话,并把它当做服务器生成的新令牌处理。过去,Microsoft IIS与Allaire ColdFusion服务器都存在这种缺陷。

如果一个应用程序或服务器以这种方式运作,它就非常容易受到会话固定攻击,因为攻击者根本不必采取任何措施确保固定在目标用户的浏览器中的令牌当前有效。攻击者只需选择任意一个令牌,将其尽可能广地进行分发(例如,通过电子邮件向个体用户、邮件列表等发送一个包含该令牌的URL),然后定期访问应用程序中的某个受保护页面(如“用户资料”),检查受害者何时使用这个令牌登录。即使目标用户几个月都没有访问这个URL,但蓄意破坏的攻击者仍然有可能劫持该用户的会话。

查找并利用会话固定漏洞

如果应用程序支持身份验证,则应该检查它如何处理与登录有关的会话令牌。在下面两种情况下,应用程序可能易于受到攻击。

应用程序向每名未通过验证的用户发布一个匿名会话令牌。在用户登录后,它并不发布新令牌,相反,他们现有的会话被升级为通过验证的会话。使用应用程序服务器的默认会话处理机制的应用程序常常采用这种行为。

应用程序并不向匿名用户发布令牌;只有用户成功登录后,应用程序才向该用户发布令牌。但是,如果用户使用通过验证的令牌访问登录功能,并使用不同的证书登录,则应用程序并不发布新令牌;相反,与之前通过验证的会话关联的用户身份将转换为第二名用户的身份。

在这两种情况下,攻击者都能获得有效令牌(通过请求登录页面或用他自己的证书登录),并将其传送给目标用户。当该用户使用这个令牌登录时,攻击者就能劫持这名用户的会话。

渗透测试步骤

(1)通过任何可行的办法获得一个有效令牌。

(2)访问登录表单并使用这个令牌登录。

(3)如果登录成功,而且应用程序并不发布新令牌,则表示它易于受到会话固定攻击。

如果一个应用程序并不支持验证,但允许用户提交并审查敏感信息,那么应该确认用户在提交敏感信息前后是否使用相同的会话令牌。如果令牌没有发生变化,则攻击者就可以获得令牌,并将其传送给目标用户。用户提交敏感信息后,攻击者就可以使用该令牌查看这名用户的信息。

渗透测试步骤

(1)以完全匿名的用户身份获得一个会话令牌,然后完成提交敏感数据的过程,接下来继续浏览,直到任何显示敏感数据的页面。

(2)如果最初获得的同一个令牌现在可用于获取敏感数据,应用程序就易于受到会话固定攻击。

(3)如果已经发现任何会话固定漏洞,则应确定应用程序是否接受它之前并未发布的任何令牌。如果接受,那么在很长一段时间内攻击者都可以非常轻松地利用这个漏洞。

防止会话固定漏洞

任何时候,只要一名用户与应用程序的交互状态由匿名转变为确认,应用程序就应该发布新的会话令牌。这不仅适用于用户成功登录的情况,而且适用于匿名用户首次提交个人或其他敏感信息时。

为进一步防止会话固定攻击,一些安全性至关重要的应用程序采用每页面令牌来强化主会话令牌,以提供深层防御。这种技巧可以击退大多数会话劫持攻击,请参阅第7章了解详情。

应用程序不得接受它认为不是自己发布的任意会话令牌。应立即在浏览器中取消该令牌,并将用户返回到应用程序的起始页面。

开放式重定向漏洞

如果应用程序提取用户可控制的输入,并使用这个数据执行重定向,指示用户的浏览器访问不同于用户所请求的URL,这时就会导致开放重定向漏洞。相比于可执行大量恶意操作的跨站点脚本漏洞,攻击者通常对这些漏洞不太感兴趣。攻击者主要利用开放式重定向漏洞实施钓鱼攻击,诱使受害者访问欺骗性Web站点并输入敏感信息。对潜在的受害者而言,重定向漏洞提高了攻击者的可信度,因为它允许攻击者创建一个指向他所针对的可信Web站点的URL,因此更具有说服力,但任何访问这个URL的用户将被悄悄重定向到攻击者控制的Web站点。

也就是说,现实世界中的大多数钓鱼攻击都使用其他技巧来获得不受所针对的应用程序控制的可信度。这类技巧包括注册类似的域名、使用官方形式的子域,以及在HTML电子邮件中在定位文本与链接的目标URL之间造成不匹配。研究表明,多数用户都无法或不太可能基于URL结构作出安全决策。因此,典型的开放式重定向漏洞对钓鱼攻击者而言并无多大价值。

近年来,开放式重定向漏洞一直被攻击者以相对良性的方式加以利用,用于实施“瑞克摇摆”(rickrolling)攻击。在这种攻击中,受害者在不知情的情况下被重定向到英国流行乐传奇人物里克·阿斯特利的视频,如图13-5所示。

图13-5 “瑞克摇摆”攻击的结果

查找并利用开放式重定向漏洞

查找重定向漏洞的第一步是确定应用程序中的所有重定向。应用程序可以通过几种方式使用户的浏览器重定向到不同的URL。

HTTP重定向使用一条状态码为3xx的消息与一个指定重定向目标的Location消息头。例如:

HTTP Refresh消息头可在固定时间间隔后使用任意URL重新加载某个页面,该间隔可以为零(0),也就是能立即触发重定向。例如:

HTML<meta>标签可复制任何HTTP消息头的行为,因此可用于建立重定向。例如:

JavaScript中的各种API可用于将浏览器重定向到任意URL。例如:

以上这些方法可用于指定绝对或相对URL。

渗透测试步骤

(1)确定应用程序中使用重定向的所有位置。

(2)要确定所有重定向,一个有效的方法,是使用拦截代理服务器浏览应用程序,并监控访问页面的请求(与其他资源,如图像、样式表、脚本文件等不同)。

(3)如果一个导航操作导致了几个连续请求,应分析它使用什么方法进行重定向。

绝大多数的重定向都不受用户控制。例如,在典型的登录机制中,向/login.jsp提交有效的证书将返回一个指向/myhome.jsp的HTTP重定向。这时,重定向的目标始终相同,因此不会受到任何重定向漏洞的影响。

但是,在有些情况下,用户提交的数据以某种方式用于设置重定向的目标。一个常见的例子是,应用程序强制使会话已经终止的用户返回登录页面,然后在用户重新成功通过验证后将他们重定向到最初的URL。如果遇到这种行为,就表明应用程序可能易于受到重定向攻击,因此,应当对这种行为进行深入分析,以确定它是否可被攻击者利用。

渗透测试步骤

(1)如果用户数据在包含绝对URL的重定向中进行处理,则应修改URL中的域名,并测试应用程序是否将用户重定向到另一个域。

(2)如果所处理的用户数据包含相对URL,应将此URL修改为指向另一个域的绝对URL,并测试应用程序是否将用户重定向到这个域。

(3)无论是哪一种情况,如果见到以下行为,那么应用程序肯定容易受到重定向攻击:

尝试访问

http://mdsec.net/updates/8/

http://mdsec.net/updates/14/

http://mdsec.net/updates/18/

http://mdsec.net/updates/23/

http://mdsec.net/updates/48/

 注解 如果应用程序使用可由用户控制的数据指定框架的目标URL,这时会发生一种与重定向并非完全相同但相似现象。如果可以构建一个URL,将外部URL的内容加载到子框架中,就可以相当隐秘地实施重定向攻击。这时,可以使用其他内容仅替换应用程序的部分界面,并使浏览器地址栏中的域保持不变。

以下情况很常见:用户控制的数据用于设置重定向的目标,但却被应用程序以某种方式过滤或净化掉,以阻止重定向攻击。这时并没有办法确定应用程序是否易于受到攻击;因此,接下来应该探查应用程序采用的防御机制,确定是否能够避开它们以执行任意重定向。通常会遇到以下两种防御:尝试阻止绝对URL、附加一个特殊的绝对URL前缀。

阻止绝对URL

应用程序可能会检查用户提交的字符串是否以http://开头,如果是,就阻止该请求。这时,使用下面的技巧可以成功创建一个指向外部Web站点的重定向(请注意第三行开头的空格):

另外,应用程序可能会删除http://及任何指定的外部域,尝试净化绝对URL。这时,使用上面的技巧可以成功避开净化;同时还应测试下面的攻击是否可行:

有时,应用程序可能会检验用户提交的字符串是否以指向它自己的域名的绝对URL开头,或是否包含这个URL。这时,下面的攻击可能有效:

尝试访问

http://mdsec.net/updates/52/

http://mdsec.net/updates/57/

http://mdsec.net/updates/59/

http://mdsec.net/updates/66/

http://mdsec.net/updates/69/

附加绝对前缀

应用程序可能会在用户提交的字符串前附加一个绝对URL前缀,从而建立重定向的目标。

这时,我们无法确定应用程序是否易于受到攻击。如果所使用的前缀由http://与应用程序的域名组成,但在域名后没有斜线字符,那么它就易于受到攻击。例如,下面的URL

http://mdsec.net/updates/72/?redir=.mdattacker.net

会重定向到

http://mdsec.net.mdattacker.net

它由攻击者控制,前提是攻击者控制着域mdattacker.net的DNS记录。

然而,如果绝对URL前缀确实包含斜线字符(/)或服务器上的某个子目录,那么应用程序可能不会受到针对外部域的重定向攻击。这时,攻击者最多只能构建一个URL,将用户重定向到同一应用程序中的另一个URL。通常,这种攻击并不能取得任何成果,因为如果攻击者能够诱使用户访问应用程序中的一个URL,那么他大概也只能向他们直接传送另一个URL。

尝试访问

http://mdsec.net/updates/72/

如果使用从DOM中查询数据的客户端JavaScript实现重定向,则负责执行重定向与相关确认的所有代码通常将在客户端上可见。因此,应仔细检查这些代码,确定它如何将用户控制的数据合并到URL中,以及它是否执行了任何确认,如果是,是否有什么办法可以避开确认。注意,和基于DOM的XSS漏洞一样,在将脚本返回浏览器之前,服务器可能对其执行了其他确认。下面的JavaScript API可用于执行重定向:

document.location

document.URL

document.open()

window.location.href

window.navigate()

window.open()

尝试访问

http://mdsec.net/updates/76/

http://mdsec.net/updates/79/

http://mdsec.net/updates/82/

http://mdsec.net/updates/91/

http://mdsec.net/updates/92/

http://mdsec.net/updates/95/

防止开放式重定向漏洞

绝不将用户提交的数据合并到重定向目标中,是避免开放式重定向漏洞的最有效方法。开发者这样做出于各种原因,但通常我们都可以找到替代办法。例如,用户界面中常常包含一组链接,每个链接指向一个重定向页面,并以目标URL为参数。这时,可能的替代方法如下。

从应用程序中删除重定向页面,用直接指向相关目标URL的链接替代指向重定向页面的链接。

建立一个包含所有有效重定向URL的列表。不以参数的形式向重定向页面传送目标URL,而是传送这个列表的索引。重定向页面应在它的列表中查询这个索引,并返回一个指向相关URL的重定向。

如果重定向页面不可避免地要收到用户提交的输入并将它合并到重定向目标中,应使用以下措施降低重定向攻击的风险。

应用程序应在所有重定向中使用相对URL,重定向页面应严格确认它收到的URL为相对URL。它应当确保:用户提交的URL或者以其后接一个字母的斜线字符开头,或者以一个字母开头,并且在第一个斜线前没有冒号。应拒绝,而不是净化任何其他输入。

应用程序应该在所有重定向中使用相对于Web根目录的URL,在发布重定向之前,重定向页面应在所有用户提交的URL前附加http://yourdomainname.com。如果用户提交的URL并不以斜线字符开头,应在它的前面附加http://yourdomainname.com/。

应用程序应对所有重定向使用绝对URL,重定向页面在发布重定向之前,应确认用户提交的URL以http://yourdomainname.com/开头。此外,应拒绝任何其他输入。

和基于DOM的XSS漏洞一样,建议应用程序不要根据DOM数据通过客户端脚本执行重定向,因为这些数据不在服务器的直接控制范围内。

客户端SQL注入

HTML5支持客户端SQL数据库,应用程序可使用该数据库在客户端存储数据。这些数据库使用JavaScript访问,如以下示例所示:

应用程序可以使用此功能将常用数据存储到客户端,然后在需要时将这些数据快速检索到用户界面中。它还允许应用程序以“离线模式”运行,在这种模式下,所有由应用程序处理的数据将驻留在客户端,用户操作也存储在客户端,以便在网络连接可用时与服务器进行同步。

我们在第9章中介绍了如何在服务器端SQL数据库中实施SQL注入攻击,在这种攻击中,攻击者将受其控制的数据以危险的方式插入SQL查询中。实际上,在客户端也可能发生此类攻击。下面列出了一些可能受到这种攻击的应用程序。

社交网络应用程序,这类应用程序将用户的联系人信息存储在本地数据库中,包括联系人姓名和状态更新。

新闻应用程序,这类应用程序将文章和用户评论存储在本地数据库中,以便于离线查看。

Web邮件应用程序,这类应用程序将电子邮件存储在本地数据库中,在离线模式下运行时,则存储待发邮件以便于稍后发送。

在这些情况下,攻击者可以将专门设计的输入包含在受其控制的一组数据中(应用程序在本地存储这些数据),从而实施客户端SQL注入攻击。例如,通过发送一封电子邮件,并在主题行中包含SQL注入攻击代码(如果这些数据嵌入在客户端SQL查询中),就可以攻破收件人用户的本地数据库。如果应用程序以危险的方式使用本地数据库,就可能导致严重的攻击。仅仅使用SQL注入,攻击者就可以从数据库中检索用户已收到的其他邮件的内容,将这些数据复制到发送给攻击者的待发电子邮件,然后将该电子邮件添加到已排队的待发邮件表中。

通常存储在本地数据库中的数据类型可能为SQL元字符,如单引号。因此,在正常使用测试期间即可确定许多SQL注入漏洞,从而实施针对SQL注入攻击的防御机制。和服务器端注入一样,这些防御机制也可以通过各种方法规避,从而实施成功的攻击。

客户端HTTP参数污染

在第9章中,我们介绍了如何在某些情况下使用HTTP参数污染攻击来破坏服务器端应用程序逻辑。有时,这些攻击也可以在客户端实施。

以一个使用以下URL加载收件箱的Web邮件应用程序为例:

在收件箱中,每封邮件旁显示了几个链接,可用于执行删除、转发和回复等操作。例如,回复第12封邮件的链接如下:

这些链接中的一些参数将被复制到收件箱URL中。即使应用程序能够有效防范XSS攻击,但攻击者仍然可以构建一个URL,使用在这些链接中回显的其他值来显示收件箱。例如,攻击者可以提供以下参数:

此参数包含一个URL编码的&字符,应用程序服务器将自动对该字符进行解码。传递给应用程序的start参数的值为:

如果应用程序接受这个无效值并仍然显示收件箱,同时不加修改地回显该值,用于回复第12封邮件的链接将变为:

现在,此链接包含两个操作参数——一个指定delete,一个指定reply。和标准的HTTP参数污染一样,在用户单击“回复”链接时,应用程序的行为取决于它如何处理重复的参数。许多时候,应用程序使用第一个值,因此,用户将在不知情的情况下删除任何其尝试回复的邮件。

请注意,在本示例中,用于执行操作的链接包含一个rnd参数,它实际上是一个反CSRF令牌,以防止攻击者通过标准的CSRF攻击轻松诱发这些操作。由于客户端HPP攻击会注入由应用程序构建的现有链接,因此该反CSRF令牌将以正常方式进行处理,因而无法阻止攻击。

在现实世界的大多数Web邮件应用程序中,很可能存在更多可供利用的操作,包括删除所有邮件、转发单个邮件,以及创建通用的邮件转发规则。根据这些操作的实施方式,攻击者就可以在链接中注入若干所需的参数,甚至利用本站重定向功能,以诱使用户执行正常情况下受反CSRF防御保护的复杂操作。此外,攻击者还可以使用多级URL编码,在一个URL中注入几个攻击。在这种情况下,当用户尝试阅读邮件时,将执行一个操作,而当用户尝试返回收件箱时,则会执行另一个操作。

本地隐私攻击

许多用户从共享的环境中访问Web应用程序,这时,攻击者可直接访问用户访问的同一台计算机。在这种情况下,如果应用程序存在漏洞,它们的用户就易于受到一系列攻击。这类攻击主要针对以下领域。

 注解 应用程序可能会采用各种机制在用户的计算机上存储敏感信息。许多时候,为测试应用程序是否采用了某种存储机制,最好是使用完全“干净”的浏览器,以便于接受测试的应用程序存储的数据不会丢失在已存储的现有数据中。要做到这一点,最理想的方法,是使用包含全新安装的操作系统和任何浏览器的虚拟机。

此外,在某些操作系统上,在使用文件系统内置的管理器时,包含本地存储数据的文件和文件夹在默认情况下可能处于隐藏状态。为确保标识所有相关数据,应将计算机配置为显示所有隐藏文件和操作系统文件。

持久性cookie

一些应用程序将敏感数据保存在持久性cookie中,大多数浏览器将该cookie存放在本地文件系统上。

渗透测试步骤

(1)检查应用程序解析过程中(请参阅第4章了解相关内容)确定的所有cookie。如果发现有任何Set-cookie指令包含将来日期的expires属性,那么浏览器会将相关cookie保存到这个日期。例如:

(2)如果某个持久性cookie中包含任何敏感数据,本地攻击者就能够截获这些数据。即使持久性cookie中包含的是加密值,但如果这个值发挥着非常关键的作用(如不需用户输入证书即可重新验证其身份),则截获这个值的攻击者根本不用破译它的内容,就可以将它重新提交给应用程序(请参阅第6章了解相关内容)。

尝试访问

http://mdsec.net/auth/227/

缓存Web内容

大多数浏览器将非SSL Web内容保存在缓存中,除非Web站点特别指示不要这样做。缓存数据一般保存在本地文件系统中。

渗透测试步骤

(1)对于任何通过HTTP访问和包含敏感数据的应用程序页面,应检查服务器响应的内容,确定所有缓存指令。

(2)下面的指令可阻止浏览器缓存某个页面。注意,这些指令可以在HTTP响应消息头或HTML元标签中指定。

(3)如果未发现这些指令,相关页面很可能会被一个或几个浏览器缓存。注意,每个页面都会执行缓存指令,因此必须检查每一个基于HTTP的敏感页面。

(4)为确保缓存敏感信息,应使用一个默认安装的标准浏览器,如Internet Explorer或Firefox。在浏览器的配置中,完全清除它的缓存和全部cookie,然后访问包含敏感数据的应用程序页面。检查出现在缓存中的文件,看其中是否包含敏感数据。如果有大量文件生成,可以从页面的源代码中提取一个特殊的字符串,并在缓存中搜索该字符串。

常用浏览器的默认缓存位置如下。

Internet Explorer——C:\Documents and Settings\用户名\Local Settings\Temporary Internet Files\Content.IE5的子目录。

注意,在Windows Explorer中,要查看这个文件夹,必须输入准确的路径并显示隐藏的文件夹,或通过命令行浏览至这个文件夹。

Firefox(Windows中)——C:\Documents and Settings\用户名\Local Settings\Application Data\Mozilla\Firefox\Profiles\配置文件名\Cache。

Firefox(Linux中)——~/.mozilla/firefox/配置文件名/Cache。

尝试访问

http://mdsec.net/auth/249/

浏览历史记录

许多浏览器都保存有浏览历史记录,其中可能包含通过URL参数传送的任何敏感数据。

渗透测试步骤

(1)确定应用程序中通过URL参数传送敏感数据的任何情况。

(2)如果存在这样的情况,应检查浏览器的历史记录,证实这些数据已经保存在那里。

尝试访问

http://mdsec.net/auth/90/

自动完成

许多浏览器对基于文本的输入字段执行一项可由用户配置的自动完成功能,这些字段可保存诸如信用卡号码、用户名与密码之类的敏感数据。Internet Explorer与Firefox分别将自动完成数据保存在注册表与文件系统中。

如前所述,除可被本地攻击者访问外,在某些情况下,保存在自动完成缓存中的数据也可通过XSS攻击获取。

渗透测试步骤

(1)检查可从其文本字段中获取敏感数据的任何表单的HTML源代码。

(2)如果没有在表单标签或输入字段的标签中设置autocomplete=off属性,输入的数据将保存在已启用自动完成的浏览器中。

尝试访问

http://mdsec.net/auth/260/

Flash本地共享对象

Flash浏览器扩展实施它自己的本地存储机制,这种机制称为本地共享对象(LSO),也称为Flash cookie。与其他多数机制不同,存储在LSO中的数据可在不同的浏览器之间共享,只是这些浏览器安装了Flash扩展。

渗透测试步骤

(1)有一些用于Firefox的插件(如BetterPrivacy)可浏览由个体应用程序创建的LSO数据。

(2)可以直接查看磁盘上的原始LSO数据的内容。这些数据的位置因浏览器和操作系统而异。例如,对于最新版本的Internet Explorer,LSO数据位于以下文件夹中:

C:\Users\{用户名}\AppData\Roaming\Macromedia\Flash Player\#SharedObjects\{随机}\{域名}\{存储名}\{SWF文件名}

尝试访问

http://mdsec.net/auth/245/

Silverlight独立存储

Silverlight浏览器扩展实施自己的本地存储机制,这种机制称为Silverlight独立存储。

渗透测试步骤

可以直接查看磁盘上的原始Silverlight独立存储数据的内容。对于最新版本的Internet Explorer,这些数据存储在以下位置的一系列多层嵌套、随机命名的文件夹中:

C:\Users\{用户名}\AppData\LocalLow\Microsoft\Silverlight\

尝试访问

http://mdsec.net/auth/239/

Internet Explorer userData

Internet Explorer实施自己的本地存储机制,这种机制称为userData。

渗透测试步骤

可以直接查看存储磁盘上IE的userData中的原始数据的内容。对于最新版本的Internet Explorer,这些数据位于以下文件夹中:

C:\Users\user\AppData\Roaming\Microsoft\Internet Explorer\UserData\Low\{随机}

尝试访问

http://mdsec.net/auth/232/

HTML5本地存储机制

HTML5正引入一系列新的本地存储机制,它们包括:

会话存储;

本地存储;

数据库存储。

这些机制的规范和用法仍在开发阶段。并非所有浏览器都实施了所有这些机制,测试其用法及查看存储的任何数据的方式因浏览器而异。

防止本地隐私攻击

即使敏感数据经过加密,应用程序也应避免将其保存在持久性cookie中。因为截获这些数据的攻击者可重新将其提交给应用程序。

应用程序应使用适当的缓存指令防止浏览器保存敏感数据。在ASP应用程序中,下面的指示将在服务器中包含必要的指令:

在Java应用程序中,可使用以下命令达到相同的目的:

应用程序决不能使用URL传送敏感数据,因为有许多位置都可能记录这些URL。应用程序应使用通过POST方法提交的HTML表单传送所有这些数据。

任何时候,如果用户在文本输入字段中填入敏感数据,都应在表单或字段标签中指定autocomplete=off属性。

其他客户端存储机制,如HTML5即将引入的新功能,将为应用程序提供实施重要功能的机会,包括更快速地访问特定的用户数据,并能够在网络访问不可用时继续工作。如果需要在本地存储敏感数据,最好是对这些数据进行加密,以防止攻击者直接访问它们。此外,应告知用户存储在本地的数据的本质,向他们警告攻击者本地访问这些数据的风险,以便其在需要时禁用此功能。

攻击ActiveX控件

如我们在第5章中所述,应用程序可以使用各种厚客户端技术将它的一些处理操作分配给客户端完成。ActiveX控件对于针对其他用户的攻击者特别有用。如果应用程序安装了一个可从自己的页面调用的控件,该控件必须注册为“脚本执行安全”。这样,用户访问的任何其他Web站点都能够使用这个控件。

通常,浏览器并不接受Web站点要求它们安装的任何ActiveX控件。默认情况下,当Web站点试图安装某个控件时,浏览器会显示一个安全警报,要求得到用户许可。是否信任发布该控件的Web站点以及是否允许安装该控件,将由用户自行决定。但是,如果用户安装该控件,并且其中包含任何漏洞,则用户访问的任何恶意Web站点都可以利用这些漏洞。

ActiveX控件中常见的对攻击者有用的漏洞主要分为两类。

由于ActiveX控件通常以C/C++之类的本地语言编写,它们之中很可能存在一些典型的软件漏洞,如缓冲区溢出、整数漏洞以及格式字符串漏洞(请参阅第16章了解详情)。人们已经在流行Web应用程序(如在线赌博站点)发布的ActiveX控件中发现了大量这些类型的漏洞。通常,攻击者可以利用这些漏洞在受害用户的计算机上执行任意代码。

许多ActiveX控件中包含一些本质上存在风险、易被滥用的方法。

LaunchExe(BSTR ExeName)

SaveFile(BSTR FileName, BSTR Url)

LoadLibrary(BSTR LibraryPath)

ExecuteCommand(BSTR Command)

开发者往往会执行这些方法来提高控件的灵活性,以便于将来扩展控件的功能,而不必部署全新的控件。但是,一旦安装了这些控件,任何恶意站点当然也可以通过同样的方式对其进行“扩展”,从而执行针对用户的恶意操作。

查找ActiveX漏洞

当应用程序安装ActiveX控件时,除浏览器会显示一个要求获得安装控件许可的警报外,还应该可以在某个应用程序页面的HTML源代码中看到类似于下面的代码:

这段代码告诉浏览器用指定的名称和classid示例化ActiveX控件,并从指定的URL下载该控件。如果浏览器中已经安装有控件,就不需要使用codebase参数,浏览器会根据控件的唯一classid,从本地计算机中找到该控件。

如果用户允许安装这个控件,浏览器会将其注册为“脚本执行安全”。这意味着将来任何Web站点都可以将其示例化,并调用它的方法。可以通过检查注册表项HKEY_CLASSES_ROOT\CLSID\从上面的HTML中提取的控件classid\Implemented Categories确认这一点。如果其中存在子注册表项7DD95801-9882-11CF-9FA9-00AA006C42C4,则表示该控件已经注册为“脚本执行安全”,如图13-6所示。

图13-6 已注册为“脚本执行安全”的控件

浏览器示例化ActiveX控件后,就可以通过以下脚本调用它的方法:

渗透测试步骤

一种探查ActiveX漏洞的简单方法是,修改调用该控件的HTML代码,向其提交自己的参数,然后监控执行结果。

(1)使用第16章描述的相同攻击有效载荷可探查缓冲区溢出之类的漏洞。如果以不受控制的方式触发这种漏洞,很可能会导致负责该控件执行的浏览器进程崩溃。

(2)本质上存在风险的方法通过其名称即可确定,如LaunchExe。在其他情况下,控件名称可能无害或含义模糊,但有时,一些有用的数据,如文件名、URL或系统命令,明显被用作控件的参数。应该尝试将这些参数修改为任意值,确定控件是否按预计的方式处理输入。

我们常常发现,应用程序并没有调用控件的所有方法。例如,一些方法主要用于测试目的、一些已被取代但尚未删除、一些可能是为了方便将来使用或用于自我更新目的。为了对控件进行综合测试,有必要枚举出它通过这些方法暴露的各种受攻击面,并对这些受攻击面进行彻底测试。

有各种工具可用于枚举和测试ActiveX控件方法。iDefense开发的COMRaider就是一个有用的工具,它能够显示一个控件的全部方法,并对每个方法执行基本的模糊测试,如图13-7所示。

图13-7 COMRaider显示某个ActiveX控件的方法

防止ActiveX漏洞

保护本地编译软件组件的安全,防止其受到攻击,是一个广泛而复杂的话题,这不属于本书的讨论范围。基本上,ActiveX控件的设计者与开发者必须确保恶意Web站点无法调用该控件实施的方法,用以对安装这个控件的用户执行恶意操作。以下是一些应该注意的问题。

应对控件进行以安全为中心的源代码审查与渗透测试,以确定缓冲区溢出之类的漏洞。

控件不得暴露任何使用用户可控制的输入调用外部文件系统或操作系统、本质上存在风险的方法。只需稍微做出一些努力,就可以找到更安全的替代方法。例如,如果有必要启动外部进程,则应编辑一个列表,列出所有可合法、安全启动的外部进程;然后创建单独的方法调用每个进程,或者使用一个方法提取这个列表中的索引号。

为进行深层防御,一些ActiveX控件对发布HTML页面(这些控件即从中调用)的域名进行确认。Microsoft的“SiteLock活动模板库”模板允许开发者将ActiveX控件仅限于特定的域名列表。

一些控件甚至更进一步,要求提交给它们的所有参数必须使用加密签名。如果提交的签名无效,控件不会执行请求的操作。还要注意,如果允许调用这些控件的Web站点存在任何XSS漏洞,那么攻击者就有可能突破这类防御。

攻击浏览器

迄今为止,我们在这一章和上一章介绍的攻击主要与利用应用程序的某种行为特征攻破应用程序用户有关。虽然某些攻击技巧需要利用特定浏览器的怪癖,但跨站点脚本、跨站点请求仿造以及JavaScript劫持之类的攻击全都源于特定Web应用程序中的漏洞。

另一类针对用户的攻击并不依赖于特定应用程序的行为。相反,这些攻击主要利用浏览器的行为特征,或者核心Web技术本身的设计缺陷。这些攻击可能由任何恶意网站或任何本身已被攻破的“良性”站点实施。介绍Web应用程序攻击的书籍通常都没有涉及这类攻击。但是,我们有必要简单了解这些攻击,部分是因为它们与利用应用程序特定功能的攻击的某些特点相同。通过展示在不存在任何应用程序特定漏洞的情况下,攻击者可以达到什么目的,这些攻击还为我们了解各种应用程序行为的影响提供了相关信息。

以下各部分的介绍相对比较简单。有关这方面的主题,可以写成一本书。拥有大量空余时间的准作者可以向Wiley提交出版The Browser Hacker’s Handbook的提议。

记录键击

JavaScript可在浏览器窗口处于激活状态时监控用户按下的所有键,包括密码、私人消息和其他个人信息。下面的概念验证脚本将截获Internet Explorer中的所有键击,并在浏览器的状态栏中显示全部内容:

只有当运行上述代码的框架处于激活状态时,这些攻击才能捕获键击。但是,如果在自身页面的框架内嵌入了第三方小组件或广告小程序,某些应用程序可能易于受到键击记录攻击。在所谓的“逆向键击劫持”攻击中,在子框架中运行的恶意代码能够夺取顶层窗口的控制权,因为同源策略并不能阻止这种操作。恶意代码可以通过处理onkeydown事件来捕获键击,并且能够将单独的onkeypress事件传递给顶层窗口。这样,输入的文本仍然会在顶层窗口中正常显示。通过在暂停输入时暂时放弃激活状态,恶意代码甚至可以在顶层窗口内的正常位置保留显示闪烁的光标。

窃取浏览器历史记录与搜索查询

JavaScript可用于实施蛮力攻击,查明用户最近访问的第三方站点以及他们在常用搜索引擎上执行的查询。在介绍蛮力攻击(实施此攻击的目的,是为了确定可在其他域上使用的有效反CSRF令牌)时,我们已经讨论了这种技巧。攻击者可以动态创建常用Web站点以及搜索查询的超链接,并使用getComputedStyle API检查这些链接是否以彩色标记为“已被访问”,从而完成这项任务。而且,攻击者可以迅速检查大量可能的目标,而不会给用户造成很大的影响。

枚举当前使用的应用程序

JavaScript可用于确定用户当前是否登录到第三方Web应用程序。大多数应用程序都包含只有登录用户可查看的页面,如“用户资料”页面。如果未通过验证的用户请求这个页面,将会收到错误消息,或者一个转向登录页面的重定向链接。

通过对受保护的页面执行跨域脚本包含,并运行定制的错误处理程序来处理脚本错误,种行为可确定用户是否已经登录第三方Web应用程序:

当然,无论受保护的页面处于什么状态,由于它仅包含HTML内容,因此这时将会出现一个JavaScript错误。重要的是,根据实际返回的HTML文档,该错误将包含不同的行号与错误类型。接下来,攻击者可以运行错误处理程序(在fingerprint函数中),检查用户登录时产生的行号与错误类型。尽管应用程序实施了同源策略,但攻击者的脚本仍然能够推断出受保护页面的状态。

确定用户当前登录哪些常用的第三方应用程序后,攻击者就可以执行针对性极强的跨站点请求伪造攻击,以被攻破的用户身份在应用程序中执行任意操作。

端口扫描

JavaScript可对用户本地网络或其他可访问的网络上的主机进行端口扫描,以确定可被利用的服务。如果用户受到企业或家庭防火墙的保护,攻击者将能够到达无法通过公共互联网访问的服务。如果攻击者扫描客户端计算机的回环接口,就能够避开用户安装的任何个人防火墙。

基于浏览器的端口扫描可使用Java applet确定用户的IP地址(可能进行了网络地址转换),从而推断出本地网络的IP范围。然后,脚本尝试与任意主机和端口建立连接,以测试连通性。如前所述,同源策略阻止脚本处理这些请求的响应。但是,在检测登录状态时使用的相似技巧也可用于测试网络连通性。这时,攻击者的脚本尝试从每个目标主机和端口动态加载并执行一段脚本。如果那个端口上有Web服务器正在运行,它将返回HTML或其他一些内容,生成端口扫描脚本能够检测到的JavaScript错误。否则,连接尝试将会超时或不返回任何数据,在这种情况下不会导致错误。因此,尽管应用程序实施同源限制,端口扫描脚本仍然能够确定任意主机和端口的连通性。

请注意,大多数浏览器都在可以使用HTTP访问的端口上实施了限制,并阻止了其他主要服务常用的端口(如用于SMTP的端口25)。但是,通过利用相关漏洞,可以突破这些浏览器实施的限制。

攻击其他网络主机

成功使用端口扫描确定其他主机后,就可以使用一段恶意脚本尝试标识每一个发现的服务,然后通过各种方法实施攻击。

许多Web服务器包含位于特殊URL位置的图像文件。下面的代码检查一幅与一系列常用DSL路由器有关的图像:

如果notNetgear函数未被调用,则说明服务器已被成功标识为NETGEAR路由器。接下来,脚本可通过利用特定软件中任何已知的漏洞,或执行请求伪造攻击,继续攻击Web服务器。在本示例中,攻击者可以尝试使用默认证书登录路由器,并对路由器进行重新配置,以打开其外部接口上的其他端口,或向外界披露它的管理功能。注意,许多这种非常有效的攻击只需要提出任意请求,而不需要处理它们的响应,因此不会受到同源策略的限制。

在某些情况下,攻击者可以利用DNS重新绑定(DNS rebinding)技巧违反同源策略,从本地网络中的Web服务器中检索内容。这些攻击将在本章后面讨论。

利用非HTTP服务

除针对Web服务器实施攻击外,有些情况下还可以利用用户的浏览器、针对可以从用户的计算机访问的非HTTP服务实施攻击。只有所攻击的服务接受必然会在每个请求的开头出现的HTTP消息头,攻击者就可以在消息主体中发送任意二进制内容,从而与非HTTP服务进行交互。实际上,许多网络服务都接受无法识别的输入,并仍然处理随后针对相关协议而构造的输入。

我们已在第12章介绍了一种跨域发送任意消息主体的技巧,该技巧使用HTML表单(其enctype属性设置为text/plain)向易受攻击的应用程序发送XML内容。下面的论文介绍了实施这类攻击的其他技巧:

www.ngssoftware.com/research/papers/InterProtocolExploitation.pdf

这类协议间攻击可对目标服务实施未授权操作,或利用该服务内的代码级漏洞来攻破目标服务器。

此外,在某些情况下,还可以对非HTTP服务行为加以利用,针对在同一服务器上运行的Web应用程序实施XSS攻击。要实施这种攻击,必须满足以下条件。

非HTTP服务必须在未被浏览器阻止的端口上运行(如前所述)。

非HTTP必须接受浏览器发送的意外HTTP消息头,而不仅仅是在出现这种情况时关闭网络连接。许多服务都接受意外HTTP消息头,特别是那些基于文本的服务。

非HTTP服务必须在其响应中(如在错误消息中)回显一部分请求内容。

浏览器必须接受不包含有效HTTP消息头的响应,并且必须将一部分响应作为HTML处理(如果响应中包含HTML)。实际上,在收到合适的非HTTP响应时,所有最新版本的浏览器都以这种方式进行处理(可能是为了向后兼容)。

在隔离域源访问cookie时,浏览器必须忽略端口号。确实,在处理cookie时,当前浏览器会忽略端口。

如果满足这些条件,攻击者就可以构建针对非HTTP服务的XSS攻击。要实施这种攻击,需要以正常方式在URL或消息主体中发送专门设计的请求。然后,请求中包含的脚本代码将被回显,并在用户的浏览器中执行。该代码可以从非HTTP服务所在的域中读取用户的cookie,然后将这些cookie传送给攻击者。

利用浏览器漏洞

如果用户的浏览器或任何安装的扩展存在漏洞,攻击者就可以通过恶意JavaScript或HTML代码利用这些漏洞。某些情况下,攻击者可以利用Java虚拟机之类的扩展中的漏洞、与本地计算机或其他位置上的非HTTP服务进行双向二进制通信。这样,攻击者就可以利用通过端口扫描确定的存在于其他服务中的漏洞。许多软件产品(包括并非基于浏览器的产品)还安装了可能包含漏洞的ActiveX控件。

DNS重新绑定

DNS重新绑定(DNS rebinding)是一种在某些情况下可部分违反同源策略,从而允许恶意Web站点与其他域进行交互的技术。之所以能够实施这种攻击,是因为同源策略主要基于域名进行隔离,而最终传送HTTP请求则需要将域名转换为IP地址。

整体看来,这种攻击的过程如下。

用户访问攻击者域上的恶意Web页面。为检索此页面,用户的浏览器会将攻击者的域名解析为攻击者的IP地址。

攻击者的Web页面向攻击者的域提出Ajax请求(同源策略允许这种行为)。攻击者利用DNS重新绑定确保浏览器再次解析攻击者的域,在这次解析过程中,域名将解析为攻击者所针对的第三方应用程序的IP地址。

随后针对攻击者的域名提出的请求将被发送到目标应用程序。由于这些请求与攻击者的原始页面在同一个域上,因此,同源策略允许攻击者的代码检索目标应用程序返回的请求的内容,并将这些内容返还给攻击者(可能位于受其控制的其他域上)。

实施这种攻击将面临各种阻碍,包括一些浏览器为继续使用以前解析的IP地址(即使域已被重新绑定到其他地址)而采用的机制。此外,浏览器发送的Host消息头仍然会引用攻击者的域,而不是可能会导致问题的目标应用程序的域。之前,攻击者可以利用一些方法在各种浏览器上突破这些阻碍。除浏览器外,还可以针对浏览器扩展和Web代理实施DNS重新绑定攻击,不过浏览器扩展和Web代理的运行机制可能会有所不同。

请注意,在DNS重新绑定攻击中,就浏览器而言,针对目标应用程序的请求仍然在攻击者的域中提出。因此,这些请求中不会包含目标应用程序所在的域的任何cookie。为此,攻击者可以通过DNS重新绑定从目标应用程序检索到的内容,与任何可以直接向目标应用程序提出请求的用户能够检索到的内容相同。因此,这种技巧在目标应用程序已实施了其他控制来防止攻击者直接与其进行交互的情况下尤其有用。例如,如果用户处在无法通过互联网直接访问的组织内部网络中,攻击者可以诱使该用户从所在网络的其他系统中检索内容,并将这些内容传送给攻击者。

浏览器利用框架

人们已开发出各种框架,用以演示和利用各种针对因特网终端用户的攻击。这些框架通常需要通过某种漏洞(如XSS),在受害者的浏览器中放入一个JavaScript钩子(hook)。放置钩子后,浏览器就会与攻击者控制的服务器建立联系。浏览器会定期访问这个服务器,向攻击者提交数据,同时提供一个控制信道,方便接收攻击者发出的命令。

 注解 尽管同源策略实施了各种限制,但在这种情况下,攻击者仍然可以利用各种技巧、通过已注入到目标应用程序中的脚本与其控制的服务器进行双向异步交互。一种简单的方法是对自己的域实施动态跨域脚本包含。这些请求能够向攻击者提交截获的数据(在URL查询字符串中),并接收有关应执行的操作的指令(在返回的脚本代码中)。

以下是可以在这种类型的框架中执行的一些操作:

记录键击并向攻击者发送这些内容;

劫持用户访问易受攻击的应用程序的会话;

“指纹”识别受害者的浏览器,从而利用已知的浏览器漏洞;

对其他主机(位于被攻破的用户浏览器能够访问的私有网络中)进行端口扫描,并向攻击者传送扫描结果;

通过迫使浏览器发送恶意请求,可对借助被攻破的用户浏览器访问的其他Web应用程序实施攻击;

对用户的浏览历史记录实施蛮力攻击,并将结果送交给攻击者。

BeEF是一个典型的综合型浏览器利用框架,它由Wade Alcon开发,能够执行上述功能。图13-8说明了BeEF如何截取一名被攻破用户的信息,包括计算机的相关资料、当前显示的URL与页面内容,以及用户输入的键击。

图13-8 利用BeEF从一名被攻破的用户截取的数据

图13-9显示BeEF正对受害用户的计算机进行端口扫描。

图13-9 BeEF正对一名被攻破的用户计算机进行端口扫描

XSS Shell是另外一个功能非常强大的浏览器利用框架,它由Ferrruh Mavituna开发。这个框架提供一系列功能,可控制通过XSS攻破的僵尸主机(zombie host),包括截获键击、剪贴板内容、鼠标移动、屏幕截图、URL历史记录,以及注入任意JavaScript命令。即使导航到应用程序的其他页面,它还会驻留在用户的浏览器中。

中间人攻击

我们在前几章中讲到,如果应用程序使用未加密HTTP通信,则位于适当位置的攻击者可以通过各种方式拦截敏感数据,如密码和会话令牌。更令人惊奇的是,即使应用程序使用HTTPS传输所有敏感数据,并且目标用户始终验证是否正确使用了HTTPS,攻击者仍然能够实施一些严重的攻击。

这类攻击称为“中间人”攻击。这类攻击者不只是被动监视其他用户的流量,而且会动态更改某些流量。这类攻击往往更加复杂,但确实可以在各种常见的情形(包括无线公共热点和共享的办公网络)中实施。

许多应用程序使用HTTP传输非敏感数据,如产品说明和帮助页面。如果这些内容使用绝对URL实现任何脚本包含,攻击者就可以利用主动中间人攻击攻破同一域上受HTTPS保护的请求。例如,某应用程序的帮助页面可能包含以下代码:

目前,许多知名Web应用程序都采用这种行为,即使用绝对URL包含通过HTTP传送的脚本。在这种情况下,活跃的中间人攻击者当然可以通过修改任何HTTP响应来执行任意脚本代码。但是,由于同源策略通常会将通过HTTP和HTTPS加载的内容视为属于不同来源,攻击者并不能利用这种攻击截获使用HTTPS访问的内容。

为克服这种障碍,攻击者可以通过修改任何HTTP响应来构建重定向,或在其他响应中重写链接目标,从而诱使用户通过HTTPS加载同一页面。当用户通过HTTPS加载帮助页面时,其浏览器将使用HTTP执行指定的脚本包含。令人遗憾的是,一些浏览器在这种情况下并不显示任何警告。然后,攻击者可以在包含脚本的响应中返回任意脚本代码。该脚本将在HTTPS响应中执行,允许攻击者截获通过HTTPS访问的所有内容。

即使所攻击的应用程序并不使用普通HTTP传送任何内容,但攻击者仍然可以通过向任何其他域提出HTTP请求来返回重定向,从而诱使用户使用普通HTTP向目标域提出请求。虽然应用程序本身可能不会监听端口80上的HTTP请求,但攻击者可以拦截这些诱发的请求,并在这些请求的响应中返回任意内容。在这种情况下,攻击者可以采用各种技巧来攻击应用程序域的HTTPS来源。

首先,如介绍cookie劫持攻击时所述,攻击者可以使用通过普通HTTP传送的响应来设置或更新HTTPS请求使用的cookie值。即使cookie最初通过HTTPS设置并被标记为安全,攻击者仍然可以这样做。如果有任何cookie值由在HTTPS来源中运行的脚本代码以危险的方式进行处理,攻击者就可以利用cookie注入攻击、通过该cookie来实施XSS攻击。

其次,我们在前面讲到,一些浏览器扩展并不能正确隔离通过HTTP和HTTPS加载的内容,并将这些内容视为属于同一来源。这时,攻击者的脚本(由诱发的HTTP请求的响应返回)就可以利用此类扩展来读取或写入用户使用HTTPS访问的页面的内容。

要实施上述攻击,需要通过某种方法,如从用户向任何其他域提出的HTTP请求返回重定向响应,诱使用户向目标域提出任意HTTP请求。你可能认为极为注重安全的用户并不会受到上述攻击。假设用户一次仅访问一个Web站点,并在访问每个新站点之前重新启动浏览器。假设他使用全新的浏览器登录自己的银行应用程序,并且该程序仅使用HTTPS传输数据。他是否会受到中间人攻击呢?

令人担心的是答案是肯定的,他可能会受到攻击。今天的浏览器会在后台提出各种普通HTTP请求,而不论用户访问哪一个域。常见的例子包括反钓鱼列表、版本ping以及针对RSS源的请求。这时,攻击者可以通过HTTP,用指向目标域的重定向来响应其中的任何请求。如果浏览器直接访问该重定向,攻击者就可以实施上述某种攻击,首先攻破目标域的HTTP来源,然后将攻击扩展到HTTPS来源。

注重安全的用户如果需要通过不可信网络访问受HTTPS保护的敏感内容,可以将浏览器的代理配置设置为“对除HTTPS以外的所有协议使用无效的本地端口”,从而在一定程度上阻止上述攻击。即使这样做,他们仍然需要当心针对SSL的主动攻击(该主题不属于本书的讨论范围)。

小结

我们已经分析了各种情形,说明了Web应用程序中存在的漏洞是如何令它的用户遭受恶意攻击的。许多这种漏洞都非常难以理解和发现,而且在这个过程中往往需要进行大量的调查,为此付出的努力超出了它们作为某个重要攻击的前提的实际意义。然而,严重的漏洞常常隐藏在大量无关紧要的客户端缺陷之中,而攻击者则可以利用这类漏洞对应用程序实施攻击。因此,许多时候,付出这样的努力还是值得的。

而且,随着人们对Web应用程序安全意识的逐渐增强,直接针对服务器组件的攻击可能更难以发现或实施。但是,针对其他用户的攻击,无论其结果好坏,肯定会成为每个人将来必须面对的问题。

问题

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

(1)已知一项应用程序功能将一个查询字符串参数的内容插入到某个HTTP重定向的Location消息头中。利用这种行为,攻击者可以实施哪3种不同类型的攻击?

(2)要针对应用程序的一项敏感功能实施CSRF攻击,必须满足什么前提条件?

(3)哪3种防御措施可用于防止JSON劫持攻击?

(4)对于以下每一种技术,确定该技术请求/crossdomain.xml正确实施域隔离的任何情形:

(a)Flash

(b)Java

(c)HTML5

(d)Silverlight

(5)“我们不会受到单击劫持攻击,因为我们不使用框架。”以上表述是否正确,为什么?

(6)已知在某应用程序使用的昵称中存在一个永久性XSS漏洞。此字符串仅在配置它的用户登录应用程序时向该用户显示。请描述用于攻破该应用程序的其他用户的攻击所需执行的步骤。

(7)如何测试应用程序是否允许使用XMLHttpRequest提出跨域请求?

(8)请描述攻击者可诱使受害者使用任意cookie的3种方法。

浙ICP备11005866号-12