CSRF Attacks
These write-ups draw on labs developed by Wenliang Du at Syracuse University and Collin Howland, Faith Letzkus, Julio Trujillo, and Steve Cole at Washington University in St. Louis.
Lab setup
In this lab, we will use three websites. The first website is the vulnerable Elgg site accessible at www.seed-server.com. The second website is the attacker’s malicious web site that is used for attacking Elgg. This web site is accessible via www.attacker32.com. The third website is used for the defense tasks, and its hostname is www.example32.com. We use containers to set up the lab environment.
There are several user accounts on the Elgg server; the user name and passwords are given in the following:
UserName | Password |
---|---|
admin |
seedelgg |
alice |
seedalice |
boby |
seedboby |
charlie |
seedcharlie |
samy |
seedsamy |
Elgg setup
Just like our XSS lab, we will use Elgg — but with different security features turned off (the token and ts fields), so that we can successfully launch CSRF attacks. * We use two containers, one running the web server (10.9.0.5) , and the other running the MySQL database (10.9.0.6).
-
We use another container (10.9.0.105) for the attacker machine, which hosts a malicious website. The Apache configuration for this website is listed in the following:
<VirtualHost *:80> DocumentRoot /var/www/attacker ServerName www.attacker32.com </VirtualHost>
Since we need to create web pages inside this container, for convenience, as well as for keeping the pages we have created, we have a mounted folder (
csrf/attacker
on the hosting VM) to the container’s/var/www/attacker
folder, which is the DocumentRoot folder in our Apache configuration. Therefore, the web pages we put inside the attacker folder on the VM will be hosted by the attacker’s website. You should have access to basic code templates inside this folder.
DNS Configuration
We need to add the following entries to the /etc/hosts
file, so these hostnames are mapped to their corresponding IP addresses. You need to use the root privilege to change this file (using sudo). These hostnames might have already been mapped to different IP addresses, if that is the case, remove old entries and put in the following mappings:
10.9.0.5 www.seed-server.com
10.9.0.5 www.example32.com
10.9.0.105 www.attacker32.com
Using HTTP HeaderLive, and Web Developer Tools
Just like we did in Lab2, we need to know what a legitimate HTTP request looks like and what parameters it uses, etc. This will be useful in our CSRF attacks, when we forge HTTP requests.
In the Web Developer Tools
the Network tool in particular will be really useful. You can get to this using:" Tools → Web Developer → Network
.
Javascript Debugging: Similar to Lab2, you might also want to debug Javascript. To do so, go to Tools → Web Developer → Web Console
, and click the JS tab. Click the downward pointing arrowhead beside JS
and ensure there is a check mark beside Error (to show errors). If you are also interested in Warning messages, click Warning. See Figure 5 below.
The default font size of Web Developer Tools window is quite small. It can be increased by focusing click anywhere in the Network Tool window, and then using Ctrl and + button. |
Task 1: CSRF Attack using a GET Request
In this task, we will get Samy, a malicious attacker to launch a CSRF attack on Alice, such that Alice without realizing, adds Samy as a friend. To do so, Samy sends Alice an URL (via an email or a posting in Elgg); Alice, curious about it, clicks on the URL, which leads her to Samy’s web site: www.attacker32.com. Pretend that you are Samy, describe how you can construct the content of the web page, so as soon as Alice visits the web page, Samy is added to the friend list of Alice (assuming Alice has an active session with Elgg).
To add a friend to the victim, we need to identify what the legitimate Add-Friend HTTP request (a GET request) looks like. We can use the "HTTP Header Live" Tool to do the investigation. In this task, you are not allowed to write JavaScript code to launch the CSRF attack. Your job is to make the attack successful as soon as Alice visits the web page, without even making any click on the page (hint: you can use the img
tag, which automatically triggers an HTTP GET request).
Elgg has implemented a countermeasure to defend against CSRF attacks. In Add-Friend
HTTP requests, you may notice that each request includes two the CSRF defense parameters, elgg_ts
and elgg_token
.
We have disabled the countermeasure for this lab, so there is no need to include these two parameters in the forged requests.
Task 2: CSRF Attack using a POST Request
After adding himself to Alice’s friend list, Samy wants to do something more. He wants Alice to say “Samy is my Hero” in her profile, so everybody knows about that. Alice does not like Samy, let alone putting that statement in her profile. Samy plans to use a CSRF attack to achieve that goal.
One way to do the attack is to post a message to Alice’s Elgg account, hoping that Alice will click the URL inside the message. This URL will lead Alice to your (i.e., Samy’s) malicious web site www.attacker32.com, where you can launch the CSRF attack.
The objective of your attack is to modify the victim’s profile. In particular, the attacker needs to forge a request to modify the profile information of the victim user of Elgg. Allowing users to modify their profiles is a feature of Elgg. If users want to modify their profiles, they go to the profile page of Elgg, fill out a form, and then submit the form—sending a POST request—to the server-side script /profile/edit.php
,
which processes the request and does the profile modification.
The server-side script edit.php accepts both GET and POST requests, so you can use the same vulnerability in Task 1 to achieve the attack. However, in this task, you are required to use the POST request. Namely, attackers (you) need to forge an HTTP POST request from the victim’s browser, when the victim is visiting their malicious site. Attackers need to know the structure of such a request. You can observe the structure of the request, i.e., the parameters of the request, by making some modifications to the profile and monitoring the request using the "HTTP Header Live" tool. Unlike HTTP GET requests, which append parameters to the URL strings, the parameters of HTTP POST requests are included in the HTTP message body as follows. See the content between the two star symbols below:
http://www.seed-server.com/action/profile/edit
POST /action/profile/edit HTTP/1.1
Host: www.seed-server.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:23.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://www.seed-server.com/profile/elgguser1/edit
Cookie: Elgg=p0dci8baqrl4i2ipv2mio3po05
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 642
__elgg_token=fc98784a9fbd02b68682bbb0e75b428b&__elgg_ts=1403464813 ✰
&name=elgguser1&description=%3Cp%3Iamelgguser1%3C%2Fp%3E
&accesslevel%5Bdescription%5D=2&briefdescription= Iamelgguser1
&accesslevel%5Bbriefdescription%5D=2&location=US
...... ✰
Now that you have seen the structure of the request, you need to be able to generate the request from your attacking web page using JavaScript code. To help you write such a JavaScript program, we provide a sample code in the following code snippet. You can use this sample code to construct your malicious web site for the CSRF attacks. This is only a sample code, and you need to modify it to make it work for your attack.
<html>
<body>
<h1>This page forges an HTTP POST request.</h1>
<script type="text/javascript">
function forge_post()
{
var fields;
// The following are form entries need to be filled out by attackers.
// The entries are made hidden, so the victim won’t be able to see them.
fields += "<input type=’hidden’ name=’name’ value=’****’>";
fields += "<input type=’hidden’ name=’briefdescription’ value=’****’>";
fields += "<input type=’hidden’ name=’accesslevel[briefdescription]’
value=’2’>"; [Line: 1]
fields += "<input type=’hidden’ name=’guid’ value=’****’>";
// Create a <form> element.
var p = document.createElement("form");
// Construct the form
p.action = "http://www.example.com";
p.innerHTML = fields;
p.method = "post";
// Append the form to the current page.
document.body.appendChild(p);
// Submit the form
p.submit();
}
// Invoke forge_post() after the page is loaded.
window.onload = function() { forge_post();}
</script>
</body>
</html>
In Line 1, the value 2 sets the access level of a field to public. This is needed, otherwise, the access level will be set by default to private, so others cannot see this field.
Copy-pasting the above code will cause errors. You should write the code in your own file. |
Task 3: CSRF Defense
CSRF is not difficult to defend against. Initially, most applications put a secret token in their pages, and by checking whether the token is present in the request or not, they can tell whether a request is a same-site request or a cross-site request. This is called secret token approach.
Task 3A: Enable Secret Tokens
-
Elgg adds security token and timestamp to all the HTTP requests. The following HTML code is present in all the forms where user action is required. These are two hidden fields; when the form is submitted, these two hidden parameters are added to the request:
<input type = "hidden" name = "__elgg_ts" value = "" /> <input type = "hidden" name = "__elgg_token" value = "" />
-
Elgg also assign the values of the security token and timestamp to JavaScript variables, so they can be easily accessed by the JavaScript code on the same page.
elgg.security.token.__elgg_ts; elgg.security.token.__elgg_token;
-
The secret token and timestamp are added to Elgg’s web pages by the
vendor/elgg/elgg/views/default/input/securitytoken.php
module. The code snippet below shows how they are dynamically added to web pages.$ts = time(); $token = elgg()->csrf->generateActionToken($ts); echo elgg_view(’input/hidden’, [’name’ => ’__elgg_token’, ’value’ => $token]); echo elgg_view(’input/hidden’, [’name’ => ’__elgg_ts’, ’value’ => $ts]);
-
Secret token generation Elgg’s security token is a hash value (md5 message digest) of the site secret value (retrieved from database), timestamp, user session ID and random generated session string. The code below shows the secret token generation in Elgg (in
vendor/elgg/elgg/engine/classes/Elgg/Security/Csrf.php
)./** * Generate a token from a session token (specifying the user), * the timestamp, and the site key. */ public function generateActionToken($timestamp, $session_token = ’’) { if (!$session_token) { $session_token = $this->session->get(’__elgg_session’); if (!$session_token) { return false; } } return $this->hmac ->getHmac([(int) $timestamp, $session_token], ’md5’) ->getToken(); }
-
Secret token validation. The elgg web application validates the generated token and timestamp to defend against the CSRF attack. Every user action calls the validate function inside
Csrf.php
, and this function validates the tokens. If tokens are not present or invalid, the action will be denied and the user will be redirected. In our setup, we added a return at the beginning of this function, essentially disabling the validation.public function validate(Request $request) { return; // Added for SEED Labs (disabling the CSRF countermeasure) $token = $request->getParam(’__elgg_token’); $ts = $request->getParam(’__elgg_ts’); ... (code omitted) ... }
Turn on the countermeasure To turn on the countermeasure, get into the Elgg container, go to the` /var/www/elgg/vendor/elgg/elgg/engine/classes/Elgg/Security` folder, remove the return statement from
|
When we launch the edit-profile attack while the countermeasure is enabled, the failed attempt will cause the attacker’s page to be reloaded, which will trigger the forged POST request again. This will lead to another failed attempt, so the page will be reloaded again and another forged POST request will be sent out. This endless loop will slow down your computer. Therefore, after verifying that the attack failed, kill the tab to stop the endless loop. |
Clickjacking
Clickjacking, also known as a “UI redress attack,” is an attack that tricks a user into clicking on something they do not intend to when visiting a webpage, thus “hijacking” the click. In this part of the project, , we will explore a common attack vector for clickjacking: the attacker creates a webpage that loads the content of a legitimate page but overlays one or more of its buttons with invisible button(s) that trigger malicious actions. When a user attempts to click on the legitimate page’s buttons, the browser registers a click on the invisible button instead, triggering the malicious action.
Examples of Clickjacking
Before we get started with the lab I have some examples of clickjacking that you can download to your VM
# cp into your labs folder
$ cp /home/chaganti/public/cs88/projects/cj-examples.zip .
$ unzip cj-examples.zip
I’ll go through examples in the lab. === Lab Setup
For this part of the project, we will use two websites. The first is the vulnerable homepage of the fictional business “Alice’s Cupcakes”, accessible at http://www.cjlab.com
. The second is the attacker’s malicious web site
that is used for hijacking clicks intended for the Alice’s Cupcakes page, accessible at http://www.cjlab-attacker.com
.
We use docker containers to set up the web servers, one running the website for Alice’s Cupcakes (the “defender”, with IP address 10.9.0.5) , and the other running the website for the attacker (with IP address 10.9.0.105).
The Defender Container
The Defender container. The website for Alice’s Cupcakes is hosted on an Apache web server. The website setup is included in apache defender.conf inside the defender image folder. The configuration specifies the URL for the website and the folder where the web application code is stored. The configuration also contains placeholders for HTTP response headers returned by the server (commented out), which will be filled in during the course of the lab as a defense countermeasure.
<VirtualHost *:80>
DocumentRoot /var/www/defender
ServerName www.cjlab.com
# Header set <Header-name> "<value>";
# Header set Content-Security-Policy " \
# <directive> ’<value>’; \
# "
</VirtualHost>
Because we need to modify the defender’s web page inside this container, for convenience as well as to allow the modified files to persist beyond the containers, we have mounted a folder (cj/defender
on the hosting VM) to the container’s /var/www/defender
folder, which is the DocumentRoot folder
in our Apache configuration. Therefore any files we modify inside the defender folder on the VM will be seen as modified by the defender’s web server on the container.
The Attacker Container
The Attacker container. The attacker’s website is also hosted on an Apache web server. The website setup is included in apache attacker.conf inside the attacker image folder. The Apache configuration for this website is as follows:
<VirtualHost *:80>
ServerName www.cjlab-attacker.com
DocumentRoot "/var/www/attacker"
DirectoryIndex attacker.html
</VirtualHost>
Because we need to modify the attacker’s web page inside this container, for convenience as well as to allow the modified files to persist beyond the containers, we have mounted a folder (cj/attacker
on the hosting VM) to the container’s /var/www/attacker
folder, which is the DocumentRoot folder
in our Apache configuration. Therefore any files we modify inside the attacker folder on the VM will be seen as modified by the attacker’s web server on the container.
Any time you make updates to the websites, you may need to clear the browser’s cache and/or rebuild and restart the containers for the change to be visible, depending on the scope of the change. |
DNS Configuration
We access the defender website and the attacker website using their respective URLs. To enable these hostnames to be mapped to their corresponding IP addresses, we need to add the following entries to the /etc/hosts
file on the VM. You need to use the root privilege to change this file (using sudo).
10.9.0.5 www.cjlab.com
10.9.0.105 www.cjlab-attacker.com
Test the Defender and Attacker sites
-
Test: defender: Build and start the containers, then navigate to the page
http://www.cjlab.com
on the VM. You should see a page for Alice’s Cupcakes, a fictional local bakery. If the whole site does not fit in your window, useCtrl + (minus key)
andCtrl + (plus key)
to zoom out and in respectively until the site fits. Note that the header and footer buttons on the site are just placeholders and do not contain live links. -
Test: attacker: Next, navigate to the page
http://www.cjlab-attacker.com
. You should see a single button which, when clicked, takes you to a page that tells you you’ve been hacked. In a real attack, this button could perform a variety of malicious actions. The goal of the attacker is to overlay this button onto a view of the defender’s webpage displayed on the attacker’s site, so that a victim user will inadvertently click the malicious button when they think they are clicking a button on the defender’s webpage.
Task 1: Copy that site!
In the defender folder, you will find the files comprising the website for Alice’s Cupcakes: index.html
and defender.css
. In the attacker folder, you will find the files comprising the attacker’s website: attacker.html and attacker.css
. You will be making changes to all of these files except defender.css
throughout this part of the project.
Our first step as the attacker is to add code to attacker.html
so that it mimics the Alice’s Cupcakes website as closely as possible. A common way to do this is with an HTML Inline Frame element (“iframe”).
An iframe enables embedding one HTML page within another. The src attribute of the iframe specifies the site to be embedded, and when the iframe code is executed on a page, the embedded site is loaded into the iframe |
Embed the defender’s site into the attacker’s site.
-
• Add an iframe HTML element in attacker.html that pulls from http://www.cjlab.com.
-
Modify the CSS in attacker.css using the height, width, and position attributes to make the iframe cover the whole page and the button overlay the iframe.
-
Hints:
-
Explicitly set the iframe to have no border.
-
Investigate the ‘absolute’ and ‘relative’ settings of the position attribute to determine which should be used.
-
-
Test your changes by navigating to the attacker’s website. (Remember that you may need to clear the browser’s cache and reload the page to see changes made after the initial load.)
Task 2: Let’s Get Clickjacking!
Basic clickjacking attack. Add code to the CSS specification of a “button” object given in attacker.css
to make the malicious button in attacker.html invisible. Position the button so that it covers the “Explore Menu” button within the iframe added in the previous Task. There are a variety of ways to accomplish this Task; we recommend using the CSS attributes margin-left, margin-top, color, and background-color. When this Task is complete, you will have a functioning clickjacking attack.
Task 3: Bust That Frame!
“Frame busting” is the practice of preventing a web page from being displayed within a frame, thus defending against the type of attack implemented in the previous Task. One way to bust frames is to include script code in the webpage source that prevents the site from being framed – that is, it prevents other sites from opening the webpage in an iframe. In this Task we will add script code to the defender’s webpage that ensures it is the topmost window on any page where it is being displayed, thus preventing buttons on an attacker’s page from being overlaid on top of it.
Write the frame-busting script. Open the file defender/index.html, which contains code for the Alice’s Cupcakes homepage. We would like to protect the homepage from clickjacking. Your task is to fill in the Javascript method called makeT hisF rameOnT op(). Your code should compare window.top and window.self to find out if the top window and the current site’s window are the same object (as they should be). If not, use the Location Object to set the location of the top window to be the same as the location of the current site’s window. This should be a simple method and take no more than a few lines of code. Test it out and confirm that your script successfully stops the clickjacker.
Task 4: Attacker Countermeasure (Bust the Buster)
Disable the frame-busting script. Now let’s explore how an attacker can create a workaround for frontend clickjacking defenses like frame busting. There are multiple workarounds, but one of the simplest in the current scenario is to add the sandbox attribute to the malicious iframe. Read more about the sandbox attribute on this page about iframes, then add the sandbox attribute to the iframe in attacker.html.
Your final presentation can choose to (but is not required to) answer the following questions:
|
Task 5: The Ultimate Bust
As we saw in the previous Task, front-end defenses such as frame busting can be directly circumvented by other front-end settings on the attacker’s webpage and are therefore not sufficient to prevent clickjacking. To prevent clickjacking attacks more comprehensively, we need to set up back-end (i.e. server-side) defenses.
Modern websites can cooperate with common browsers to provide such defenses. The front-end attacks presented in previous Tasks all rely on the ability of an attacker’s webpage code (running in a victim user’s browser) to fetch a benign website’s content before the benign webpage code has a chance to execute any front-end defenses.
To block this capability, special HTTP headers have been created that specify to browsers the circumstances under which a website’s content should or should not be loaded. By providing one of these HTTP headers with its response to a request for content, the website can instruct browsers to only display the content according to specific matching rules designed to exclude clickjacking attack scenarios. These headers are not part of the official HTTP specification, but are processed by many common browsers.
One such header is called “X-Frame-Options”, and a newer, more popular one is called “ContentSecurity-Policy”. This header can include a diverse set of key-value directives to implement a site’s Content Security Policy (CSP) with the intention of stopping many common attacks while perserving the desired content-sharing behavior of the site. The CSP header directive relevant for preventing clickjacking is “frame-ancestors” , which specifies the valid parents that may embed a page in a frame.
You can read more about the XFO attribute here, and more about CSPs here. Modify the defender’s response headers. Open the Apache configuration file for the defender’s website (apache defender.conf
in the defender’s image folder). Uncomment the lines that specify the HTTP response headers served with the page, and substitute appropriate text in order to prevent the clickjacking attack.
Specifically, set the X-Frame-Options (XFO) header to the value "DENY" and the Content-SecurityPolicy (CSP) header to contain the directive "frame-ancestors ‘none’ ".
Because you are making a change to the server’s configuration, you will need to rebuild and restart the containers for the change to take effect. |
Your final presentation should answer the following questions:
|
Learn more. There are other ways to perform clickjacking besides the one explored in this lab, and many possible malicious consequences beyond the ones suggested here. To learn more about clickjacking, visit the Open Web Application Security Project (OWASP) page on Clickjacking here. |