(1)向应用程序中的每一个可能的位置提交一个特殊的字符串后,必须反复检查应用程序的全部内容与功能,确定这个字符串在浏览器中显示的任何情况。在某个位置(例如,个人信息页面的姓名字段)输入用户控制的数据,这个数据可能会在应用程序的许多不同位置显示(例如,用户主页上、注册用户列表中、任务等工作流程项目中、其他用户的联系列表中、用户提交的消息或问题中、应用程序日志中等)。应用程序可能对每个出现的字符串实施了不同的保护性过滤,因此需要对它们进行单独分析。
(2)如有可能,应检查管理员能够访问的所有应用程序区域,确定其中是否存在任何可被非管理用户控制的数据。例如,应用程序一般允许管理员在浏览器中检查日志文件。这种类型的功能极有可能包含XSS漏洞,攻击者通过生成含有恶意HTML的日志记录即可对其加以利用。
(3)在向应用程序中的每个位置提交一个测试字符串时,并不总是把它作为每个页面的每一个参数这样简单。在保存被提交的数据之前,许多应用程序功能需要经历几个阶段的操作。例如,注册新用户、处理购物订单、转账等操作往往需要按预定的顺序提交几个不同的请求。为避免遗漏任何漏洞,必须确保每次测试彻底完成。
(4)在探查反射型XSS漏洞时,应该注意可控的受害者请求的每一个方面。包括请求的所有参数和每一个HTTP消息头。在探查保存型XSS漏洞时,还应该分析应用程序用于接收并处理可控输入的任何带外通道。任何这类通道都是引入保存型XSS攻击的适当攻击向量。同时,审查在应用程序解析过程中得到的结果(请参阅第4章了解相关内容),确定每一个可能的受攻击面。
(5)如果应用程序允许文件上传与下载,应始终探查这种功能是否易于受到保存型XSS攻击。我们将在本章后面部分讨论测试这类功能的详细技巧。
(6)充分发挥想象,确定控制的数据是否可通过任何其他方法保存在应用程序中并显示给其他用户。例如,如果应用程序的搜索功能显示常用的搜索项列表,就可以通过多次搜索这个列表,引入保存型XSS有效载荷,即使主搜索功能本身安全地处理输入。
确定用户控制的数据被应用程序保存并随后在浏览器中显示的每一种情况后,应当遵循与前面描述的探查潜在的反射型XSS漏洞时相同的过程。也就是说,决定需要提交哪些输入,以在周围的HTML中嵌入有效的JavaScript,然后尝试避开干扰攻击有效载荷执行的过滤。
提示
在探查反射型XSS漏洞时,每次测试一个参数,并检查每个响应中是否出现输入,就可以轻易确定哪些请求参数易于受到攻击。但是,在探查保存型XSS漏洞时,要确定这一点并不容易。如果在每个页面的每一个参数提交相同的测试字符串,那么你可能会发现,这个字符串在应用程序的许多位置重复出现,因而无法准确确定每个出现的字符串由哪个参数负责。为避免出现这个问题,在探查保存型XSS时,可以为每个参数提交一个不同的测试字符串,例如,把测试字符串与它提交到其中的字段名称连接起来。
在测试保存型XSS漏洞时,我们还可以采用一些特殊的技巧。在下面几节中,我们将详细介绍这些技巧。
1.在Web邮件应用程序中测试XSS
如前所述,由于Web邮件应用程序将直接从第三方收到的内容包含在向用户显示的应用程序页面中,因此,这种程序本身就存在着保存型XSS攻击风险。要测试这种功能,应该在该应用程序上创建自己的电子邮件账户,并通过电子邮件向自己实施大量XSS攻击,然后在该应用程序中查看每封邮件,确定是否有任何攻击取得成功。
为彻底完成这一任务,你需要通过电子邮件发送各种反常的HTML内容(如我们在测试避开输入过滤的方法时所述)。如果仅限于使用标准电子邮件客户端,你可能会发现,无法完全控制原始的邮件内容,或者邮件客户端可能会净化或“清除”你有意设计的畸形语法。
在这种情况下,最好是采用其他方法来生成电子邮件,以便于直接控制邮件的内容。一种方法是使用UNIX sendmail命令。首先,需要使用应当用于向外发送电子邮件的邮件服务器的详细信息配置电脑;然后,可以在文本编辑器中创建原始的电子邮件,并使用以下命令发送该邮件:
以下为原始电子邮件文件的一个示例。在消息主体中测试各种XSS有效载荷和避开过滤的机制时,也可以尝试指定不同的Content-Type和charset:
2.在上传文件中测试XSS
如果应用程序允许用户上传可被其他用户下载并查看的文件,就会出现保存型XSS漏洞;然而,这种漏洞常常被人们忽略。如今的应用程序通常都提供文件上传功能,除传统的用于文件共享的工作流功能外,文件还可以通过电子邮件附件的形式传送给Web邮件用户。图像文件则可以附加到博客文章中,并且可以用作定制的头像或通过相册共享。
应用程序是否易于受到上传文件的攻击,取决于许多影响因素:
在文件上传过程中,应用程序可能会限制可以上传的文件的扩展名。
在文件上传过程中,应用程序可能会检查文件内容,以确认其是否为所需的格式,如JPEG。
在文件下载过程中,应用程序可能会返回Content-Type消息头,以指定文件所包含的内容的类型,如image/jpeg。
在文件下载过程中,应用程序可能会返回Content-Disposition消息头,以指定浏览器应将文件保存到磁盘上。否则,对于相关的内容类型,应用程序会处理并在用户的浏览器中显示文件。
在测试文件上传功能时,首先你应该尝试上传一个包含概念验证脚本的简单HTML文件。如果该文件被接受,则尝试以正常方式下载该文件。如果应用程序按原样返回最初的文件,并且你的脚本得以执行,则应用程序肯定易于受到攻击。
如果应用程序阻止上传的文件,则尝试使用各种文件扩展名,包括.txt和.jpg。如果在你使用其他扩展名时,应用程序接受包含HTML的文件,则应用程序可能仍然易于受到攻击,具体取决于其在下载过程中如何传送文件。Web邮件应用程序通常易于受到这类攻击。攻击者可以发送包含诱惑性图像附件的电子邮件,如果用户查看该附件,他们的会话将被攻破。
即使应用程序返回Content-Type消息头,指定下载文件应为图像,但是,如果文件实际包含的是HTML内容,一些浏览器仍然会将该文件作为HTML处理。例如:
旧版的Internet Explorer就存在这种缺陷。如果用户直接请求一个JPEG文件(并非通过嵌入式<img>标签),那么在收到上述响应时,IE会将该文件的内容当做HTML处理。虽然这种缺陷已经得到修复,但将来在其他浏览器中也可能会出现此类缺陷。
混合文件攻击
通常,为防范上述攻击,应用程序会对上传文件的内容执行某种确认,以确保其确实包含所需格式的数据,如图像。但是,使用“混合文件”(在一个文件中组合两种不同的格式)仍然可以对这些应用程序实施攻击。
Billy Rios设计的GIFAR文件就是一种常见的混合文件。GIFAR文件包含GIF图像格式和JAR(Java档案)格式的数据,并且是这两种格式的有效实例。这是因为,与GIF格式相关的文件元数据位于文件的开始部分,与JAR格式相关的元数据则位于文件的结尾部分。因此,如果应用程序允许包含GIF数据的文件,那么,在确认上传文件的内容时,该应用程序也会接受GIFAR文件。
通常,使用GIFAR文件实施的上传文件攻击由以下步骤组成。
攻击者发现由一名用户上传的GIF文件可由其他用户下载(如社交网络应用程序中的用户头像)的应用程序功能。
攻击者构建一个GIFAR文件,在其中包含一段Java代码,用于劫持任何执行该代码的用户的会话。
攻击者将该文件作为他的头像上传。因为其中包含有效的GIF图像,应用程序将接受该图像。
攻击者确定可利用上传的文件对其实施攻击的适当外部网站。该网站可能为攻击者自己的网站,或允许用户创建任意HTML(如博客)的第三方站点。
在该外部网站上,攻击者使用<applet>和<object>标签从上述社交网络站点以Java applet的形式上传GIFAR文件。
如果用户访问该外部站点,攻击者的Java applet将在其浏览器中执行。与包含正常脚本的文件不同,在遇到Java applet时,同源策略的执行方式会有所不同。Java applet将被视为属于加载它的域,而不是调用它的域。因此,攻击者的applet将在社交网络应用程序的域中执行。如果受害用户在受到攻击时已登录该社交网络应用程序,或者最近曾登录该应用程序并选中了 “保持登录状态”(stay logged in)选项,则攻击者的applet将完全控制受害用户的会话,从而侵入该用户。
当前版本的Java浏览器插件通过确认所加载的JAR文件是否包含混合内容,从而阻止了这种使用GIFAR文件的特殊攻击。但是,使用混合文件隐藏可执行文件的原理仍然适用。鉴于当前所使用的客户端可执行代码格式的范围不断扩大,攻击者或许可以以其他格式,或在将来通过其他方式实施类似的攻击。
在通过Ajax上传的文件中测试XSS
一些应用程序使用Ajax来检索和呈现在片段标识符之后指定的URL。例如,应用程序的页面中可能包含以下链接:
http://wahh-app.com/#profile
当用户单击此链接时,客户端脚本将处理单击事件,使用Ajax来检索在片段标识符之后显示的文件,并在现有页面中的<div>元素的innerHtml中设置响应。这样可提供无缝的用户体验,因为单击用户界面中的选项卡将更新所显示的内容,而无须重新加载整个页面。
在这种情况下,如果应用程序还包含其他允许上传和下载图像文件(如用户头像)的功能,你就可以上传一个包含嵌入式HTML标记的有效图像文件,并构建以下URL,使客户端代码提取该图像并将其作为HTML显示:
http://wahh-app.com/#profiles/images/15234917624.jpg
HTML可以嵌入到有效图像文件的各种位置,包括图像的注释部分。一些浏览器,包括Firefox和Safari,乐于将图像文件以HTML格式显示。图像的二进制部分将显示为乱码,而任何嵌入的HTML将正常显示。
提示
假设潜在的受害者使用的是兼容HTML5的浏览器,如果所请求的域许可,该浏览器可用于跨域传送Ajax请示。在这种情况下,另一种可能的攻击方法,是在片段标识符后面放置一个绝对URL,指定一个位于可与目标域进行Ajax交互的服务器上的、完全由攻击者控制的外部HTML文件。如果客户端脚本不确认所请示的URL是否在同一个域上,客户端远程文件包含攻击将取得成功。
由于旧版HTML并不需要对URL的域进行此类确认,因此,HTML5中对域确认所做的更改可能会给此前安全的应用程序造成可利用的漏洞。
使用以下方法无法确定基于DOM的XSS漏洞:提交一个特殊的字符串作为每个参数,然后监控响应中是否出现该字符串。
确定基于DOM的XSS漏洞的基本方法是,用浏览器手动浏览应用程序,并修改每一个URL参数,在其中插入一个标准测试字符串,例如:
通过在浏览器中显示每一个返回的页面,可以执行所有客户端脚本,并在必要时引用经过修改的URL参数。只要包含cookie的对话框出现,就表示发现了一个漏洞(可能为基于DOM的或其他类型的XSS漏洞)。使用本身提供JavaScript解释器的工具甚至可以自动完成这个过程。
然而,这种基本的方法并不能确定所有基于DOM的XSS漏洞。如上文所述,在HTML文档中注入有效JavaScript所需的准确语法,取决于用户可控制的字符串插入点前后已经存在的语法。这时,可能需要终止被单引号或双引号引用的字符串,或者结束特定的标签。有时可能需要插入新标签,但有时并不需要。客户端应用程序代码可能会尝试确认通过DOM获得的数据,但它仍然易于受到攻击。
即使应用程序可能易于受到精心设计的攻击,但如果插入标准测试字符串仍不能得到有效的语法,那么嵌入式JavaScript将不会执行,因此也不会有对话框出现。由于无法在每个参数中提交每一种可能的XSS攻击字符串,这种基本的探查方法必然会遗漏大量的漏洞。
确定基于DOM的XSS漏洞的一种更加有效的方法,是检查所有客户端JavaScript,看其中是否使用了任何可能会导致漏洞的DOM属性。有大量工具可用于自动完成这个测试过程。其中一个有用的工具为DOMTracer,下载该工具的URL如下所示:
www.blueinfy.com/tools.html