3 elements:
- A relevant action the attacker wants to trigger.
- Session handling is solely cookie-based
- Request parameters must be predictable
Trigger with a webpage that has a hidden form, etc. Deliver a link to the victim via e-mail, social media, comment on popular site, img src if it’s a GET,etc.
CSRF PoC generator is built-in to Burp
- Select a request and right click
- Engagement Tools→ Generate CSRF PoC
- Tweak the PoC to fine-tune
- Copy the generated HTML into a web page and view in a browser logged in to the vulnerable website
Common defenses:
- CSRF tokens
- Can be a hidden parameter generated per-user on a form
- Can be a header
- May be possible to bypass by switching HTTP methods
- May be possible to just omit the token and it won’t be validated
- Tokens may be assigned from a global pool. Log in as your user, get one, use it.
- Will need to intercept the original request since most CSRF tokens are one-use. Grab it and make it into a PoC
- CSRF token may be tied to a cookie, but not the session cookie. You can detect this if changing the session cookie logs you out but changing the CSRF cookie just results in an invalid CSRF token message.
- Use some feature of the website or subdomain to set a cookie you can control to set the CSRF token
- Same thing works if cookie is set to match a request parameter
- SameSite cookies
- Refers to same scheme (http(s)), same TLD and first-level domain. Not the same as origin which is the scheme, full domain, and port.
- Intended to prevent a third-party site from triggering a request to another site with the cookies included, which can help prevent CSRF, among other things.
- Possible settings are strict, lax, or none. Chrome now sets lax by default if none is specified.
- To set this just include a SameSite attribute in the cookie
- If a cookie is set with the
SameSite=Strict
attribute, browsers will not send it in any cross-site requests. This can have functionality impacts.
- Lax means that the cookie will be sent cross site if:
-
The request uses the GET
method.
- It may be possible to turn a POST into a GET and trigger it with a script, e.g.
<script>
document.location = '<https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000>';
</script>
-
This may also be possible through some frameworks providing overrides to the method, for example Symfony does this with form tags
<form action="<https://vulnerable-website.com/account/transfer-payment>" method="POST">
-
Additional example that uses a GET but sets the method to POST:
GET /my-account/change-email?email=bob2%40dobbs.com&_method=POST HTTP/2
-
The request resulted from a top-level navigation by the user, such as clicking on a link
-
Not a background request, e.g. script/iframe/img and other resources. However script seems to work using the document.location method.
- None means that there is no cross-site protection. Used for tracking cookies, etc.
- Must include the Secure attribute to ensure it’s only sent over https or browser won’t set it.
- It may be possible to validate even strict SameSite protections using a client-side redirect that can be manipulated.
- Referrer validation