About Me

Showing posts with label CRSF. Show all posts
Showing posts with label CRSF. Show all posts

Friday, 27 April 2012

Paper: Preventing Cross-Site Request Forgery (CSRF)

---[ 0x01: Introduction ]

I already dealt with the Cross Site Request Forgery topic, but not too deep regarding the possible solutions that web developers should adopt.
In these days i've been deeply involved in this topic during the coding of a distributed web application which should warrant a good level of security for user and most of all for the system's administrators (who are not that smart though their tasks :P).

Considering this situation i had to consider each aspect and each possible attack attempts that the applications could eventually suffer.

The one that gave me most problems to apply has been the Session Riding (or CSRF, call it as you prefere) because there is no 100% certain way to prevent that due to the concept that the attack fully stands on the users' credentials.

If you don't really know what Session Riding is you should read the previous paper reachable at the following link:
http://www.playhack.net/view.php?id=30
-----------------------------------------------------------------------------[/]



---[ 0X02: Possible Solutions ]
Ok, from here i must assume that you quite deeply know how a Session Riding attack should work out :P
Let's just have a little and fresh resume..

Consider that a trusted user is logged into a website which permits him to accomplish some important or confidential actions, an attacker wants to get over a possible login attack (which often will be voided) and disfrut the opened session of the user in order to realize some crafted actions.

