How JSON CSRF can be exploitable?
The JSON CSRF can be exploited in four ways depending on other factors that we will discuss:
- By using normal HTML Form1: When Content-Type is not validating at the server-side and also not checking for the POST data if it’s correctly formatted or not.
- By using normal HTML Form2 (By Fetch Request): When Content-Type is not validating at the server-side and only checking for the POST data if it’s correctly formatted or not.
- By using XMLHTTP Request/AJAX request: When Content-Type is validating at the server-side and the server accepts only “Content-Type: application/json”
- By using Flash file: When Content-Type is validating at the server-side and the server accepts only “Content-Type: application/json” and CORS is also configured properly
Case1: When Content-Type is not validating at the server-side and also not checking for the POST data if it’s correctly formatted or not.
Why do we need to check by changing the Content-Type?
Because we can’t send the Content-Type: application/JSON by using a normal HTML form, it is only possible through an XMLHTTP Request/AJAX request to the server but for sending the AJAX request from another domain, we need a CORS misconfiguration.
Now come back to Case 1. If the server is accepting the JSON data by changing the Content-Type then we can try it by changing it into the below three Content-Type.
* Content-Type: text/plain
* Content-Type: application/x-www-form-urlencoded
* Content-Type: application/xml
Check if any one of these is working, if anyone is working then we can use the HTML form which includes the entire JSON payload as a parameter but the problem in this technique is that when we click on Submit button on CSRF POC, it sends trailing “=” character. To resolve this issue we padded the additional parameter towards the end of the JSON payload.
Check the below blogs for extra understanding:
http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html
JSON CSRF POC Copied From: https://www.directdefense.com/csrf-in-the-age-of-json/
<html>
<body>
<form action=”https://members.bankofdirectdefense.com/accounts/transfer" method=”POST” enctype=”text/plain”>
<input type=”hidden” name=”{\”from-account\”: 1,\”toAccount\”: \”021000021–9876543210\”,\”amount\”: 1000,\”currency\”: \”USD\”,\”foo” value=”\”:\”bar\”}” />
</form>
<script>document.forms[0].submit();</script>
</body>
</html>
Note: This scenario is only possible when the server accepts the above-mentioned Content-Type and also the server is not validating the request body or JSON data at the server-side.
Case 2: When Content-Type is not validating at the server-side and only checking for the POST data if it’s correctly formatted or not.
If the server is validating the POST data and also the format of JSON data then the above Case1 method does not work. For this, we can use the “fetch” method to send the JSON data with Content-Type to the server.
Let's assume that we have Case 1 scenario where the application accepted the other Content-Type but the server is validating the JSON body and JSON format. We can resolve this problem by using the fetch method.
JSON CSRF POC Copied From: https://www.geekboy.ninja/blog/tag/json-csrf/
Note: When “Content-Type: text/plain or application/x-www-form-urlencoded or multipart/form-data” then without CORS misconfiguration it will work. “credentials: include” should also be there so that browser sends the cookies to the server to perform CSRF.
One CORS condition is required to achieve the above case. The ACAO (Access-Control-Allow-Origin) should not be a wildcard value. The application dynamically set ACAO to the origin of the request. As per CORS specifications, a wildcard value paired with ACAC (Access-Control-Allow-Credential) set to true will result in an error. For this reason, we need the application to dynamically set ACAO to the origin of the request.
<html>
<title>JSON CSRF POC</title>
<body>
<center>
<h1> JSON CSRF POC </h1>
<script>
fetch('http://vul-app.com', {method: 'POST', credentials: 'include', headers: {'Content-Type': 'text/plain'}, body: '{"name":"attacker","email":"attacker.com"}'});
</script>
<form action="#">
<input type="button" value="Submit" />
</form>
</center>
</body>
</html>
Case3: When Content-Type is validating at the server-side and the server accepts only “Content-Type: application/json”
As I have mentioned in Case1 that the browser doesn’t allow us to send the Content-Type: application/json by using a simple HTML form. To achieve this we have to use the AJAX request. But for achieving this by AJAX request some CORS conditions should be there otherwise it will not work.
The browser only allows the “Simple Requests” without triggering the CORS preflight request.
What is a Simple Request as per a JSON CSRF attack?
In the JSON CSRF attack, we mostly need to change the “Content-Type”. So Simple Request is a request that only allows the “GET, HEAD, and POST” method and in “Content-Type: text/plain or application/x-www-form-urlencoded or multipart/form-data”. If we try to use the application/json as Content-Type then CORS preflight request first initiates and when the CORS conditions are true then only it allows the AJAX request to send the data.
For More Details Read This Article: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#requests_with_credentials
The browser is configured in such a way that when it finds an AJAX request other than “Simple AJAX Request” it first sends the “Preflight” request.
Image Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#requests_with_credentials
Check the above image and think about why the browser needs a preflight request?
The browser needs to send the preflight request to confirm that the header (Content-Type: application/json which is not a simple request, POST method and Origin) which we tried to append in the request is allowed or not by the server. If we get the response from the server like in the above image then the JSON CSRF will work.
What conditions do we need to achieve Case3?
* The “Content-Type” header should be allowed by the server so that we can add a custom header that the browser directly does not allow us to add. The requested Method and Origin should also be allowed by the server. Check preflight response.
* The “Access-Control-Allow-Credential” should be true.
* The ACAO (Access-Control-Allow-Origin) should not be a wildcard value. The application dynamically set ACAO to the origin of the request. As per CORS specifications, a wildcard value paired with ACAC (Access-Control-Allow-Credential) set to true will result in an error.
The Example Copied From: https://www.directdefense.com/csrf-in-the-age-of-json/
<html>
<body>
<script>
function submitRequest()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "https:\/\/members.bankofdirectdefense.com\/accounts\/transfer", true);
xhr.setRequestHeader("Content-Type", "application\/json");
xhr.withCredentials = true;
xhr.send("{\"from-account\": 1,\"toAccount\": \"021000021-9876543210\",\"amount\": 1000,\"currency\": \"USD\"}");
submitRequest();
</script>
</body>
</html>
Case 4: When Content-Type is validating at the server-side and the server accepts only “Content-Type: application/json” and CORS is also configured properly
Follow this article for this case. He explained it in detail: https://blog.appsecco.com/exploiting-csrf-on-json-endpoints-with-flash-and-redirects-681d4ad6b31b
References:
https://www.directdefense.com/csrf-in-the-age-of-json/
http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html
https://www.geekboy.ninja/blog/tag/json-csrf/
https://blog.appsecco.com/exploiting-csrf-on-json-endpoints-with-flash-and-redirects-681d4ad6b31b
https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
https://developer.mozilla.org/en-US/docs/Web/API/fetch
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Comments
Post a Comment