CSRF attack: operation mechanics, defense and PoC construction

Depov

Moderator
Staff member
MODERATOR
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
136
Reaction score
136
Deposit
0$
On the fintech pedest, the developers swore that the CSRF attack is impossible - "we have a set-off of CORS." After 40 minutes, a working PoC was ready: the POST-form automatically sent changed email linking the account. CORS had nothing to do with this query - the browser honestly sent the session cookie together with a "simple" request, and the server did not check anything but it. A typical story with Cross-Site Question Forgery: The vulnerability is considered closed, although in fact it is disguised as a misconception of how the browser works.
How CSRF Attack Works - Mechanical for a Pentester
Intersite Forgery of the Request (CSRF, aka XSRF), "sea-surf", session riding) - an attack in which the victim's browser performs an HTTP request to the target web application on behalf of an authenticated user. The victim does not enter data, does not press "Confirm" - the browser does it himself, because it attaches cookies to each request for the relevant domain.
According to the PortSwigger description, CSRF attacks require three conditions:
1. Target action - the application has a function that the attacker wants to call: a change of password, transferring funds, changing email, adding administrator.
2. Session on cookies - the application identifies the user exclusively for session cookies without additional checks.
3. Predictable parameters - all query parameters are known to the attacker in advance. If the current password is required to change the password, the CSRF will not work.
All three are in place - in front of you confirmed CSRF vulnerability in the web application.