The attacker in order to hijack the user's session will craft an appropriate web page which will hide a javascript function that re-create an original form but with fixed values, then he'll make the victim visit that page which on load will submit the form to the remote action page which will accomplish the request secretely (without the victim's aknowledge) confying on the user's trusted credentials.

This is a as quick as simple explaining of how a Session Riding attack would work out, the important question now is "How do i prevent my users to be victims of that?".

Now you would probably consider the following solutions:
- Check some cookies credentials
- Check the HTTP Referer
- Use a CAPTCHA

With some tryouts you'll realize that these are not the most proper solutions to adopt, let's see why one by one.
-----------------------------------------------------------------------------[/]


------[ 0x03a: Cookies Hashing ]
This first one could be a very simple and quick solutions to this problem because the attacker should not be aware of the victim's cookies contents, and cannot craft then a proper workaround.

An implementation of this solutions would work out in a way like following.
In some login file we create the Cookie related to the current session:
     <!-- login.php -->
     <?php
     // Cookie value
     $value = "Something from Somewhere";
     // Create a cookie which expires in one hour
     setcookie("cookie", $value, time()+3600);
     ?>
     <!-- EOF -->


We use an hashing of the Cookie to make the form verified
     <!-- form.php -->
     <?php
     // Hash the cookie
     $hash = md5($_COOKIE['cookie']);
     ?>
     <form method="POST" action="resolve.php">
          <input type="text" name="first_name">
          <input type="text" name="last_name">
          <input type="hidden" name="check" value="<?=$hash;?>">
          <input type="submit" name="submit" value="Submit">
     </form>
     <!-- EOF -->


And the action script would be something like following:
     <!-- resolve.php -->
     <?php
     // Check if the "check" var exists
     if(isset($_POST['check'])) {
          $hash = md5($_COOKIE['cookie']);
          // Check if the values coincide
          if($_POST['check'] == $hash) {
               do_something();
          } else {
               echo "Malicious Request!";
          }
     } else {
          echo "Malicious Request!";
     }
     ?>
     <!-- EOF -->


Actually this would be a fine solution to CSRF if we wouldn't consider the fact that the user's cookie are a way easy to retrieve disfruting some XSS flaw in the website (that we previousy saw they are not a rarity :D). It would be more secure if we create and destroy a random cookie for each form request that the user makes, but it wouldn't be very comfortable.
-----------------------------------------------------------------------------[/]



------[ 0x04b: HTTP Referer ]
The easiest way to check if the incoming requests are trusted and allowed, is to disfrut the HTTP Referer and check if they come from the same website or from a remote malicious page: this would be a great solution, but it falls due to the possibility to spoof the referers and make them appear to be corrects.

Let's see why it's not a proper solution..
The following code shows an implementing example of HTTP Referer:
     <!-- check.php -->
     if(eregi("www.playhack.net", $_SERVER['HTTP_REFERER'])) {
          do_something();
     } else {
          echo "Malicious Request!";
     }
     <!-- EOF -->

     

This check can be easily bypassed forging a fake HTTP Referer from the attacker's script using something like:
     header("Referer: www.playhack.net");
Or any other way to forge the Headers to be sent from the malicious script.

Since the HTTP Referer is sent by the browser and not controlled by the server you should never consider this variable as a trusted source!
-----------------------------------------------------------------------------[/]



------[ 0x05c: CAPTCHA Image ]
Another idea that came out in order to solve this issue is to use a random CAPTCHA image in every form which require the user to type in a textbox the generated string and with that verify the integrity of the submitted datas and the credentials of the user.

This solutions has been discarded some time ago due to the possibility to retrieve the captcha image using the so called MHTML bug, which affected several versions of Microsoft Internet Explorer.

You can find all the specific informations about this vulnerability from the Secuniawebsite:
http://secunia.com/advisories/19738/

Here's an extract from the Secunia's explanation of the bug:
"The vulnerability is caused due to an error in the handling of redirections for URLs with the 'mhtml:' URI handler. This can be exploited to access documents served from another web site."

In the same page you can find also a web test made from Secunia Staff.

Actually this bug is known to be solved with several patches released by Microsoft for Windows XP and Windows Vista and with the release 6.0 of their own browser Internet Explorer.

Even if actually it appears to be secure, the times brought to others possible and theoretically more reliable solutions.
-----------------------------------------------------------------------------[/]



---[ 0x06: One-Time Tokens ]
Now let's explain the final solution i decided to adopt for my job: after having dealt with all of these unreliable techniques i tried to write something different and probably more effective.

In order to make the webforms safe from Session Riding (CSRF) i decided to make the checking free from any kind of item that could be spoofed, retrieved or faked.

So i needed to create some one-time tokens that cannot be guessed or retrived in any way and that after having accomplished their task would have been destroyed.

Let's start from the token value generation:
     <!-- start function -->
     <?php
     function gen_token() {
          // Generate the md5 hash of a randomized uniq id
          $hash = md5(uniqid(rand(), true));
          // Select a random number between 1 and 24 (32-8)
          $n = rand(1, 24);
          // Generate the token retrieving a part of the hash starting from
          // the random N number with 8 of lenght
          $token = substr($hash, $n, 8);
          return $token;
     }
     ?>
     <!-- EOF -->


The uniqid() PHP function allows the web developer to get a unique ID from the current time in microseconds, which is quite good in order to retrieve a value that won't be repeated again.

We retrieve the MD5 hashing of that ID, and then we select 8 characters from that hashing starting from a random number <=24 (strlen($hash)-8).

The returned $token variable will retrieve an 8-long randomized token.

Let's now generate a Session Token which will be used later for the last check:
     <!-- start function -->
     <?php
     function gen_stoken() {
          // Call the function to generate the token
          $token = gen_token();
          // Destroy any eventually Session Token variable
          destroy_stoken();
          // Create the Session Token variable
          session_register(STOKEN_NAME);
          $_SESSION[STOKEN_NAME] = $token;
     }
     ?>
     <!-- EOF -->


With this function we call the gen_token() function and use the returned token to copy his value into a new $_SESSION variable.

Now let's see the function that will start the whole mechanism and that generates the hidden input for our form:
     <!-- start function -->
     <?php
     function gen_input() {
          // Call the function to generate the Session Token variable
          gen_stoken();
          // Generate the form input code
          echo "<input type=\"hidden\" name=\"" . FTOKEN_NAME . "\"
               value=\"" . $_SESSION[STOKEN_NAME] . "\">\n";
     }
     ?>
     <!-- EOF -->

   
As we can see this function just call the gen_stoken() function and create the HTML code for the hidden input that will be included in the web form.

Let's now take a look to the function that make the check of the Session Token with the submitted hidden input:
     <!-- start function -->
     <?php
     function token_check() {
          // Check if the Session Token exists
          if(is_stoken()) {
               // Check if the request has been sent
               if(isset($_REQUEST[FTOKEN_NAME])) {
                    // If the Form Token is different from Session Token
                    // it's a malicious request
                    if($_REQUEST[FTOKEN_NAME] != $_SESSION[STOKEN_NAME]) {
                         gen_error(1);
                         destroy_stoken();
                         exit();
                    } else {
                         destroy_stoken();
                    }
               // If it isn't then it's a malicious request
               } else {
                    gen_error(2);
                    destroy_stoken();
                    exit();
               }
          // If it isn't then it's a malicious request
          } else {
               gen_error(3);
               destroy_stoken();
               exit();
          }
     }
     ?>
     <!-- EOF -->


This function check the existence of the $_SESSION[STOKEN_NAME] and of $_REQUEST[FTOKEN_NAME] (i used the $_REQUEST method in order to accept both GET and POST methods from the form) and check if their values are the same: if they are the submitted form is authorized.

The important point of this function is that at every concluding step the tokens get destroyed and will be recreated only at next web form page call.

The use of these functions is really simple we just need to just add some additional PHP instructions.

This is the webform:
     <!-- form.php -->
     <?php
          session_start();
          include("functions.php");
     ?>
     <form method="POST" action="resolve.php">
          <input type="text" name="first_name">
          <input type="text" name="last_name">
          <!-- Call the function to generate the hidden input -->
          <? gen_input(); ?>
          <input type="submit" name="submit" value="Submit">
     </FORM>
     <!-- EOF -->

   
And this is the resolving script:
     <!-- resolve.php -->
     <?php
          session_start();
          include("functions.php");
        
          // Call the function to make the check
          token_check();
        
          // Your code
          ...
     ?>
     <!-- EOF -->

   

As you can see is really simple to implement such a check and it should protect your users from being hijacked by attackers and avoid to get your data compromised.
-----------------------------------------------------------------------------[/]



---[ 0x07 Conclusions ]
Let's conclude this short paper saying that there is no 100% way to be secure that your web application is completely safe, but you can start avoiding the most common attacking techniques.

Another point that i'd like to make you focus on is that a web developer SHOULD NOT forget of general applications faults (like XSS Browser Bugs ecc..), it would be a great mistake not considering them as a potential threat for your users: you should always keep in mind everything that could compromise your application's integrity, security and interoperability.

Cya!

nexus

(The above PHP codes were taken from the Seride project, hosted at http://projects.playhack.net/project.php?id=3)

-----------------------------------------------------------------------------[/]


\======================================[EOF]=====================================/

Thursday, 26 April 2012

Paper: Cross-Site Request Forgery: the Sea Surf

---[ 0x01: Introduction ]
Today we talk about Cross Site Request Forgery (also known as XSRF) abbreviated in CSRF, from which pronounce has come the friendly name "Sea Surf" ;)
Following the previous papers on Cross Site Scripting written by me, i thought it was an obvious step to deal with this theme: here i am then!

This kind of vulnerability, which is very common and understimated, permits to make a victim user to send any kind of HTTP request to a website in which he is logged in and trusted in some way.

In this way the attacker, forging some malicious HTML or JavaScript code, uses an opened session of the victim to make HIM doing actions, which really  complicates the identification of a CSRF attack.

This Session Riding could easily be taken in action with markup languages (such as Blog's and Wiki's syntax) and BBcode too.
-----------------------------------------------------------------------------[/]



---[ 0x02: About Authentications ]
Commonly when a user logs into a trusted website, the authentication system will flag this person with a "token" that tells to the website that the current user is authed and authorized to visit some reserved pages and services.

These "tokens" are realized with the creations of Cookies and Sessions, commonly generated with some hashed or encoded number , which strictly identify a single user.

Anytime this user logs into the website with his own credentials he will be flagged and a new session will be generated, and meanwhile an attacker could easily makes some unauthorized actions in the "ward" of that website ;)

It could looks like something quite un-dangerous, because only an idiot user will accept any kind of request that will disfrut his own authentication: great mistake! Don't ever understimate the power of a sweet Cookie! :P

Cookies are the aim of the most XSS attacks because permits an instant access to any kind of confidential and private service an user has privileges on: the CSRF is even more powerful, because disfruts the current session and cannot be avoided easily if the website doesn't provide very short temporary cookies.
-----------------------------------------------------------------------------[/]



---[ 0x03: Difference between XSS and CSRF ]
Actually, what's the real difference between XSS and CSRF? They look very similars!

As a matter of fact they're quite similars, but there's a core difference that makes the two vulnerabilities strictly opposed eachothers.

In the XSS vulnerabilities the USER trusts the WEBSITE's integrity, and gets  tricked to give direct informations to the ATTACKER (with cookie grabbing of fake logins for example).

In the CSRF vulnerabilities is the WEBSITE that trusts in the USER's requests and accomplish any kind of action that comes from his flagged authentication in order to get some advantages to the ATTACKER.

The Cross Site Request Forgery situation can be resumed with this graph:
                      
                           trusted <-----flag-----.
 .----------.          .------.           .---|-----.
 | ATTACKER |__________| USER |___________| WEBSITE |
 `----------`  tricks  `------` (request) `---------`
       |           \_ _ _ _ _ _ _ _/          |
       |                 |
       `--------------------------------------`
