How attackers chain weak Anti-CSRF with other vulnerabilities to cause maximum damage
Cross-Site Request Forgery (CSRF) is a type of attack where an attacker crafts a malicious HTTP request and tricks a victim user into making that request to a server on which the victim is already authenticated. For a more detailed understanding about CSRF attacks, read the OWASP Foundation's article.
Although CSRF vulnerabilities are rarer to find these days due to the advent of more secure web frameworks, they are still as exploitable as before. There are multiple protection mechanisms to mitigate CSRF vulnerabilities of which utilizing Anti-CSRF Tokens is the most common.
The Seven Sins
Anti-CSRF Tokens allow the server to uniquely distinguish who actually requests the resource/action, thereby preventing CSRF attacks. However, the following seven common implementation weaknesses enable attackers to bypass security:
- Removing the Anti-CSRF Token: Completely removing the Anti-CSRF token parameter from the original request may allow to bypass CSRF protection due to lack of validation at server-side.
- Altering the Anti-CSRF Token: When token checks are loosely handled, spoofing a same length token by changing some part of token may allow bypassing CSRF protection.
- Using the Attacker’s Anti-CSRF Token: When the server only checks if a token is valid but does not check which user the token is associated with, an attacker can simply provide their own CSRF token to satisfy server’s check and bypass the CSRF protection.
- Spoofing the Anti-CSRF Token: When tokens are generated using weak or no cryptography, an attacker may potentially generate spoofed tokens that impersonates other user in order to bypass CSRF protection.
- Using guessable Anti-CSRF Tokens: When an application is using a fairy small or guessable token, an attacker can potentially try to guess or brute force a valid token for the victim user to bypass CSRF protection.
- Stealing Anti-CSRF Tokens: When CSRF tokens are passed as cookie parameters without Secure and HTTPOnly flags, an attacker can potentially steal the CSRF token via XSS or other attacks.
- Swapping HTTP Verbs: When applications do not implement the same levels of security in similar HTTP methods such as GET and POST, an attacker may be able to swap verbs to bypass security. This method is covered in the article The Dark Side of Request Routing.
In this post, we will discuss how I was able to bypass an Anti-CSRF Token mechanism by swapping HTTP request methods and using a client-side validation vulnerability to perform a full account takeover.
Let’s Begin With a Bit of History
I was performing a security assessment of a web application we will call weaksite.com. After exploring the application, I found the /editprofile
endpoint which accepts requests as follows:
POST /editprofile HTTP/1.1 Host: weaksite.com <redacted>username=test&description=<some_text>&phone=1231231231&anti_csrf=<token>
You can see in the above request that the anti_csrf
token parameter is present. I checked if the server correctly validates the request when the token is missing or tampered with, and it did. So basically no luck there.
Next, I simply changed the HTTP Request Method from POST to GET, removed the ***anti_csrf*** parameter, and converted POST parameters to GET parameters. The new request looked like this:
GET
/editprofile?username=test&description=<some_text>&phone=1231231231 HTTP/1.1
Host: weaksite.com
<redacted>
This request successfully went through and we were able to bypass the CSRF check successfully!
The impact of this vulnerability is medium-ish because we are not able to do much more than change some profile information. Let’s find ways to drive up the impact, shall we?
Exploring the application further, I checked the Password Reset Functionality. This endpoint also contained an Anti-CSRF token, but it also asked for the current password. The original password change request looks like this:
POST /changepassword HTTP/1.1
Host: weaksite.com
<redacted>current_password=currentpassword&new_password=new_password&confirm_password=new_password&anti_csrf=<token>
So I simply removed the current_password
field and the server went ahead and reset the password!
So now we have two things:
- Way to bypass and Anti-CSRF tokens
- Way to bypass current password on password change
We are now going to chain these two issues to change the password of the victim user using CSRF, the forged request will look like this:
GET
/changepassword?new_password=new_password&confirm_password=new_password HTTP/1.1
Host: weaksite.com
<redacted>
Since the server is not validating the CSRF protection mechanism on a different HTTP verb and, at the same time, the checks for current_password
at server-side are loose, an attacker can simply utilize a combo attack to takeover any user’s account with little user interaction. This impacts the confidentiality, integrity, and availability of the system since the user’s account can now be fully compromised.
Takeaways
- Avoid the seven deadly sins of Anti-CSRF Tokens
Implementing an Anti-CSRF mechanism alone is not sufficient, one must ensure that the Anti-CSRF Tokens are being validated properly on the server-side. - Abusing HTTP verbs to perform CSRF is exploited in the wild
It is essential to block the HTTP Verbs which are not required on the sensitive endpoints. A malicious user can, for example, covert a POST request to GET request which may allow to bypass the verification to Anti-CSRF Token check.
Also, check out our article on HTTP verb abuse: The Dark Side of Request Routing