CSRF does not allow you to read the server response (Same-Origin Policy limitation). The attack only works for actions with side effects: data change, sending forms, execution of transactions. To steal data will require a bundle CSRF + XSS - and directly warns about it OWASP: Cross-Site Scripting may bypass any CSRF protection mechanisms.
CSRF location in the attack chain
According to MITRE ATT&CK, the CSRF is used by several techniques:
• Malicious Link (T1204.001, Execution) )- the victim must be forced to follow the link or open a page with an exploit.
• Browser Session Hijacking (T1185, Collection) )- the attacker exploits the active browser session of the victim to perform actions.
• Exploit Public-Facting Application (T1190 - CSRF is used as the first step to fix, for example, through changing email with subsequent password reset.
Kill chain in its entirety: social engineering (reference through email, messenger, forum) -> the victim opens a malicious page -> browser sends a request with session cookies -> server performs the action -> the attacker receives control (email change -> password reset -> full account capture).

[Applicable to: external pentest, any web application with cookie-based authentication. In the internal pentest - CSRF on administrative panels (routers, printers, CI/CD) available via localhost]
CSRF example of an attack: from GET to POST
CVE-2008-6586 - classics via GET query
Real CSRF vulnerability CVE-2008-6586 (CWE-352) in μTorrent WebUI 0.315 - a visual demonstration of how NOT to design an API. Web interface μTorrent on localhost:8080 performed critical operations through GET without verification: forced loading of an arbitrary torrent file and change the administrator password.

The EDB-31672 (author th3.r00k, published on April 18, 2008) was posted on forums and in email as an invisible picture:
HTML:
<img src="http://localhost:8080/gui/?action=setsetting&s=webui.password&v=eviladmin" width="0" height="0">
The browser tried to “load the picture”, sending a GET request from cookies. The user lost control of the record - the password was changed silently. Direct violation of RFC 2616: GET and HEAD should not produce side effects. But who did it stop?
Building a PoC for POST requests
Most modern applications use POST to change data. This complicates the operation by one step - no more. According to the PortSwigger description, the standard CSRF PoC for POST looks like this:
HTML:
<form action="https://target.com/email/change" method="POST">
<input type="hidden" name="email" value="[email protected]"/>
</form>
<script>document.forms[0].submit();</script>
The victim opens the page - JavaScript instantly sends the form. The browser attaches session cookie, the server changes email. Then the attacker requests a password reset on his email and gains full control over the account.

In Burp Suite Professional, it is automated: right click on request -> Engagement tools -> Generate CSRF PoC. The generator creates HTML with a form, taking into account all the parameters. In practice, I start with a generator, and then finishing PoC with my hands: adding iframe to hide the redirect, process a non-standard Content-Type or replace the method.
CSRF Attack Restrictions
CSRF is not a universal vector. This is when the attack doesn’t work:
1782681987045.png

Client-side CSRF and Login CSRF
According to OWASP Prevention Cheat Sheet, there is a separate class of CSRF vulnerabilities on the client side. JavaScript on the application page takes a value from the URL-parameter and uses it to form an AJAX request. The attacker constructs a link in which the controlled parameter directs the request for the right endpoint - everything happens inside the origin, standard checks (including SameSite and Referer) are blind.

Separate category - Login CSRF. The attacker forges the request for the login so that the victim is authorized under someone else's record. After that, the victim performs actions (saves documents, enters card data), and the attacker sees everything through his account. Login CSRF is often ignored when testing, although it allows you to collect confidential information without a single alert. I check Login CSRF on each project - and I find once every few months.
How to Protect a Web Application from CSRF
According to OWASP, CSRF protection is based on a combination of multiple levels.
CSRF token - Synchronizer Token Pattern
The most reliable method. The server generates a unique, unpredictable CSRF token for each session and inserts it into a form as a hidden field. When sending, the server compares the received token with the saved.

Token requirements for OWASP: uniqueness for the session, generation through CSPRNG, prohibition to transfer to the URL (leaning through Referer, logs, browser history), prohibition of storage in cookies for a synchronized pattern.

For SPA applications, the token is transmitted through a meta tag in HTML and attached to AJAX queries through a custom headline X-CSRF-Token. The casting header automatically falls under the Same-Origin Policy - an additional layer of protection without excess code.
Signed Double-Submit Cookies
For stateless architecture, OWASP recommends Signed Double-Submit Cookie. The token is placed in both cookies and the form parameter. The server compares both values. Critical: the token is necessarily tied to session ID via HMAC with server secret. Naive Double-Submit without a signature - OWASP explicitly marks as DISCOURAGED - vulnerable to the cookie through a subdomain or CRLF.
SameSite Cookie and Fettch Metadata
Attribute SameSite controls the sending of cookies on cross-site requests:
1782681975139.png

Fetch Metadata headers - a more recent approach: browsers send Sec-Fetch-Site(Sec-Fetch-Site) Sec-Fetch-Mode, Sec-Fetch-Dest with every request. The server rejects requests with Sec-Fetch-Site different from same-origin. Go has included support for this mechanism in the standard library since version 1.25 (CrossOriginProtection) Plus - does not require a front-end modification.
When there is enough built-in protection of the framework
Before implementing your own mechanism - check the framework. Django, Laravel, . NET, Spring Security gives ready-made solutions. Your own implementation is the source of mistakes. An illustrative example is described by the developers of Banki.ru on Habre: the csurf library for Express.js, created to protect against CSRF, itself contained a CSRF vulnerability and was archived. The team had to write protection from scratch - with HMAC signature, salted hashing and incart in cookies on the Double Submit pattern. Irony - the library of "protection" was more leaky than the lack of protection at all.
Testing web application on CSRF vulnerability
A checklist suitable for transfer to the pentest report:
1. Identify state-changing endpoints - everything that changes the data: POST, PUT, DELETE, as well as GET with side effects. Priority: change email, password, access rights, financial transactions.
2. Check the presence of a CSRF token - look for a hidden field or custom headline in the query. No, design PoC.
3. Remove the token from the request - in Burp Repeater, remove the parameter with the token. The server accepted the request? Protection is formal.
4. Substitute someone else's token - register a second account, take its token. If it works, the token is not tied to the session.
5. Change the HTTP method - replace POST with GET, transfer the settings to the URL. Check if validation is used.
6. Check the session cookie attributes - SameSite=Noneor the absence of an attribute in non-Chromium browsers extends the vector.
7. Suppress Referer - if the protection is built on the Referer check, add to PoC: <meta name="referrer" content="no-referrer">.
8. Check Login CSRF - forging the entry-register request.
9. Build and confirm PoC - Burp Suite -> Generate CSRF PoC -> open in the browser with an authorized session -> confirm the execution of the action.
10. Document the full chain of impact - in the report: "change of email -> password reset -> full account capture", not an abstract "discovered CSRF vulnerability".
 
Top Bottom