Thursday, November 29, 2012

(on HNews)
Basically, browsers often suggest you to save your password and prefill it automatically.

The bug I just discovered: This value can be retrieved from JS side easily(and this means XSS can steal it). Your REAL password. It's not fucking yet-another-CSRF or SQL injection(server side is pwned) or other trivial. YOU are pwned. Kind of a serious issue.

Very similar to old issue with 'highlighted' visited links, when attacker could know did you visit certain link or not.

Also, XSS can be on any page and user can be signed in or signed out. It will just open iframe or window and get values because of same origin.

Browsers should deny access to prefilled passwords from JS.(UPD: not helpful)

P.S. I'm alive and in Asia(now Kuala Lumpur). Don't worry, new stuff will be published soon ;)

I WAS WRONG. (About these two things)

1. Proposed solution will break the AJAX-based authentications since JS will not have access to password anymore. For example you might want to send password in a header:
Authentication: username:password
and to do so you have to use XHR. If you cannot retrieve password from autofilled input authentication will get broken.

2. There is one more workaround - XSS can change 'action' field to 3rd party website and then .submit(). JS doesn't need access to .value - browser itself will send it to attacker's server. Should we restrict sending passwords only to actions on the current page domain(same origin)? Sounds ugly.

Possible solutions:
1. restricting 'action' value to same origin. Ugly?
2. using Autocomplete only when user is interacting with the website e.g. by typing the first letters of the nickname.
3. Ask in the top bar notification "Should we use autocomplete on example.com?" or smth like this. Looks not bad to me.

4. BEST ONE: do not use any autofill. At least for passwords.
Because security of autofills is fucked. The more websites you use - the more probability to be XSSed on the one of them.

Thursday, September 6, 2012

Authorization 'code' expires as soon as access_token expires - approximately 60-80 minutes, during this period it can be used many times to obtain access_token. Every time you visit example.org/fb_callback?code=123qwe... you are authenticated for example.org.

o The authorization server should enforce a one time usage restriction (see Section 5.1.5.4). [unlimited]

There are couple of ways to get 'code':Logs.
For example if you use omniauth with rails check your logs for
GET "/auth/facebook/callback?code=..."
I recommend to filter this parameter with built-in tool:
config.filter_parameters += [:password, :code]Sniff
Callback is located on Client's website - and it is not always HTTPS. Your URL with code may be sniffed with MITM, browser plugins, browser history(if it has not redirects) etcXSS
Here is a neat exploit to extract callback URL for proper redirect_uri.

1) Load authorize URL with proper redirect_uri as callback in iframe
2) get redirected on proper redirect_uri with code
3) another redirect, usually to root
4) fires up 'onload' event
5) since we are on the same origin we just go into iframe and extract 'document.referrer' - redirect_uri with code.
6) leak code and use it for replay attacks.

Mitigation:
One time usage of 'code', please. There is no sense to keep 'code' if Client already obtained access_token for it.

Vkontakte Referrer LeakVkontakte has one time usage of 'code'. No replay attack here... Wait, there is a similar one. VK OAuth2 has a huge flaw.
They do not require 'redirect_uri' to exchange code for token. It means there is no verification, was certain 'code' issued for proper redirect_uri or any other URL (on Client's domain).
You can get a code for
SITE.com/fake_callback_leaking_referrer?code=123qwe
and then just use it on
SITE.com/real_callback?code=123qwe
You will be authenticated.

There are literally dozens of ways to leak code: browser history, hot linked images leak referrer, clickjacking with clicking on external URL, sniffing, open redirectors(feature on some sites site.com?url=http://other.com) etc

Mitigation:

Every time you create code you must save for which redirect_uri it was issued. When code will be exchanged for token, ensure that given redirect_uri parameter is equal stored.

https://www.facebook.com/dialog/oauth?client_id=130409810307796&redirect_uri=http%3A%2F%2Fapps.facebook.com%2Ftetris_battle%2F%2F%3Fkt_track_apa%3D1%26reload%3D1%26reloadTime%3D1346239416%26localJS%3Dfalse&state=6997cb601838cb0fb65d53aecbebcd21&scope=publish_actions%2Cemail%2Cuser_location%2Cuser_birthdayJust change 'scope' param
https://www.facebook.com/dialog/oauth?client_id=130409810307796&redirect_uri=http%3A%2F%2Fapps.facebook.com%2Ftetris_battle%2F%2F%3Fkt_track_apa%3D1%26reload%3D1%26reloadTime%3D1346239416%26localJS%3Dfalse&state=6997cb601838cb0fb65d53aecbebcd21&scope=
And authorize the app. You permitted nothing special but app works - enjoy.UPDATE:
The post had nothing to do with security. I was annoyed with terrible fact "you can ask permissions, it will look legit and user cannot uncheck them in UI. Well if he's smart enough to change URL - you have to check permissions in your code"
There are two ways to fix it (OAuth2.a deals with the issue this way):
1) when app has "frozen" scope. This is not param in URL anymore, just a field in the database. Developer doesn't need to make sure what is allowed anymore - he is sure.
2) when app has "agile" scope. Client 'proposes' scope and User can uncheck not desired permissions. App should check explicitly what was permitted.

