Today I found a possible Cross-site Request Forgery vulnerability in a web application, however – the application expected JSON as its input. The fact that the input is JSON means that the attack is a little bit more complicated, the browsers built in protections get in the way a little more. So here’s some notes and tricks which might help a little!
So recently I wrote about writing burp extensions and I taught this through writing an extension to deal with CSRF tokens that are in each page, so as you navigate the site or fuzz a function you have to extract a token from each page to include it in the next request.
That’s not the only way to implement tokens though, and today I came across “the other way” during a Penetration Test so modified my original code and figured I’d share this version too!
I wrote a very simple burp extension that can pull a token a CSRF token out of a response and update the next request with that token. It’s designed to be a simple as possible so it works for my lesson on writing burp extensions and if you’re lucky then all you need to do is update the script with the name of the token your target application uses and you’re good to go but it’s designed to be as easy to tweak to your needs as possible. I also wrote about how to install custom extensions here if you’ve not done that before, just copy and paste the below code into a file called csrftei.py and load that file into burp! The code is all available below and should be nicely commented to explain how everything works:
Often abbreviated to CSRF and often pronounced as “Sea-Surf” is an attack against a Web Application that abuses an application’s trust in the user. An attacker’s aim is to cause a function to execute on the application using the user’s authentication credentials simply by causing the user’s browser to request that function in the normal way, but from a malicious site.
For example, a user navigates to a malicious site and this site in turn sends a request to the vulnerable function on the vulnerable web site. This is where “Cross-site” comes from, it is a malicious site sending a request to the vulnerable site.
A protection mechanism exists to prevent domains from messing with each other, known as Same-Origin Protection (SOP). This protection prevents one domain from processing responses from other domains and there-by generally prevents any malicious two-way interaction between websites. However, it only prevents the malicious application from processing the response, it does not prevent the victim application from receiving and processing a request. Some requests can cause damage without the requirement for a response.
Take the function for changing a user’s password. If an application has a change password function that is accessed in a way such as:
and the response is simply “Success” this could be abused by attackers for the purposes of account take-over. The attack would simply be that the victim navigates to a malicious site where that site sends the above GET request to the vulnerable web-server.
The attacker can place the payload on a malicious site with HTML such as:
<img src="http://vulnerable.example.com/myprofile?change-password=Password123" width=0 height=0>
The user’s web browser will by default pass along the user’s cookie-based access token to the victim website and as far as the site is concerned the user has changed their password. Allowing the attacker to simply navigate to vulnerable.example.com in their own browser and login using the password “Password123”.
There are two simple ways to fix this issue, either is generally sufficient independently. The first is for the application to check the “Referer” header in the HTTP request, if it’s not coming from a trusted site then the request should be denied. The second way to fix this issue is to embedded in the page body a security token that is required for each function to execute, as the token is embedded in the page body an attacker would not be able to determine what this is as Same-Origin Policy blocks the attacker from reading responses!