Cross Site Request Forgery [ CSRF / XSRF ]
Autor: SecurityKill
Fecha: 03/4/2008
Contacto: SecurityKill [ at ] gmail [ dot ] com
======================================
[ + ] Indice [ + ]
= > 0x001 < = => Introducción
= > 0x002 < = => Como funciona el CSRF / Pequeño ejemplo
= > 0x003 < = => Codeando una Aplicación Vulnerable
= > 0x004 < = => Evitando el CSRF
= > 0x005 < = => Despedida
======================================
[ + ] Introducción [ + ]
Bueno, en este paper vamos a hablar sobre lo que es CSRF / XSRF [ Cross Site Request Forgery ] .
Intentare explicar todo lo posible sobre esta vulnerabilidad y lo mas importante .. Como prevenir
estos ataques.
Empezemos .. =)
======================================
[ + ] Como funciona el CSRF [ + ]
Bueno, en el CSRF el atacante trata de " Forzar " algún codigo malicioso aprovechandose de una sesión
abierta o no caducada de la victima para asi lograr que la victima haga lo que nosotros queramos.
[ + ] Pequeño Ejemplo [ + ]
Bueno, digamos que estamos logueados en un foro .. y un usuario nos manda un mensaje privado diciendonos algo como :
" Hola, mira que buen tutorial de C++ .. [ Clic Aqui < = URL Maliciosa ] "
Y digamos que cuando el usuario clickee en el link lo va llevar a una pagina mas o menos como esta:
http://site.com/foro/index.php?action=logout
Esto cerraría la sesión del usuario .. pero que pasaría si en vez de cerrar la sesión del usuario pudieramos cambiar alguno de sus datos como su email / password ..
======================================
[ + ] Codeando una aplicación Vulnerable [ + ]
Esta aplicación será una cuenta .. Digamos que es un hosting de imagenes llamado " MyHosting " ... Y si queremos cambiar nuestros datos ( Email / password, etc ) .. Tenemos un formulario como el siguiente:
// Index.php
Código:
<form method="POST" action="datos.php" name="datos">
Usuario <input type="text" name="usuario">
Email <input type="text" name="email">
Contraseña <input type="text" name="contraseña">
Email alternativo: <input type="text" name="emailalternativo">
<input type="submit" name="submit" value="cambiardatos">
</form>
// Fin Index.php
===========================================
// Datos.php
Código:
<?
session_start();
if(isset($_REQUEST['usuario']))
$usuario = $_REQUEST['usuario'];
else
die("Rellene el campo Usuario");
if(isset($_REQUEST['email']))
$email = $_REQUEST['email];
else
die("Rellene el campo email");
if(isset($_REQUEST['contraseña']))
$contraseña = $_REQUEST['contraseña];
else
die("Rellene el campo Contraseña");
if(isset($_REQUEST['emailalternativo']))
$emailalternativo = $_REQUEST['emailalternativo];
else
die("Falta el email alternativo");
// Digamos que esta funcion llamada CambiarDatos
// es la que actualiza los datos de nuestra querida cuenta premium en MyHosting
CambiarDatos($usuario, $email, $contraseña, $emailalternativo);
?>
Entonces, a la hora de cambiar nuestros datos .. tendriamos una url mas o menos como esta:
http://http://myhosting.com/Datos.php.php?usuario=SecurityKill&email=mymail@gmail.com&
contraseña=mypass123&emailalternativo=mymail2@gmail.com
Entonces, aqui esta el peligro ... Que pasa si estamos logueados en la página .. y un usuario nos manda un link y lo vemos .. que contiene un codigo como este:
Código:
<html>
<head>
<title>Hi</title>
</head>
<body>
<img src="http://http://myhosting.com/Datos.php.php?usuario=SecurityKill&email=atackermail@gmail.com&contraseña=atackerpassword&emailalternativo=atackermail2@gmail.com">
</body
</html>
Si el usuario estuviera logueado en Myhosting.com y la victima viera esta página .. ¿Que pasaría? Se enviaría una petición HTTP a MyHosting y se cambiarían los datos del usuario ..
===========================================
[ + ] Evitando el CSRF [ + ]
Bueno, vamos a usar como ejemplo MyHosting ..
Tenemos el index.php ( Le he añadido un campo llamado "actualcontraseña " )
Código:
<form method="POST" action="datos.php" name="datos">
Usuario <input type="text" name="usuario">
Email <input type="text" name="email">
Contraseña <input type="text" name="contraseña">
Email alternativo: <input type="text" name="emailalternativo">
Contraseña Actual: <input type="text" name="actualcontraseña">
<input type="submit" name="submit" value="cambiardatos">
</form>
Un archivo llamado " config.php " que va a conectar a la bd:
Código:
<?php
$bd_host = "localhost";
$bd_usuario = "user";
$bd_password = "pass";
$bd_base = "bd";
$con = mysql_connect($bd_host, $bd_usuario, $bd_password); mysql_select_db($bd_base, $con);
?>
Y El archivo " datos.php " pero .. modificado:
Código:
<?
include('config.php');
session_start();
if(isset($_REQUEST['usuario']))
$usuario = $_REQUEST['usuario'];
else
die("Rellene el campo Usuario");
if(isset($_REQUEST['email']))
$email = $_REQUEST['email];
else
die("Rellene el campo email");
if(isset($_REQUEST['contraseña']))
$contraseña = $_REQUEST['contraseña];
else
die("Rellene el campo Contraseña");
if(isset($_REQUEST['emailalternativo']))
$emailalternativo = $_REQUEST['emailalternativo];
else
die("Falta el email alternativo");
if(isset($_REQUEST['actualcontraseña']))
$actualcontraseña = $_REQUEST['actualcontraseña];
else
die("Especifique la contraseña");
if ($actualcontraseña==NULL) {
echo "Especifique su contraseña Actual";
}else{
$query = mysql_query("SELECT usuario,actualcontraseña FROM myhosting_usuarios WHERE username = '$usuario'") or die(mysql_error());
$data = mysql_fetch_array($query);
if($data['contraseñaa'] != $actualcontraseña) {
echo "Contraseña Actual Inavalida";
}else{
CambiarDatos($usuario, $email, $contraseña, $emailalternativo);
?>
Lo que hariamos en este caso sería seleccionar Desde la BD la contraseña actual en la tabla myhosting_usuarios desde el campo " contraseñaa " si es diferente .. No se cambian los datos, si la contraseña coincide .. se realiza la operación .. en este caso .. hacer un update a la tabla " myhosting_usuarios " cambiando los datos del user.
Obviamente si quieren probar code en localhost van a tener que crear una bd y modificar
la función que cambia los datos del user ...
Pueden usar esta consulta SQL ..
Código:
CREATE TABLE `myhosting_usuarios` (
`id` int(11) NOT NULL auto_increment,
`usuario` varchar(15) NOT NULL,
`email` varchar(15) NOT NULL,
`emailalternativo` varchar(15) NOT NULL,
`contraseña` varchar(150) NOT NULL,
`contraseñaa` varchar(150) NOT NULL,
KEY `id` (`id`)
) ENGINE=MyISAM;
INSERT INTO `myhosting_usuarios` VALUES (1, 'SecurityKill', 'mymail@gmail.com', 'mymail2@gmail.com', 'mypass', 'mypass');
Otra forma de prevenir estos ataques .. sería usando CAPTCHA .. Aqui un codigo:
Código:
<?php
/***************************************************************************
*
* Filename : image.php
* Began : 2005/04/04
* Modified :
* Copyright : (c) 2005 xkare.com
* Version : 1.0
* Written by : Mert ÖÐÜT in istanbul / TURKEY
*
* You are encouraged to redistribute and / or modify this program under the terms of
* the GNU General Public License as published by the Free Software Foundation
* (www.fsf.org); any version as from version 2 of the License.
*
***************************************************************************/
session_start();
function strrand($length)
{
$str = "";
while(strlen($str)<$length){
$random=rand(48,122);
if( ($random>47 && $random<58) ){
$str.=chr($random);
}
}
return $str;
}
$text = $_SESSION['string']=strrand(5);
$img_number = imagecreate(47,17);
$backcolor = imagecolorallocate($img_number,244,244,244);
$textcolor = imagecolorallocate($img_number,0,0,0);
imagefill($img_number,0,0,$backcolor);
imagestring($img_number,50,1,1,$text,$textcolor);
header("Content-type: image/png");
imagejpeg($img_number);
?>
Creamos un campo de texto llamado code
Código:
<input type='text' size='5' maxlength='5' name='code'><img src="image.php">
Y Comprobamos que el codigo sea valido ..
Código:
if($_POST['code']!=$_SESSION['string']){
echo "Error en el codigo de seguridad "; exit();
}
===========================================
[ + ] Despedida [ + ]
Bueno, espero que les haya servido este paper sobre CSRF =)
Si van a publicarlo en otro foro / blog pongan la fuente y autor =)
Saludos, SecurityKill .