Tuesday, August 28, 2012

I demonstrated The Most Common OAuth2 Vulnerability in Authorization Code Flow a while ago – signing in the Victim's account(followed by getting an access to Victim's resources on that website) by connecting Attacker's oauth account through CSRF-callback URL with Attacker's code. Despite popularity of that attack, it can be easily mitigated with 'state' param(to prevent CSRF) – and now it's fixed in popular ruby/python libraries.

Now I want to share a very straightforward attack for Implicit Flow based websites(realized in brainstorming with @isciurus). There is no proper mitigation so far.

Generally speaking:

'access_token' is a string that identifies your Resources on Provider. No other parameters are required to call Provider's API. There is no guarantee user's access_token1 for client1 is not used by client2 or client75 - nothing stops them.

Let's assume I create a website: e.g. superfunnypicturez.com. I ask my users to authorize my Client on facebook and I don't ask any scopes at all - I need only "/me" endpoint with "uid" param to be available. They authorize my Client because superfunnypicturez.com requires only 'read' access and nothing seems to be dangerous. I get their 'access_token's and now I can request /me endpoint and get their "uid"(often used for authentication)

Let's assume there is another site: e.g. weuseimplicitflow.com and yep, it uses Implicit Flow(receives token via CALLBACK#access_token=123qwe...). It's a pity - this website authenticates users by given access_token. Most likely it sends access_token on server-side and invokes /me endpoint from there.

Since I am admin of superfunnypicturez.com and you authorized my Client and gave me an access_token from your account I just put that access token in callback URL: CALLBACK#access_token=YOUR_TOKEN and now weuseimplicitflow.com's Client authenticates me as you because that token I just provided returns your 'uid' when /me endpoint is called. I need only one access_token from your Provider's account to rule all your accounts on 3rd party websites that use Implicit Flow.

Recap:

OAuth2 is extremely insecure for authentication goals by default.

Auth Code Flow: You must use 'state' parameter and verify - is this user the same user you sent to authorization URL by checking state value from session and returned one.

Implicit Flow: You must ensure that access_token you are going to use is issued for your Client. Please, use this URL for Facebook: https://graph.facebook.com/app?fields=id&access_token=TOKEN. Not all providers support this feature though. If access_token is anyhow obtained from User (not from Provider) - you must verify is this access_token issued for your Client.

Oh, also:

As I mentioned in my previous post on stupidity of OAuth2 - if Provider has Implicit Flow as an option - lots of Users can be compromised someday. If a single XSS is found on Client's domain - hackers can steal all access_tokens with it even if your website uses Auth Code Flow by just changing response_type param in authorize URL.

Below I explain some security and usability concerns about current OAuth2 and propose(I do, not just say 'it is bad') improvements to make it more agile and safe-by-default. OAuth2.a is going to be easier to implement and more secure.

TL;DR:

redirect_uri can be on any domain and amount of redirect_uri-s is unlimited. They are whitelisted and only exact match verification is applied(redirect_uri IS NOT flexible domain.com/*). Client sets redirect_uri-s on his admin page in Provider.

for every redirect_uri MUST be defined certain response_type - token or code. It must not be possible to set response_type in authorize URL. Every redirect_uri has its own defined response_type

Tuesday, July 3, 2012

HN discussionTL;DRIf 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 draftthoroughly 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.

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.

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

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.

Thursday, June 21, 2012

Security is art for me. Reporting yet another routine vulnerability(e.g. XSS is one) is a routine.

Now the question is: Why reporting a vulnerability is always such a hassle and tedious email ping-pong? Should we have another startup: getavuln.com(getsatisfaction analogy) which aggregates vulnerabilities for all websites to make reporting easier? I'm kidding.Frankly, I want every flaw I find to be fixed - I report it and reported so far to more than 20 pretty popular sites. Only 1 of them(skrill) was nice enough to pay me some bounty and just a few of them said 'thanks'.I'm pissed off explaining to technical support of Tumblr what is the vulnerability and how to fix it. Getting reply "What is your browser and which OS do you use" - WTF, why do you waste my time? :(

Post the link and enjoy - everyone will reblog it by clicking and will not notice anything. Also you can add me on tumblr and then press the link in your dashboard to see it in action instantly. Get 'reports' first -twitterandRSS.

Wednesday, June 6, 2012

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

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

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>

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

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

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.

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.

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.