the website accomplishes the request


As we can see the situation is opposed to the XSS' one, the website (trusting the authentication and the authorizations of the user) just accomplishes the request that are sent to him, which are obscured to the USER's awareness.

The important point of this attack is that the request to the website is sent by the USER, not the ATTACKER: this makes the vulnerability more dangerous.
-----------------------------------------------------------------------------[/]


---[ 0x04: Get deep in CSRF ]
Okay, now that we got a general idea of what CSRF is, let's try to get into some simple examples.

Assure that for example a user is subscribed into a website that provide some particular services, maybe which even schedule some money transactions: when the user logs in, the server will create a cookie or a session that flags the user as authed and authorized to access to his own private pages.

Assure also that the website is maybe a e-banking service and it provides an HTML form which perform money transactions, and the code will look like:

<!-- scratch of a form -->
<form method="POST" action="sendmoney.php" name="sendmoney">
<div>How much: <input type="text" name="cash"></div>
<div>To: <input type="text" name="toname"></div>
<div>ABI: <input type="text" name="toabi"></div>
<div>CAB: <input type="text" name="tocab"></div>
<div>CIN: <input type="text" name="tocin"></div>
<div><input type="submit" name="submit" value="Buy"></div>
</form>
<!-- EOF -->


Through this form the user could transfer some money to the target bank account.
Ok, it's really a stupid thing and quite impossible to be found right that, but it's only to make you understand the thing more clearly :P don't complain for that please!

Ok, when the user will submit the values of the form the script sendmoney.php will execute the query and make the e-banking system accomplish his request of transfer.
Maybe the script will look like:

/* sendmoney.php */
<?
session_start();
if(isset($_REQUEST['cash']))
$cash = $_REQUEST['cash'];
else
die("Specify the amount of money");
if(isset($_REQUEST['toname']))
$toname = $_REQUEST['toname'];
else
die("Specify a recipient");
if(isset($_REQUEST['toabi']))
$toabi = $_REQUEST['toabi'];
else
die("Specify the ABI");
if(isset($_REQUEST['tocab']))
$tocab = $_REQUEST['tocab'];
else
die("Specify the CAB");
if(isset($_REQUEST['tocin']))
$tocin = $_REQUEST['tocin'];
else
die("Specify the CIN");

// This function safely send the money to the target
send_money($cash, $toname, $toabi, $tocab, $tocin);

?>
/* EOF */


Consider that this script is well written and the send_money() sanitizes all the variables that are submitted to him, the transfer will be finally accomplished.

In this particular case the use of REQUEST global variable allows to an attacker to disfrut the GET method in order to trick the user and steal his money :)

If the user is authed in, as we previously said, an attacker could provide to the user a webpage or an image which will look like something like this:

<!-- coolthing.html -->
<html>
<head><title>Cool Thing</title></head>
<body>
<img src="http://bankhost.com/sendmoney.php?cash=ALL&toname=ME&toabi=
          123456&tocab=123456&tocin=X">
