Tuesday, July 3, 2012

The Most Common OAuth2 Vulnerability


HN discussion
TL;DR
If website uses OAuth multi-logins there is an easy way to log into somebody's account, protection is almost never implemented and people don't take into account that OAuth is also used for authentication.

OAuth2 is an authorization framework. Apparently it's very popular now. Disregards its popularity a lot of people don't understand it deeply enough to write proper and secure implementation.

OAuth1.a and OAuth2 are incompatible, some services use former(twitter, wtf, come on!), some latter, some of them have insufficient and poor documentation(in terms of security) etc. It took me a few hours to read OAuth2 draft thoroughly and I found a few interesting vectors. One of them I am exposing in this post.

It's really dangerous but very common vulnerability for multi-login OAuth websites. 
A little bit of theory:
  • response_type = code is server-side auth flow, should be used when possible, more secure than response_type = token. Provider returns 'code' with User's user-agent and Client sends along with client's credentials the code to obtain 'access_token'. Callback when user is redirected looks like site.com/oauth/callback?code=AQCOtAVov1Cu316rpqPfs-8nDb-jJEiF7aex9n05e2dq3oiXlDwubVoC8VEGNq10rSkyyFb3wKbtZh6xpgG59FsAMMSjIAr613Ly1usZ47jPqADzbDyVuotFaRiQux3g6Ut84nmAf9j-KEvsX0bEPH_aCekLNJ1QAnjpls0SL9ZSK-yw1wPQWQsBhbfMPNJ_LqI
  • I remind you, OAuth is all about authorization, not authentication. What's the difference, you might ask. OAuth just gives to Client access to User's resources on Provider.
    But very often Client authenticates you by 'profile_info' resource, thus we can call it authentication framework either.
Condition for the hacklogin with OAuth Provider + ability to add OAuth Provider logins in settings


Hacking, Step-by-step:
  • Choose Client which suits hack's "condition" - some site.com(we will use Pinterest as showcase) Start authentication process - click "Add OAuth Provider login". You need to get callback from Provider but should not visit it. It's quite difficult - all modern browsers redirect you automatically. I recommend bundle Firefox + NoRedirect extension.
  • Do not visit the last URL(http://pinterest.com/connect/facebook/?code=AQCOtAVov1Cu316rpqPfs-8nDb-jJEiF7aex9n05e2dq3oiXlDwubVoC8VEGNq10rSkyyFb3wKbtZh6xpgG59FsAMMSjIAr613Ly1usZ47jPqADzbDyVuotFaRiQux3g6Ut84nmAf9j-KEvsX0bEPH_aCekLNJ1QAnjpls0SL9ZSK-yw1wPQWQsBhbfMPNJ_LqI#_=_), just save and put it into <img src="URL"> or <iframe> or anything else you prefer to send requests.


  • Now all you need is to make the User(some certain target or random site.com user) to send HTTP request on your callback URL. You can force him to visit example.com/somepage.html which contains <iframe src=URL>, post <img> on his wall, send him an email/tweet, whatever. User must be logged in site.com when he sends the request.
    Well done, your oauth account is attached to User's account on site.com.
  • Voila, press Log In with that OAuth Provider - you are logged in directly to User's account on site.com.

    Enjoy: read private messages, post comments, change payment details, have lulz, whatever. In fact account is yours now.

    After you had enough fun you can just Disconnect that OAuth Provider and log out. Nobody will have an idea what has happened, you left no fingerprints!
How to detect, is certain OAuth implementation vulnerable?
If site doesn't send 'state' param and redirect_uri param is static and doesn't contain any random hashes - it's vulnerable.
I know at least 10+ popular vulnerable sites: e.g. pinterest, digg, soundcloud, snip.it, bit.ly, stumbleupon etc. If you know more sites - please drop me a line at homakov@gmail.com
Also all Rails + Omniauth are vulnerable. Have fun(about 23,300 results)

updates:



Mitigation:
You are supposed to send special optional param 'state' - any random hash you get back by Provider in User's callback: ?code=123&state=HASH. Before adding OAuth account you MUST verify session[state] is equal params[state].
Classic: Insecure-by-default means insecure. Majority of developers don't use it at all - nobody pays for "optional" weird param :trollface:
MUST READ SECTION.

Notices:
  • $_SESSION['state'] == $_REQUEST['state'] is vulnerable code, was used a while ago in FB examples. Emtpy string equals empty string.
  • I recommend you to filter 'code' in logs config.filter_parameters += [:code]
  • state should not be equal form_authenticity_token(session[:csrf_token]) in rails
  • if you implemented response_type=token flow w/o FB JS library, it's most likely vulnerable too.

At the moment I am working on "OAuth2 Security Proposal". The Proposal aims to make OAuth2 safer by changing its policies, rules and workflows. Most of the points are supposed to be backwards compatible but some of them are quite difficult to apply. Stay tuned, I am publishing it in a few days.

Friday, June 22, 2012

With New Features Come New Vulnerabilites. The Web is Broken.

I spam in twitter and RSS.
HN discussi0n

Security Digest:
  • Rails coders, I remind you the very last time :) Run command Find ".to_json" agains your 'app/views' and please sanitize it, I stumble upon case 2 from my Rails & Security talk really often.
  • Use JSONP only with unique token per user. Don't give out private data via static URL.
  • It goes without saying but.. Seriously, Regexp /^http://www.site.com/ is not enough to mitigate CSRFs (Yeah, also if you are rubyist you should use \A instead of ^! Rails has reminder now https://github.com/rails/rails/pull/6671) Why? Because http://www.site.com.hacker.com and http://www.site.com@hacker.com both are legit domains too. Do add "\/" in the end of your Regexp. Anyway, don't rely on Referer.
  • X-Frame-Options (XFO) Detection from Javascript
  • I found out that 'autofocus onfocus=inject' is a really nice vector and works great. Thanks .mario's html5sec.org, some of cases over there are really worth getting addressed.
  • This is new section, please drop me a line homakov@gmail.com if you have any epic thing about security :3
