Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting past anti-CSRF to log a user into a site when you know their username and password

This sounds a bit evil, bear with me though. It's also not specifically a Rails question even though the two sites in question use Rails. (Apologies in advance for both these things)

Imagine two websites which both use Ruby on Rails:

  • mysite.com, on which i'm a developer and have full access in terms of changing code etc, and also have an admin login, so I can manage user accounts.

  • theirsite.com, on which i have an admin login but no dev access. I know the people who run it but i'd rather not ask them any favours for political reasons. That is an option however.

Using my admin login on each site i've made a user account for the same person. When they're logged into mysite.com, i'd like to be able to provide a button which logs them straight into theirsite.com. I have their username and password for theirsite.com stored in their user record in the mysite.com database, to facilitate this. The button is the submit button for a form which duplicates the form on the theirsite.com login page, with hidden fields for their username and password.

The stumbling block is that theirsite.com handles CSRF with an authenticity_token variable, which is failing validation when the login submits from mysite.com.

My first attempt to get past this was, in the mysite.com controller which loads the page with the form, to scrape the theirsite.com login page to get an authenticity token, and then plug that into my form. But this isn't working.

If i load the theirsite.com login page, and the mysite.com page with the remote login button in two browser tabs, and manually copy the authenticity_token from the theirsite.com form to the mysite.com form, then it works. This is because (i think) the authenticity_token is linked to my session via a cookie, and when i do it all in the same browser the session matches up, but when i get the authenticity token from theirsite.com via scraping (using Nokogiri but i could use curl instead) it's not the same session.

Question A) So, i think that i also need to set a cookie so that the session matches up between the browser and the Nokogiri request that i make. But, this might be impossible, and exactly the sort of thing that the anti-CSRF system was designed to defeat. Is that the case?

Question B) Let's say that i decide that, despite the politics, i need to ask the owner of theirsite.com to make a small change to allow me to log our users into theirsite.com when we know their theirsite.com username and password. What would be the smallest, safest change that i could ask them to make to allow this?

Please feel free to say "Get off SO you evil blackhat", i think that's a valid response. The question is a bit dodgy.

like image 868
Max Williams Avatar asked Jul 31 '14 09:07

Max Williams


People also ask

Can we bypass CSRF token?

Using the Attacker's Anti-CSRF Token: When the server only checks if a token is valid but does not check which user the token is associated with, an attacker can simply provide their own CSRF token to satisfy server's check and bypass the CSRF protection.

How can cross site request forgery CSRF be prevented?

The most effective method of protecting against CSRF is by using anti-CSRF tokens. The developer should add such tokens to all forms that allow users to perform any state-changing operations. When an operation is submitted, the web application should then check for the presence of the correct token.

How do you prevent CSRF attack in web API?

To prevent CSRF attacks, use anti-forgery tokens with any authentication protocol where the browser silently sends credentials after the user logs in. This includes cookie-based authentication protocols, such as forms authentication, as well as protocols such as Basic and Digest authentication.

Where are anti-CSRF tokens stored?

When a CSRF token is generated, it should be stored server-side within the user's session data. When a subsequent request is received that requires validation, the server-side application should verify that the request includes a token which matches the value that was stored in the user's session.


2 Answers

A) No, this is not possible as CSRF Protection is made to protect from actions like these only. So "Get off SO you evil blackhat"

As per the question I'm assuming that theirsite.com is using Rails(v3 or v4)

B) The smallest change that you could ask them to do is to make a special action for you, so that you could pass user credentials from your back-end and the user will be logged in from their on.

That action will work something like this :

You'll have a special code which will be passed along the credentials so that the request is verified on their servers. That code can either be a static predefined code or it can be generated on minute/hour/day basis with the same algorithm on both sites.

The function that you'd be asking to make for you will be like this:

Rails v3 and v4:

This action will be POST only.

#I'm supposing 'protect_from_forgery' is already done in theirsite.com
class ApplicationController < ActionController::Base
    protect_from_forgery
end

#changes to be made are here as follows
class SomeController < ApplicationController
    skip_before_filter :verify_authenticity_token, only: [:login_outside] #this turns off CSRF protection on specific actions

    def login_outside
        if(#check special code here)
            #Their login logic here
        end
    end
end

Check this link for further information on skipping CSRF protection in Rails

Rails 4 RequestForgeryProtection

like image 137
Jagjot Avatar answered Oct 06 '22 00:10

Jagjot


This shouldn't be too hard to do.

You need to send an ajax GET request to their signup page, copy the authenticity_token with javascript, and then send an ajax POST to the actual log in route that creates a session with the right credentials and authenticity_token.

One tricky part is finding out their log in route. Try /sessions/new or perhaps they have the url in the form, so look at the html there. Good luck!

The other tricky part is knowing how the parameters are usually sent. Check out the form's html. If all the input tags have user_ before their name's then you'll need to structure your parameters similarly; i.e. user_email, user_password.

It's entirely possible to fetch the crsf token and submit your own form (because a log-in page is accessible to anyone!). However, it'll be difficult to know the details of their arrangement. The guessing and checking isn't too bad of an options (again, /sessions/new is how I route my log in; you should also try your route to see if they have a similar one.)

If that doesn't work, try taking a look at their github account! It's very possible they haven't paid $7 a month and it's open to the public. You will easily be able to view their routes and parameter parsings that way.

Good luck!

like image 23
Kites Avatar answered Oct 06 '22 01:10

Kites