</body>
</html>
<!-- EOF -->


Actually, if the user invited to visit this page is contemporary logged into the "bankhost.com" website, the image loaded will send an HTTP request to that website asking him to accomplish that transaction: the fact is that the transfer will be formerly commanded from the user himself.

Ok.. this is not really a good way for managing the transaction: the REQUEST global is not that safe, most probably the script sendmoney will use the POST variables instead, because they may think that it would be more secure.
Obviously it is not.

Consider that the coolthing.html file will look instead like:

<!-- coolthing.html -->
<html>
<head>
<title>Cool Thing</title>
<script>
stealMoney() {
iframe = document.frames["stealmoney"];
iframe.document.steal.submit();
}
</head>
<body onload="stealMoney()">
<div><img src="reallyc00landfunnypicture.jpg"></div>
<iframe name="stealmoney" display="none">
<form method="POST" name=" steal"
action="http://bankhost.com/sendmoney.php">
<input type="hidden" name="cash" value="ALL">
<input type="hidden" name="toname" value="ME">
<input type="hidden" name="toabi" value="123456">
<input type="hidden" name="tocab" value="123456">
<input type="hidden" name="tocin" value="X">
</form>
</iframe>
</body>
</html>
<!-- EOF -->


As we can see this page's appereance is composed only by the c00l picture loaded, but as an hidden action a crafted form in the iframe "stealMoney" will execute a request to the "bankhost.com" website, asking to the user's session to transfer the money to the targeted infos :)

This is just a stupid example, but through this you can imagine what kind of  entity this vulnerability can take.
-----------------------------------------------------------------------------[/]



---[ 0x05: Attack Points ]
Let's summarize then what happens creating a CSRF attack.
1- The attacker find a clueless user which is registered to a service vulnerable of CSRF
2- The attacker creates an html page which automatically send some requests to the vulnerable website
3- The victim logs into the website and get an opened session
4- The attacker provides the crafted html page to the victim
5- The victim visits that page
6- the HTTP request is sent and the malicious action accomplished :)

I think actually that it's quite easy to understand how much dangerous this vulnerability could is for a smart and malicious attacker which basically knows how to move his attacks.
-----------------------------------------------------------------------------[/]



---[ 0x06: Prevention ]
Now that we understood how a CSRF attack is taken in action let's try to analize how we could prevent and protect ourself from this kind of flaws.
In these months has been widely discussed how to prevent this kind of vulnerability but commonly without reaching any kind of fixed, stable and functional conclusion.
It has been talked about Unique Tokens, Captchas and others.. but i still think they still won't be enough for this or simply can not be implemented smartly.

Awaiting for better results i suggest all of you to consider to ask to the user the password again at least on sensitive pages (like e-commerce forms and stuff), in order to be sure that the session cannot be hijacked (actually.. if the attacker doesn't know the user password he couldn't do anything dangerous and on the other side if he really know the password, he doesn't require CSRF at all :P).

It's really easy to implement this security misure, adding a new field in the
form:

<!-- new scratch of the form -->
<form method="POST" action="sendmoney.php" name="sendmoney">
<div>How much: <input type="text" name="cash"></div>
<div>To: <input type="text" name="toname"></div>
<div>ABI: <input type="text" name="toabi"></div>
<div>CAB: <input type="text" name="tocab"></div>
<div>CIN: <input type="text" name="tocin"></div>
<div>Your passord: <input type="password" name="pass"></div>
<div><input type="submit" name="submit" value="Buy"></div>
</form>
<!-- EOF -->


And as it comes we'll put a check like following in the 'sendmoney.php' file:

/* scratch from sendmoney.php */
if(isset($_POST['pass']) && md5($_POST['pass']) == $mysql_row['pass']) {
...
} else {
die("You must specify a correct password!");
}
/* EOF */


In this way the CSRF attack attempts will be nullified if the attacker is not aknowledged of confidentials infos like the Password for example.

Other solutions like Unique Tokens based on PHP Sessions should be avoided because the attacker could bypass them.
-----------------------------------------------------------------------------[/]