Home

CSRF

Consider this scenario: there's a simple web application, and upon logging in, we receive cookies that are stored in our web browser. Whenever we make a request to the web application, the cookies in our browser are automatically sent to the web server so that it can verify our login. This process is known as the cookie flow.

Now, let's discuss Cross-Domain Access Control. In HTML, we have an <iframe> tag that allows us to embed one website inside another. However, cross-iframe communication is not possible due to Same-Origin Policy (SOP).

SOP is a security feature that ensures an attacker website cannot make requests to arbitrary websites and read data across domains. This is crucial because cookies are automatically sent on every request made to that domain.

Therefore, the policy only allows reading from an <iframe> if the following conditions are met:

- The domains must be the same (i.e., same host).
- The schemas must be the same (i.e., same protocol).
- The ports must be the same (defaulting to port 80).

Website URL : http://google.com:80

Iframe URL : http://google.com:80


If all three conditions (same domain, same schema, and same port) are the same between an <iframe> and a website, then the browser allows cross-domain data exchange. This policy not only applies to <iframe> but also to AJAX requests.

Cross-Site Request Forgery (CSRF) occurs when one domain sends a request to another domain in order to modify some value. For example, imagine a website called vulnerable.com that, when clicked, deletes a user's account. Of course, we don't want to do that, so let's click on a different link called hack.com instead, which deletes the user's account when the link is visited.

Let's take a closer look at what happens in this example. When you log into your account on vulnerable.com, some cookies are saved in your browser. If you then click the delete button, it will send a request to the following endpoint:

vulnerable.com/delete-my-account





When you visit hack.com, a request is made to the exact same endpoint as vulnerable.com/delete-my-account

However, this request is made from hack.com. Additionally, cookies are automatically sent to the website on every request, regardless of the current domain, unless there are flags set to prevent it.

This means that the delete action happens within the context of your session, effectively deleting your account forever. In short, hack.com forged a delete request to vulnerable.com. This is known as CSRF (Cross-Site Request Forgery), an old vulnerability for which there are proper protections, such as randomized CSRF tokens or anti-CSRF tokens.





Exploit hosted on hack.com





As you can see, we have a form, and the action of this form is to send to the delete endpoint of a vulnerable application. The method used is "post." One additional thing you may notice is that there is some JavaScript which automatically submits the form, so there is no need for user interaction. Alternatively, instead of using form submission, you can also use JavaScript to make an AJAX (XHR) request or fetch request in the background, so everything happens asynchronously.

Sometimes websites will expect a JSON value, especially with the prevalence of APIs. It's common to find CSRF with some JSON in it.

In HTML, the normal POST request is usually sent through a form, and the POST data sent through the form consists of generic key-value pairs rather than JSON.

Suppose we have an endpoint called /deleteSubject which takes a JSON POST data and deletes the specific subject.





As you can see, we have some JSON data that we need to send to the website as part of a CSRF attack. However, how can we send this data using forms? As you may already know, form submission does not support JSON data.

So lets create a form:





If we set the name of subject to Math and send the request, so we'll get subjectName=Math, so as you can see the majority of this string is controlled by user.

Now, lets create something that looks like JSON :





As you can see, we are a lot closer to achieving our goal. We have everything we need, except for one thing: the data provided is not valid JSON. As you can see, there is some text at the end, denoted by the string "= Math," which has no meaning in this context.

To resolve this issue, one solution would be to use comments. However, JSON does not support comments. Fortunately, in Ruby, comments are allowed. You can simply add two forward slashes (//) at the end of the text to eliminate the extraneous information and ensure the data can be processed correctly.



But what if it wasn't Ruby and comments weren't an option?

As we have control over what comes after the equal sign, we can find a way to make it work. One solution would be to add another key-value pair to the JSON string, which does not have any functional meaning. We can include this extra pair as "junk" data to ensure that the overall string is valid JSON.



Now, this entire string is a valid JSON object. When passed, only the subject name is extracted from the JSON, and the "junk" part is ignored.

Another simple way to achieve this is by using an AJAX (XHR) request. We can send the JSON string as the body of the fetch() request, and the server will process it accordingly. Though we may encounter the Same-Origin Policy (SOP), the request will still hit the server and update the actions as intended.

It's worth noting that the form and AJAX(XHR) methods discussed will only work if the content-type header is ignored by the server. In many cases, content-type headers are required for the server to process the request correctly. Web applications may expect a content-type header to be sent explicitly in the JSON data to indicate that the data is in JSON format.

The challenge with adding a content-type header to the form is that browsers will only allow you to send specific headers if the server explicitly allows it via Cross-Origin Resource Sharing (CORS). The server must send back the Access-Control-Allow-Origin header, indicating that it is okay for the content-type header to be set to "application/json."

However, there is another way to make this work without using any of these methods, and that is by using Adobe Flash. Flash files are not directly affected by the Same-Origin Policy, making it possible to forge "Content-Type" headers using these files. However, cookies will not be sent along with the request unless the Cross-Domain XML and other necessary settings are configured.

One way to address this limitation is to use a "307 redirect," which will hold the headers that are being sent and act as a relay. We can add a content-type header in the flash files and specify the request endpoint in the JSON post data. This request endpoint should not be the user's logged-in website but instead a redirect page that in turn redirects to vulnerable websites. This way, the redirect page can receive the headers and post JSON data as a string and forward it to the user's logged-in website.

It's worth noting that CSRF can sometimes be chained with other bugs to create even more critical vulnerabilities. For example, in one instance, a CSRF token leaked and led to stored XSS and Account Takeover, although it was unfortunately reported as a duplicate.