Bypassing CSRF Protection in websites

Posted by Beleswar on Mon 24 January 2022

Hello Everyone! Hope you are doing fine during these insane days.. Ah, Chuck it, we all know nobody is fine, everybody just accepts! But I hope this makes your day somewhat easier :)

So, today's post would cover topics to get you started about CSRF protections and a solid method regarding how you can bypass them! So, what is CSRF protection? Where do I see it? What purpose does that serve? Let's dive right in!

What is CSRF?

CSRF stands for Cross Site Request Forgery. It is basically an attack, where the hacker does malicious actions on a website, by means of an authenticated user that the website trusts. Simply put, it is a malicious request (lets say to change the user's password) made by a hacker in a website, that he doesn't have access to, but through a user which has access to it.

How do Hackers use CSRF?

Some common CSRF attack actions are like, your email/password getting changed, or transferring more money to a different bank account or posting random stuffs in your social media feed etc. The hacker sends a forged malicious request on behalf of the authenticated user, and the website does not know that where is the request appearing from. Therefore, it grants the request which results in an unwanted action on the database (like password getting changed).

A legit user login request can be seen as:

username=admin&password=password&Login=Login&user_token=004fc0b9ee58345cfeeb5198b782bc63

Whereas a request made by an unauthorized hacker would look like:

username=admin&password=password&Login=Login

How does CSRF Protection works?

So websites and webapps don't want to you to perform a CSRF attack on them right. That is why they have something called as a authentication_token or user_token or csrf_token to protect against the CSRF attacks. Let's consider a scenario to see how these CSRF tokens work and their importance.

So, lets say Andrew is logged into his facebook account. He is using Chrome browser to log into facebook, and let's say his username is andrew and his password is private_andrew. Our hacker, Martin is taking a close look onto Andrew's life and wanting to hack into his facebook. So, lets say he generates a long file possible_credentials.txt, containing a list of his possible credentials like, andrew:andrew, andrew:Passw0rd!, andrew:private and so on.. These files can be easily generated through applications like crunch. So there is a good possibility that he generates andrew:private_andrew option in his file too. Now Martin tries to bruteforce these credentials in facebook login page, so that he finds the correct login credentials of Andrew. He opens up an application like Metasploit, and sets the target as facebook.com/login and USERPASS-FILE as possible_credentials.txt.

And Metasploit tries to login to facebook with every combination of the credentials (maybe in 1000s) in the file. At one point, it may show success in the andrew:private_andrew credential! So, what do you think? Is it all a long credential file that takes to hack people's accounts? Nope, this is where the CSRF protection comes to play. The facebook server does not listen to any login requests made by users, that do not have the correct authentication_token! This authentication_token is a long hash value (generally 32 characters long) that is generated by the server everytime the facebook/login page loads. So, no two authentication tokens are same at any point of time! And hence, only if this unique 32 character long token is sent everytime with the login credentials, then only the server responds to the request!

So, obviously we can not track the unique authentication token 1000 times (everytime a new credential test is done) and pass it with the credentials to the server. Hence, the facebook server won't even listen to the requests made by metasploit, even if it contains the correct credentials! So everytime we open the facebook/login page in our browser, we get an authentication token attached to our request, and that token is only valid for requests made by the browser in that particular session! Even if you reload the page, the token changes! So this is how the CSRF Protection works and prevents any unauthorized requests made to the server!

Bypassing CSRF Protection

Now comes the main question, for my cybersecurity mates! And this may be the reason you have visited this blog. Can we bypass this CSRF Protection?? The answer is yes, we can!. Protection exists doesn't mean its perfect! However, note that almost many real time servers like facebook or chrome, will block your IP if you make more than a particular number of requests to their page. So better watchout your bruteforce attempts there -.-

For this example, I am going to consider bypassing the DVWA Login Page. DVWA stands for Damn Vulnerable Web Application, & it might be the right platform for you to apply your skills legally xD. Setting up DVWA is easy and can be found here. After configuring it to your localhost, your 127.0.0.1/DVWA/ should look like this in a browser page.

dvwa-login-page
So, our aim is to bypass this login form and find the correct credentials for this page. Lets start by intercepting our request. You may use Burpsuite in your browser to capture the request everytime your page loads. So, Enter anything for username and password and press Login. The corresponding request in Burpsuite should look like this :

POST /login.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/login.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 88
Connection: close
Cookie: PHPSESSID=kmi2onkumadvnfor3bf5hspa4p; security=impossible
Upgrade-Insecure-Requests: 1

username=admin&password=password&Login=Login&user_token=004fc0b9ee58345cfeeb5198b782bc63

Let's analyze this request. We see that the request is of POST method. The cookie from the browser is PHPSESSID value. And finally the POST Data which is

username=admin&password=password&Login=Login&user_token=004fc0b9ee58345cfeeb5198b782bc63.

Notice the user_token value here? This shows that the site is CSRF protected and this is exactly the CSRF token we are looking for. The username and password can be obtained from the long list of credentials possible_credentials.txt and the Login value is constant. So, all we need is this user_token to get done. The value of user_token would be generated unique everytime a credential request is made, so how to extract it?

One method, and the most successful method, is to first send a GET request to 127.0.0.1/DVWA/login.php. In the response of the request, we will get the whole page of /login.php including all values of currently set variables. Bingo, here we will get our CSRF token. The response of your GET request would contain a part like this :

<form action="login.php" method="post">

    <fieldset>

            <label for="user">Username</label> <input type="text" class="loginInput" size="20" name="username"><br />


            <label for="pass">Password</label> <input type="password" class="loginInput" AUTOCOMPLETE="off" size="20" name="password"><br />

            <br />

            <p class="submit"><input type="submit" value="Login" name="Login"></p>

    </fieldset>

    <input type='hidden' name='user_token' value='306cb6206e79284a10099f3acd384f8c' />

    </form>

Here, we can apply a quick regex search to find our CSRF token. These tokens are generally of 32 characters length. So we can apply this regex : /\w{32}/ to extract this token easily and store it in a variable. Boom, then we send this variable's value as user_token along with username and password from the crunch file, as a POST method to 127.0.0.1/DVWA/login.php and yes! WE HAVE BYPASSED the CSRF PROTECTION!

Note, the length of these tokens can vary from page to page. In that case, you can count the length of the user_token from the initial request obtained in burpsuite and accordingly change your regex search. For example, to extract CSRF tokens of 16 character length, you can apply this regex search : /\w{16}/. Apart from this, there are other methods as well to bypass CSRF protection, but I personally didn't find them successful. But I'd leave the link here incase that helps you!

Hence, our total method to bypass CSRF protections can be boiled down to this:

  1. Use a GET request to the /login page to obtain the response headers.
  2. Extract the CSRF token using a regex search.
  3. Use a POST request to the /login page, passing the username, password, loginbtn and the CSRF token obtained above.
  4. Repeat this process using a bruteforcer, for every credentials, until you get the correct credential!
    Note: You just have to write the GET and POST requests once, the bruteforcer will execute steps 1, 2 and 3 sequentially for every credential and report you the correct one!

So, I hope this article helped you in some way and made your day easier! I have finished writing the module to bypass this dvwa_login page and I'll link the codes here soon for you to take a reference of how things work exactly! Until then, take care :)