CSRF
Last updated
Was this helpful?
Last updated
Was this helpful?
Unauthorized actions, such as transferring money or changing account details, can be performed without the user's knowledge.
Use CSRF tokens, ensure secure cookie settings, and implement same-site request headers to verify the legitimacy of requests.
One way to mitigate CSRF attacks is using a CSRF token, a unique value submitted by the user, typically as a hidden input field, but this adds overhead and usability concerns due to the need to track tokens. The cookie-to-header approach uses client-side JavaScript to send the token as a request header, but it can be bypassed if an attacker gains access to the cookie via XSS.
XSS flaws can bypass CSRF protections, as any requests generated by the XSS payload are considered part of the domain.
The double-submit approach uses a hidden input field with the CSRF token, validating that the cookie value matches the input field value without needing JavaScript access to the cookie or tracking generated tokens. If an application's form elements lack these mitigations or SameSite
cookies, it is vulnerable to CSRF, which can be detected through source code inspection.
The example below is based on TCM's Practical Bug Bounty course.
This app gives the user the option to update his email after they logged in (Figure 1).
We can see that there is no anti-CRSF token and the current cookie does not have the SameSite
flag set. Thus, we can try generate a CRSF PoC using Burp Suite Pro's engagement tool (Figure 2.1 & 2.2). This tool takes the HTML code related to the update email form
(Figure 2.3), removes the unecessary cosmetic elements, adds the html
and body
tags, and adds a script
so the payload gets executed upon loading.
Next, we can update the payload's value
parameter to an email we control, copy the HTML code into a file (csrf.html
), and find a way to serve this file to our target (Figure 3).
The example below is based on TCM's Practical Bug Bounty course.
This time the application implements a hidden CSRF token (Figure 4.1) which is supposed to mitigate such an attack by using a unique token on each request. We can check this token for various flaws, but in this case, it seems that the application just checks that a token exists and nothing more. Thus, we can generate a CSRF payload that includes a random-value CSRF token (Figure 4.2) and perform a CSRF attack (Figure 4.3).
The example below is based on OffSec's WEB-200 course.
Inspecting the login request response's cookies we can see that there is no CSRF token and the JSESSIONID
cookie does not have the SameSite
flag set (Figure 5).
One interesting functionality to target with CSRF flaws is user creation. If we can force an admin to execute our malicious request, we could create users with elevated privileges. The POST
request used for creating a new user, does not seem to include any CSRF-related parameters (Figure 6).
Similarly, the POST
request for adding the user to the SUPER
group does not include any CSRF-related parameters either (Figure 7).
At a high level, we want to copy the application's HTML forms into pages hosted on our server. We will fill the forms with our own data and make them submit on page load, so the victim must only open the page. In this case, our goal is to create a new user and then assign them the SUPER
privilege. We will start by creating the basic structure of a form element (ofbiz.html
) under /var/www/html
so we can server it using Apache.
Next, we need to add the input
elements. The POST
request that our page generates needs to match the baseline request from the app. We need to add input elements, one for each key-value pair in the original request, inside the form element.
When we visit /localhost/ofbiz.html
a GET
request will be initiated, which will then create a POST
request to ofbiz:8443/webtools/control/createUserLogin
, and the csrftest
user will be created. Note that our cookies were included within this request and that the Origin
and Referer
headers let us know that the request came from localhost
(Figure 6).
Next, we will go through the same process for the privilege escalation step.
Now, we have to combine both forms and have them submitted sequentially via implementing some JavaScript code. We will also change the username name to crsftestuser
to differentiate from the previous user.
This approach is not ideal as some JavaScripts calls can be asynchronous, meaning that thecsrf2
form could be submitted before thecsrf
form. In this case, an extra line was added that sets up a 1 second delay between the two requests.
In visiting localhost/ofbiz2.html
, two new tabs open up and the payload is successfully executed (Figure 9).
Instead of using two forms, we can make requests directly without navigating the browser away from the payload page. In brief, what the below payload does, is creating two functions, one for each POST
request, where it includes the privilege escalation request within the user creation request to make sure that the execution order is correct. Finally, it explicitly calls the first function at the end, so it is auto-called on page load.
However, when the payload is executed, the correct requests are made, but we are not able to use the current user's session cookies (Figure 10).
The cause of the problem can be identified if we inspect that JSESSIONID
set flags during a successful login: the SameSite
flag is not set, so its value defaults to Lax
which disallow transferring the cookie on cross-site requests (Figure 11 & 12).
csrftest
user.SUPER
group.JSESSIONID
cookie via Burp.JSESSIONID
cookie via Chrome.