Te inpongo el ID con Session Fixation!
Como pueden observar en mi artículo sobre Cross-Site Scripting, robar una sesión (robo de cookies) es relativamente sencillo si la página es vulnerable. A través de un ejemplo les mostré cómo es posible obtener un ID de sesión de un usuario autenticado, robando la cookie de la página. Si bien olvidé mencionarlo en ese artículo, el ataque se conoce como session hijacking. Hoy les traigo un ataque similar, pero llevado a cabo antes de que el usuario víctima se autentique en la página vulnerable.

En un sistema con sesiones, cuando un usuario abre una página, el browser busca alguna cookie relacionada y la envía (si es que encuentra alguna) al server. En el caso que el usuario no envíe cookie alguna, el servidor le indicará al browser que setee una dada cookie con el valor del ID de sesión. Este ID de sesión será utilizado por el servidor para reconocer al usuario en accesos futuros. Los IDs de sesión son números de varios bytes creados al azar, de forma que otro usuario no pueda adivinarlos. Que estos números sean realmente aleatorios es de extrema necesidad para que otro usuario no pueda hacerse pasar por el actual.


Descripción del ataque

El session fixation trata sobre forzar a un usuario a utilizar un ID de sesión enviado por el atacante. Dado que un atacante no podría (en un sistema con IDs realmente aleatorios) adivinar el ID de sesión, éste (el atacante) obtiene un ID de sesión y luego "convence" a otro usuario para que utilice el mismo. De esta forma, el atacante no necesita adivinar el ID que utiliza el otro usuario, porque fue él el que lo envió.

El ataque funciona de la siguiente manera:
1) el atacante accede al sistema de login del site www.ejemplo.com y el server de éste crea un ID de sesión, el cual se lo comunica al atacante.
2) el atacante "convence" a un usuario del site www.ejemplo.com para que utilice el ID obtenido en el paso anterior.
3) la víctima accede a www.ejemplo.com utilizando el ID indicado por el atacante y se autentica en el site.
4) una vez que la víctima se autenticó, el atacante accede a www.ejemplo.com con el susodicho ID y estará autenticado como el usuario víctima gracias al paso anterior.

Como se darán cuenta a partir de la explicación, el nombre session fixation proviene del hecho que la víctima utiliza el ID de sesión fijado por el atacante.

Para demostrar el ataque, reutilicemos el sistema de login que mostré en el artículo de XSS:

<?php session_start(); ?>
buscar:
<FORM METHOD="GET" ACTION="">
<INPUT TYPE="TEXT" SIZE="30" NAME="search" />
<INPUT TYPE="SUBMIT" VALUE="ingresar" />
</FORM>
<?php if(isset($_GET['search'])) print "resultados con la palabra <B>".$_GET['search']."</B><BR><BR>" ?>
<?php
if(isset($_POST['logout']))
{
session_destroy();
unset($_SESSION['user']);
}
function printform()
{
echo '<FORM ACTION="" METHOD="POST">
user: <INPUT NAME="user" TYPE="TEXT" SIZE="20" /><BR>
pass: <INPUT NAME="pass" TYPE="PASSWORD" SIZE="20" /><BR>
<INPUT TYPE="SUBMIT" VALUE="login" />
</FORM>';
}
function printhello()
{
print "hola usuario: ".$_SESSION['user'];
print '<FORM ACTION="" METHOD="POST"><INPUT NAME="logout" TYPE="SUBMIT" VALUE="logout" /></FORM>';
}

if(!isset($_SESSION['user']))
{
if(isset($_POST['user']) && isset($_POST['pass']))
{
if(($_POST['user'] == "demasiadovivo") && ($_POST['pass'] == "123456"))
{
$_SESSION['user'] = "demasiadovivo";
printhello();
}
else
{
echo "el usuario ".$_POST['user']." no existe";
printform();
}
}
else
printform();
}
else
{
printhello();
}
?>


Si leyeron el artículo, recordarán que el sistema simplemente tiene un input de texto para buscar palabras (con vulnerabilidad XSS) y un sistema de login básico, donde el usuario es demasiadovivo y el pass es 123456. Supongamos que este programa se encuentra en http://www.ejemplo.com/buscador.php. Lo que el atacante haría es ingresar a http://www.ejemplo.com/buscador.php y obtener el ID de sesión (podríamos usar el plug-in Tamper Data para Firefox, o bien ejecutar javascript:alert(document.cookie); en la barra de direcciones del browser). Asumamos que el ID obtenido es 1234 (uno real sería muchísimo más largo, pero mantengamos el ejemplo simple).
Ahora, el atacante arma una URL aprovechando la vulnerabilidad XSS del buscador con el siguiente contenido: http://www.ejemplo.com/buscador.php?search=<SCRIPT>document.cookie="PHPSESSID=1234";</SCRIPT> y se la envía al usuario víctima. Como pueden observar en la URL, ésta utiliza un javascript para setear la cookie con el valor PHPSESSID=1234. PHPSESSID es el nombre de la variable de sesión de PHP.
Si el usuario ingresa al link enviado por el atacante, su cookie se seteará al valor indicado. Luego, si el usuario se autentica, el atacante podrá acceder al site como si fuera el usuario, utilizando el valor 1234 como ID.
Con este ataque no necesitamos robar el ID de sesión, directamente lo generamos nosotros y hacemos que la víctima lo use.


