Greetings, cybersecurity enthusiasts! Myself Gaurav Raj (@thehackersbrain) In our previous article, we delved into the intricacies of CSRF attacks, uncovering their mechanics, their impact on web application security, and the potential risks posed to users. In this installment, we embark on a journey to explore various techniques for bypassing or identifying vulnerabilities within CSRF token validation functions. As you read further, we encourage you to leverage the knowledge gained to bolster your understanding and bug-hunting skills responsibly. It is paramount that you apply this knowledge only for ethical purposes and contribute positively to the realm of web security. Let’s dive in!
First, let’s talk about the common defenses against the CSRF attacks.
- CSRF tokens — A CSRF token can be aptly described as a sequence of unique and unpredictable characters, typically generated either randomly or derived from user-specific information using encryption or encoding techniques. This token is meticulously crafted by server-side applications and subsequently shared with the client. In scenarios necessitating authentication or authorization for actions, the server furnishes the token to the client and reciprocally the client conveys it back to the server to verify the request’s source. This meticulous process erects formidable barriers against potential attackers or adversaries, diligently safeguarding the application from unintended, malicious requests on behalf of unsuspecting users.
- SameSite Cookies — Samesite cookies, as previously elucidated, represent a pivotal browser security mechanism employed to govern the circumstances under which stored cookies within the browser are transmitted in cross-site connections or requests. In scenarios where requests entail the execution of sensitive operations, contingent upon authenticated and authorized session cookies, the judicious application of Samesite restrictions stands as a formidable line of defense.
- Referer-based Validation — In referer-based validation, the server checks the Referer header in incoming requests. If a request is expected to come from a specific source, the server can verify that the Referer header matches the expected source. If the Referer header is missing or doesn’t match the expected source, the server can reject the request as potentially malicious, which helps prevent anyone from performing cross-site attacks like CSRF.
Now as we have seen some common prevention methods, let’s see how can these be bypassed when testing for security or hunting for bugs. We will go through these one by one, so for today’s article we are focusing on the issues in CSRF token validation.
One widely employed practice for imparting CSRF tokens from servers to clients and vice-versa involves discreetly incorporating them as hidden parameters within HTML forms, as shown below
<form name="update-email" action="/update-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="example@email.com">
<input required type="hidden" name="csrf" value="<!-- randomly generated token -->">
<button class='button' type='submit'> Update email </button>
</form>
When implemented with precision, CSRF tokens serve as a robust defense mechanism against CSRF attacks. These tokens significantly heighten the complexity faced by attackers attempting to forge legitimate requests on behalf of unsuspecting victims. But as a strong defense mechanism, it is, it’s also super easy to mess it up if not careful enough while implementing.
Now let’s see common implementation flaws in CSRF token validation, which as security researchers we can find and eventually leverage to get a successful CSRF attack out of it.
- Validation of the token depends on the HTTP request method
Let’s now delve into some common implementation flaws in CSRF token validation. As security researchers, understanding these vulnerabilities can be instrumental in uncovering and potentially exploiting CSRF vulnerabilities.
One particularly prevalent oversight lies not in the token validation process itself but in the initial stage of validation. To illustrate this point, consider the following code snippet:
@app.route('/update-email')
def updateEmail():
if (request.method == 'POST'):
token = request.form.get('token')
validateCsrfToken(token)
# rest of the code
def validateCsrfToken(token):
# rest of the validation code
Take a moment to analyze this code snippet. At the line if (request.method == ‘POST’):
, it is conditional upon the HTTP request method being POST for the validateCsrfToken()
function to execute. What this means is that if an attacker crafts a CSRF attack using the GET method, the token validation process will be entirely bypassed simply by altering the request method. This scenario often arises in API interfaces, making it a critical point of vulnerability worth scrutinizing.
- Validation of CSRF token depends on the token being present
Let’s explore yet another example of an oversight in the implementation of CSRF token validation. Consider the following code snippet:
@app.route('/update-email')
def updateEmail():
token = request.form.get('token')
if (token != ""):
validateCsrfToken(token)
def validateCsrfToken(token):
# rest of the validation code
Upon a closer examination of this code snippet, it becomes apparent that the if (token != ""):
line, from the developer’s standpoint, may seem like a prudent practice to ensure the presence of data before proceeding with further actions. However, in the context of CSRF, this seemingly innocuous line presents a vulnerability. An attacker can execute a successful CSRF attack by simply omitting or leaving the csrf
parameter empty in their request, effectively circumventing this check.
- CSRF token is not bound to the user’s session
While implementing the token validation function, a critical security lapse arises when applications fail to establish a binding between their CSRF tokens and the user’s session. This oversight can over the door to potential CSRF exploits, enabling malicious actors to bypass token validation. Here’s how it works: Attackers create a dummy account on the vulnerable site and obtain a valid CSRF token. Since this token isn’t tied to any specific user’s session, it becomes a powerful tool for crafting deceptive requests.
Armed with a legitimate CSRF token obtained from their pseudo-account, attackers can skillfully navigate past token validation checks. As a result, the targeted website becomes vulnerable, allowing the attacker to execute actions on behalf of unsuspecting victims.
To illustrate, consider this code snippet
@app.route('/update-email')
def updateEmail():
token = request.form.get('token')
if (validateCsrfToken(token)):
pass
else:
# code to terminate the request
def validateCsrfToken(token):
# rest of the validation code
In this code, the validation function’s sole purpose is to determine the validity of the CSRF token. If the token checks out, the request proceeds; otherwise, it is terminated. this happens when all the generated CSRF tokens are stored in the global scope instead of generating one specifically for a user tied with their specific session. This revelation underscores the critical importance of robust token management practices in CSRF mitigation and highlights the risks associated with loosely bound CSRF tokens.
In the domain of cybersecurity, penetration testing, and vulnerability assessment, it’s a common scenario to identify individual vulnerabilities that may not yield significant impact on their own. To maximize effectiveness, we employ a methodical approach of deep analysis, finding additional vulnerabilities. These distinct weaknesses are then chained together to make a more impactful exploit. This process is also recognized as ‘Exploit Chaining’. Going forward, we’ll see some use of exploit chaining to elevate the exploit’s impact.
- CSRF token is bound to a non-session cookie
In certain cases, web applications indeed tie their CSRF tokens to cookies, but not necessarily the same cookies that track the user’s session. This situation commonly arises in scenarios where client-side sites employ multiple frameworks, leading to intricate integration challenges. Consequently, CSRF tokens become linked to cookies other than those dedicated to user session management.
In this context, potential attackers explore the target website, diligently seeking out bugs or vulnerabilities that allow them to manipulate cookies within the application’s context. The attacker’s strategy unfolds as follows:
- Identify a Cookie-Setting Feature: The attacker scans the website’s functionalities to pinpoint any existing features or vulnerabilities that facilitate cookie manipulation within the application’s context.
- Create a Dummy Account and Obtain CSRF Token: A dummy account is established on the website, getting the attacker access to a valid CSRF token.
- Set the valid CSRF Token: Leveraging the earlier identified feature or vulnerability, the attacker adroitly sets the obtained valid CSRF token to the application’s cookies within the website’s context.
- Craft the CSRF Attack: Armed with the valid CSRF token now embedded in the cookies, the attacker constructs a carefully crafted request, which includes the CSRF token, thus orchestrating an effective CSRF attack.
This sequence of actions underscores the critical importance of holistic security measures, even when cookies and tokens appear to be implemented securely. Vigilant testing and scrutiny are essential to uncover and mitigate such vulnerabilities.
Cookie-setting behavior can extend beyond a single web application, potentially affecting others in the same DNS domain. For instance, a cookie set on ‘
staging.demo.cybercraftlabs.site
’ might impact ‘secure.cybercraftlabs.site
’ if they share the same domain.
- CSRF token is duplicated in a cookie (double submit)
In a nuanced variation of the previously discussed vulnerability, certain applications adopt an unconventional approach by forgoing server-side token record-keeping. Instead, they opt to duplicate each CSRF token within both a cookie and a request parameter. During the subsequent validation process, the application’s sole objective is to confirm that the token presented in the request parameter aligns with the value contained within the corresponding cookie.
This approach, often referred to as the ‘double submit’ defense against CSRF, garners attention due to its simplicity of implementation and its capacity to obviate the need for server-side state maintenance. By synchronizing the token value in both the cookie and request parameters, these applications aim to bolster their defenses against CSRF attacks.
- Identify a Cookie-Setting Feature: The attacker scans the website’s functionalities to pinpoint any existing features or vulnerabilities that facilitate cookie manipulation within the application’s context.
- Set the Valid CSRF: At this step, The attacker doesn’t necessarily need to obtain a token, Instead, the attacker can place its own token (but try to make it look similar just like the application) and using the previously found feature, sets the cookie and craft the request using the same cookie as a token.
As the application is using the cookie and the supplied token, comparing them to validate the token, the attacker can still get a CSRF out of it.
So that’s it for this section, in the next article we’re going to see some more methods to find and exploit CSRF vulnerabilities in web applications and also try to make sense of why the vulnerabilities are there, until then keep hacking… 🤗
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⠶⠶⠶⠶⢦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠛⠁⠀⠀⠀⠀⠀⠀⠈⠙⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⣠⡴⠞⠛⠉⠉⣩⣍⠉⠉⠛⠳⢦⣄⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡀⠀⣴⡿⣧⣀⠀⢀⣠⡴⠋⠙⢷⣄⡀⠀⣀⣼⢿⣦⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣧⡾⠋⣷⠈⠉⠉⠉⠉⠀⠀⠀⠀⠉⠉⠋⠉⠁⣼⠙⢷⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣇⠀⢻⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡟⠀⣸⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣹⣆⠀⢻⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡟⠀⣰⣏⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠞⠋⠁⠙⢷⣄⠙⢷⣀⠀⠀⠀⠀⠀⠀⢀⡴⠋⢀⡾⠋⠈⠙⠻⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠀⠀⠀⠀⠹⢦⡀⠙⠳⠶⢤⡤⠶⠞⠋⢀⡴⠟⠀⠀⠀⠀⠀⠀⠙⠻⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣼⠋⠀⠀⢀⣤⣤⣤⣤⣤⣤⣤⣿⣦⣤⣤⣤⣤⣤⣤⣴⣿⣤⣤⣤⣤⣤⣤⣤⡀⠀⠀⠙⣧⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣸⠏⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⢠⣴⠞⠛⠛⠻⢦⡄⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠸⣇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢠⡟⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⢶⣄⣠⡶⣦⣿⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⢻⡄⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣾⠁⠀⠀⠀⠀⠘⣇⠀⠀⠀⠀⠀⠀⠀⢻⣿⠶⠟⠻⠶⢿⡿⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠈⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢰⡏⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⢾⣄⣹⣦⣀⣀⣴⢟⣠⡶⠀⠀⠀⠀⠀⠀⣼⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠈⠛⠿⣭⣭⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⢿⡀⠀⠀⠀⠀⠀⠀⣀⡴⠞⠋⠙⠳⢦⣀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⢰⡏⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠈⢿⣄⣀⠀⠀⢀⣤⣼⣧⣤⣤⣤⣤⣤⣿⣭⣤⣤⣤⣤⣤⣤⣭⣿⣤⣤⣤⣤⣤⣼⣿⣤⣄⠀⠀⣀⣠⡾⠁⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⠻⢧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠼⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣷⣶⣶⣶⣶⣶⣶⣿⣷⣶⣿⣿⣾⣿⣶⣶⣿⣿⣷⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣷⣷⣿⣷⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣶⣿⣿