Current status:
On the left - Me, pointing various problems, starving to get feedback and proposing some fixing in a painless way.
On the right - browsers, ruby, community, whatever's response :)


Look, web security is all about philosophy and concept. Root of plenty of the problems is a poor problem solution/design or irresponsible adding of new features.

When browsers implement a new feature they should also care how it'll work along with existing websites, in terms of security too.

Wednesday, June 6, 2012

x-www-form-urlencoded VS json - Pros and Cons. And Vulns.

In this short post I want to remind you how agile HTTP requests are. By "requests" we all mean GET and POST - these are the majority. POST contains "message", which is encoded in Internet media type etc - on wiki

By default <form method="post"> tag submits request with this header:
Content-Type:application/x-www-form-urlencoded
This is the default encoding format among HTTP requests. It was suffice just a few years ago - when all people have been sending nothing bigger and more complex than  "email=my@mail.com&name=John".

It's 2012 now, web became much more comprehensive, more rich and data sets are huge now. Developers scope related params in hashes/arrays - in a "tricky" way. If you want to have user["email"] on the server side you are supposed to send
<input name="user[email]">

but if you want user[emailS"] - array of emails, you should send
<input name="user[emails][]">

Application accumulates all params one by one and put them in the corresponding variables. This attitude is full of bugs and incompatibilities. Let me give you a hence.

Saturday, May 19, 2012

Injects in Various Ruby Websites Through Regexp.

On HN

You are a web developer. Let's assume you are building a website using Ruby(and probably Rails or any other Ruby framework). This is why you need to validate some input params - to make sure that they don't contain any crap you don't want to be there. Come on, you are going to google it, right?:

Tuesday, April 24, 2012

"match" in Rails and CSRF


Related:
CSRF afterparty & MUST READ rules
Playing With Referer & Origin + disqus.com and yfrog.com Vulnerability)


