[spanish] Cross Site Request Forgery - CSRF

2008-05-14
ID: 36370
CVE: None
Download vulnerable application: None
[ + ] Información del Paper [ + ] 

Cross Site Request Forgery [ CSRF / XSRF ] 
Autor: Tec-n0x  ;)
Fecha: 03/4/2008
Www.Editcodex.NET
Contacto: Tec-n0x [ at ] hotmail [ 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.


[ + ] Definición mas Completa ( Gracias C1c4Tr1Z ) : [ + ]

Un ataque basado en la utilización de <tags> html que realicen mediante una petición HTTP GET una acción directa (ej: <img src=http://mail.google.com/mail/?logout&hl=es>) o una acción indirecta (ej: <img src=http://www.atacante.com/xsrf.html>) , utilizando un archivo HTML que realice peticiones POST/GET, sin que la víctima de este ataque de su consentimiento o aprobación, ya que es un ataque que actúa silenciosamente. Este ataque puede a su vez aprovecharse de cookies (activas o caducas) o a la vez realizar acciones que no las utilicen en cualquier tipo de web.

[ + ] 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

==================================================================
     <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


<?
     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=Tec-n0x&[email protected]&
contraseña=mypass123&[email protected]

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:

==================================================================

<html>
<head>
<title>Hi</title>
</head>
<body>
<img src="http://http://myhosting.com/Datos.php.php?usuario=Tec-n0x&[email protected]&contraseña=atackerpassword&[email protected]">
</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 " )

==================================================================

     <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:

==================================================================

<?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:

==================================================================

<?

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 ..

==================================================================

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, 'Tec-n0x', '[email protected]', '[email protected]', 'mypass', 'mypass');

==================================================================

Otra forma de prevenir estos ataques .. sería usando CAPTCHA .. Aqui un codigo:

==================================================================

<?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

==================================================================

<input type='text' size='5' maxlength='5' name='code'><img src="image.php">

==================================================================

Y Comprobamos que el codigo sea valido ..

==================================================================

if($_POST['code']!=$_SESSION['string']){ 
echo "Error en el codigo de seguridad "; exit();
}

==================================================================

===========================================

[ + ] Despedida [ + ]

Bueno, espero que les haya servido este paper sobre CSRF =)

Gr33tz t0: Celciuz, You_kn0w, C1c4Tr1Z, N.O.X, H-Black, lEnergy, Syst3m-c0der, etc =)

Www.Editcodex.NET

Saludos, Tec-n0x  ;)
1-4-2 (www01)