Ya sabía hacer esto de otra forma...

Si ya entienden de XSS, probablemente se están preguntando: por qué no inyectar un script que directamente robe el ID de sesión?... bueno, es una pregunta muy razonable. Si bien el robo de cookies es más directo, este método nos permite obtener los mismos resultados pero de otra forma.
Session fixation es uno de los tantos ataques que se pueden realizar utilizando XSS (aunque no depende exclusivamente de éste) y vale la pena tenerlo en cuenta. Habrá casos en los que el robo de cookies utilizando otros ataques puede complicarse y se podría llevar a cabo utilizando este último.


Formas de lograr un session fixation

Además del ejemplo donde inyectamos el script <SCRIPT>document.cookie="PHPSESSID=1234";</SCRIPT> en la página, podemos realizar este ataque de otras formas:


Cookies de dominio

Si el atacante tiene un site hospedado en el mismo dominio que la página afectada, es posible utilizar cookies de dominio. Las cookies de dominio son cookies donde su atributo dominio se expande a todo un dado dominio (por ejemplo: ".ejemplo.com"). Es decir, el browser envía la misma cookie para cualquier site hospedado en el mismo dominio.
Supongamos que el atacante administra el site malo.ejemplo.com o bien detectó una vulnerabilidad XSS en éste y quiere hacer un session fixation sobre www.ejemplo.com. Lo primero que hará es insertar el código <script>document.cookie="PHPSESSID=1234;domain=.ejemplo.com";</script> dentro de malo.ejemplo.com (recuerden, se puede hacer utilizando XSS) e incitará al usuario para que acceda a dicha página. Una vez que el usuario accede, el browser aceptará la cookie y la almacenará para accesos futuros. Si luego el mismo usuario accede a www.ejemplo.com (o cualquier dominio dentro de .ejemplo.com), el browser enviará la misma cookie obtenida de malo.ejemplo.com, debido a que ésta es una cookie de dominio.


Usando el tag <META>

El tag <META> permite insertar parámetros HTTP dentro del código HTML y si bien deberían estar ubicados en al sección HEAD del HTML, distintos browsers aceptan incluirlos en cualquier lugar. Si logramos inyectar el código <meta http-equiv=Set-Cookie content="PHPSESSID=1234"> dentro de la página que deseamos acceder, lograríamos un session fixation.
Es claro que éste ataque depende de encontrar una vulnerabilidad XSS en la página, pero nos habilita un tag distinto de inyección en el caso que tags como <script> o <img> estén filtrados por el servidor.


Prevención?

Este ataque es fácil de prevenir, sólo es cuestión de generar nuevos IDs de sesión para distintos clientes. El programa del lado del servidor nunca debería usar IDs entregados por el browser para un usuario logueado, esto es, una vez que el usuario se loguea en el sistema, éste debería generar automáticamente un nuevo ID de sesión y utilizar éste en el futuro.

El problema en el ejemplo que mostré anteriormente se podría prevenir fácilmente utilizando el siguiente código para el login:

if(($_POST['user'] == "demasiadovivo") && ($_POST['pass'] == "123456"))
{
session_regenerate_id();
$_SESSION['user'] = "demasiadovivo";
}


La función session_regenerate_id() crea un nuevo ID de sesión. De ésta forma, por más que hayamos usado un ID insertado por el atacante antes de loguearnos, una vez logueados utilizaremos un ID totalmente distinto y desconocido por el atacante.

Referencias

- Session Fixation Vulnerability in Web-based Applications
- Session Fixation (wiki)
- PHP Security Guide: Sessions

2 comentarios:

JaviZ dijo...

Una vez más un muuuuuy buen artículo (incluso hasta el título está bueno, tiene el correspondiente "buen punch" :).

Salu2 y pasate una navidad de pelos (pelos=kool),
Javi

Anónimo dijo...

Muy bien explicado, me ayudo mucho el articulo

Publicar un comentario