Sometimes developers use GET for state-changing requests by purpose. This determines low-skilled developer. In this post I want to describe another vector of attack - GET Accessible Actions(GAA) - when framework abstractions + bad practices make "Good Guys' apps" insecure.

There is a thing I found exploring DSL's and engines' internals - many frameworks do "dirty work" for developer - they merge GET(stored in URL string)+POST(stored in Body) params into one unified hash. IMO it's cool and awesome to use - "params" for Rails and $_REQUEST for PHP.

But! As I found out it often confuses mechanism of handling GET requests from others(POST-like - PUT/DELETE/etc).
Same "state-changing" code is accessible via GET either, it is GAA, opening the easiest to use hole: <img src=URL/create_message?message[body]=SPAM>

Playing With Referer & Origin


(related: CSRF afterparty & MUST READ rules )


If you read owasp you should know that Referer has never been a good protection. If user submits form from https:// URL than referer header is omitted due to security reasons - it's known fact. But having https page is a big deal for hacker - very uncomfortable for massive attacks(rapidly banned/reported, expensive certificates).

I found a way(in fact two ways) to omit this header from any page - it is the trick with about:blank.

Monday, April 2, 2012

CSRF examples


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!

Friday, March 30, 2012

CSRF Is A Vulnerability In All Browsers

Navigation:
#1 CSRF Is A Vulnerability In All Browsers - You MUST Deny It ASAP.
#2 top secret(will be published on April 1)
#3 Another Rails Issue(April 2-3)
#4 The Webkit Hole(April 2-4)

It took me a long time to understand the point behind CSR (cross-site requests) and CRSF fully enough to find them EXTREMELY malicious.
Following points should be made before any explanation.
  • It is well known attack(yep, just like mass assignment). It's known but not well. You won't find any mention of CSRF in books for beginners a la "PHP in 24 hours" or "HTML/CSS for dummy". Underestimated kind of attack.
  • It is neither bug in OS nor in browser nor in the servers' adjustments. Linux/Mac/Windows, Chrome/Firefox/IE - it just doesn't matter! This is just an expected behavior. And it works like it supposed to. Funny, isn't it? Known since 2001 but not fixed yet. Interested? Keep reading.
  • HTTPS? Would not help. SSL has nothing to do with this attack.
  • Short sessions? Sounds nice, but there are always a few ways to ask/force user to sign in and than script can attack. We are human, it's not so difficult to cheat on us. And, short sessions are rare, most sites with a "remember me" button do not rely on short sessions.
  • Special plugins/extensions to be secure(e.g. https://www.requestpolicy.com/). Who uses them?! O_o Almost nobody.
  • Protection on server-side. Rails 3 framework has it out-of-box - using authenticity_token helps. By the way Rails is the most secure framework I've ever seen.(sic!) Mass assignment is "vulnerability" in the documentation and developers are in charge; but not in rails. At the same time to have protection with other langs/platforms(PHP, Java, Asp.net) you have to write ~10-50 additional lines of code. IMO(and *these cases* prove it) 90% of developers just don't care and don't spend time on that. That's a huge hole, easy to find and easy to use.

Sunday, March 4, 2012

Hacking rails/rails repo

So I commited in rails/rails repo

I simply added a <input value=USER_ID name=public_key[user_id]> field to Public key update form, where USER_ID = 4223 (from https://api.github.com/users/rails).

Backend didn't whitelist accessible attributes and had something like this:
@key = PublicKey.find(params[:id])
@key.update_attributes(params[:public_key]) #Oh no! We passed public_key[user_id] of our victim!

Now our victim (Rails) has our public key associated with their account. You can read/write in any public/private repo on github.

Thoughts on this from 2014: 
it was one of my first hacks and I didn't know how to behave. I was angry because nobody wanted to take me and mass-assignment issue seriously. After I did the commit this vulnerability was fixed on github within 1 hour and in rails within 5 hours. This was really effective, many people learned about the bug and fixed it in their apps, but I still regret about this irresponsible disclosure.