Login Register
The stories and information posted here are artistic works of fiction and falsehood. Only a fool would take anything posted here as fact.


Introuction to Cross-Site Request Forgery filter_list
Author
Message
Introuction to Cross-Site Request Forgery #1
Cross-Site Request Forgery (CSRF)
aka one-click attack or session riding

I come across this vulnerability more than any other on security conscious websites its really easy to overlook and often not viewed critical as SQLi or XSS.

So what is CSRF? To quote OWASP:

Quote:CSRF is an attack which forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated

Basically, a CSRF attack allows you the attacker to cause victims to execute actions on a target application without their consent or knowledge. These actions vary depending on the application of course but it could for example be transferring money in a banking application, granting administrative privileges, bidding on an auction, etc.

CSRF exploits the design and normal use of cookies and authorization headers(HTTP Authentication). Once set cookies and authorization headers will be automatically sent by the browser with every request to the website that set them. The website can then use that information to authenticate a user.

For example a common practice is to create a session cookie for a user once they have logged it. Then store user information inside the users session allowing the website to authenticate the user without needing to enter the user and password with every request.

So if an attacker is able to cause a users browser to make a request to a particular application that request will appear to have legitimately originated from the user and not the attacker.

If you're not quite following perhaps an example will help.

Imagine your friend Alice has a bank account with SecureBank.com.

When transferring money on SecureBank.com the website shows you a form that asks for the from, to, and transfer_amount. Imagine this form submits a GET request. The target of that request might look something like this if Alice owned the account 11077771 and was transferring $100 to Bob with account number 1001101.

Code:
https://securebank.com/transfer.php?from=11077771&to=1001101&transfer_amount=100

Now the bank is secure it makes sure you own the account you are trying to transfer from and they sanitize input to protect against XSS and SQL Injection, but this request doesn't protect against CSRF request...

What would happen if you the attacker were able to get Alice to click the following link:


Code:
https://securebank.com/transfer.php?from=11077771&to=31333337&transfer_amount=99999

Alice's browser which is logged into the bank would this access this transfer page, check if Alice own the account 11077771 which she does and then it would transfer $99,999 to the attack owner account 31333337.

So hopefully that makes sense; any request that does not contain any unique information can be replayed like that.

Of course Alice is probably going to be suspicious if I tell her to click a link and it takes her unexpectedly to her bank account. So to be a little more stealthy you can cause the browser to make the request another way. Using images you can cause Alice's browser to request the securebank website.

Code:
<img src="https://securebank.com/transfer.php?from=11077771&to=31333337&transfer_amount=99999">

When the browser sees the above image tag it will make a request to the transfer url again giving us Alice's money all you need to do is get Alice to visit your page with the image tag, script tag, css, or whatever other means you've selected to get cause the browser to make the request.

----------

So now you might be thinking "but I thought most forms used POST instead of GET, does that make them secure"...no it does not make them secure. It just makes them a little harder to exploit.

Lets imagine instead of a simple get request transfer.php it was a POST request that looked something like:

Code:
POST /transfer.php HTTP/1.1 Host: securebank.com User-Agent: My Awesome Webbrowser Cookie: phpsessid=SSDFE23UN5VYS8P0JE2V6SG&lastvisit=1398310259&user=Alice Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 47 from=11077771&to=31333337&transfer_amount=99999

So now its a POST request, you can't craft an <img> tag to make that request so what can you do?

You can craft a form! Imagine the following HTML:

Code:
<form action="https://securebank.com/transfer.php" method="POST"> <input type="hidden" name="from" value="11077771" /> <input type="hidden" name="to" value="31333337" /> <input type="hidden" name="transfer_amount" value="99999" /> <input type="submit" value="Win Lottery" /> </form>

Now all you need to do is trick Alice into visiting your page and clicking that "Win Lottery" button. Naturally that is a lot of work, getting her to visit will be hard enough so instead you can kindly submit the form for Alice automatically by adding the following javascript to your attack page.

Code:
<script> document.forms[0].submit(); </script>


This leads to a similar problem with the direct link from earlier though, don't you think Alice would be suspicious if she visits your page and is redirected to her bank? We need to hide this request from her. Fortunately this is very easy to do as you can specify a target for the form.

Code:
<form action="https://securebank.com/transfer.php" method="POST" target="hide"> <input type="hidden" name="from" value="11077771" /> <input type="hidden" name="to" value="31333337" /> <input type="hidden" name="transfer_amount" value="99999" /> <input type="submit" value="Win Lottery" /> </form> <script> document.forms[0].submit(); </script> <iframe name="hide" style="border:0px;width:1px;height:1px;overflow:hidden"></iframe>

The above code will automatically submit our form and the results will be displayed in our 'hidden' iframe allowing the request to be made without Alice knowing. ^_^

The above cases will cover 99% of all vulnerable cases but not all of them. Another common case is AJAX requests that will send the data as XML or JSON and set the Content-Type header to and then verify the content type header is the appropriate value. These are tricky to exploit because though you can't set that header in POST request with a form. Instead it needs to be set with javascript...but javascript requests are limited to the same domain. Hence the target site can set the header but your attack site cannot.

You can however get around this and some other header checks(like refer) using ... flash. Flash is able to cause the browser to make cross-domain requests with custom headers/verb(PUT, DELETE, etc). The knowledgeable among you might be thinking that to make requests with flash the target site needs to have a crossdomain.xml allowing it and that is kinda true. Except you can still make the request, you just can't read the response with flash.

That said the flash based CSRF is more complicated so I'll save that for another tutorial if there is interest.

-------------

So by now I hope you are wondering how to protect yourself from such attacks. The answer is very simple:

1. Do not make stateful changes with a GET request. This is a violation of the HTTP spec, URLs get cached by the browser revealing potentially sensitive information and its just a bad idea.
2. Include a unique token with every request. This unique token should be validated with every POST request and should only be valid for one request.

https://www.owasp.org/index.php/Cross-Si...heat_Sheet


And while we are examining CSRF requests lets consider one real life example. If you look below this post you should see a button called 'Thank'. Clicking that button with Javascript enabled will result in a request something like the follow:

Code:
GET /showthread.php?action=thank&tid=34161&pid=186191 HTTP/1.1 Host: www.hackcommunity.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/28.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 Cookie: __cfduid=*; mybb[lastvisit]=*; mybb[lastactive]=*; mapovifog=*; mybbuser=*; cf_clearance=*; sid=* Connection: keep-alive

Notice anything wrong with that request?

There is no unique value, its GET, and it makes a stateful change. So what happens if I were to include a BBCode image to that URL in my post like this?

[Image: showthread.php?action=thank&tid=34161&pid=186191]

Well...it might just force your account to thank this post ^_^...Refresh the page to see if your name appears as one of the users who has thanked this post.

EDIT: bluedog fixed the CSRF on June 14th: http://www.hackcommunity.com/Thread-Than...m-reworked
(This post was last modified: 06-14-2014, 07:42 PM by miiike980.)

Reply







Users browsing this thread: