lunes, 27 de enero de 2014

Las mejores inyecciones son chorizos y jamones (parte 3)

3.2 Haciendo daño (DROP TABLE)

Preguntémonos ahora si sería posible llevar al cabo el caso del DROP TABLE descrito en el apartado 1.

Imaginemos que el atacante no sabe el nombre de las tablas de nuestra BD. Para ilustrar qué pasaría en este caso, primero probaremos con una tabla que no exista introduciendo en el nombre de usuario la expresión

' or '1'='1'; drop table kk2--

Y al pulsar el botón "Entrar" obtenemos


Imagen 3.1 Intentando eliminar una tabla inexistente

Bueno, no sabemos si ha funcionado el DROP TABLE o ha fallado, pero sí sabemos que no se produce ningún mensaje de error. El atacante podría ir haciendo pruebas por fuerza bruta, hasta encontrar una tabla que sí exista. Para probarlo, he creado en la BD una tabla "kk" y quiero ver si se elimina y se me notifica de ello. He repetido la prueba

Imagen 3.2 Intentando eliminar una tabla que sí existe

Como véis, ningún mensaje de error o éxito. Pero al comprobar si  la tabla sigue viva me encuentro con (...redoble de tambores...)

¡Vaya, ha desaparecido! (bueno, aquí no tengo una imagen para ilustrar esto, pero tendréis que creerme, es que un pantallazo en este caso no aporta nada).

Hmmm... peligro, peligro...

En este caso, el atacante no sabe si su técnica ha funcionado, pero si lo que le interesa simplemente es hacer daño, no le sería demasiado complicado realizar un script que fuera generando por fuerza bruta todas las combinaciones de nombres entre 1 y 30 caracteres (pongamos por caso) y cargarse nuestra BD completa. Vale que esto llevaría un buen rato, pero el lobo tiene tiempo libre y ganas de fastidiar.

Según he leído (esto no lo he probado), la ejecución de dos sentencias SQL en una única llamada a la función correspondiente no funciona con todas las BBDD. Según dicen, en MySQL no funcionaría. Pero yo acabo de comprobar que en SQL Server sí funciona, así que ¡CUIDADÍN!

3.3 Meter basura en casa (INSERT INTO)

Continuando con nuestras pruebas, imaginemos por un momento que el atacante sabe el nombre de la tabla de usuarios y los campos, al menos el del nombre del usuario y el del hash de la clave (login y epass, respectivamente, en nuestro ejemplo). Pensar que un atacante sabe tanto no es descabellado, pues es relativamente sencillo forzar errores que, si no se gestionan bien (casi nunca se gestionan bien al 100%) revelan algunos de estos datos. Más adelante veremos algunos ejemplos sobre formas de obtener información acerca de la BD, como nombres de tablas, campos, etc...

En ese caso, podría intentar insertar un registro que le proporcione una cuenta de usuario. Algo así como:

' or '1'='1'; insert into usuarios(login, epass) values ('lobito', 'x')--

Donde 'x' sería el valor hash de la clave que él desea ponerse. Vale, aquí quizás estamos suponiendo ya demasiado, como que se utiliza un algoritmo u otro (MD5, SHA1...) para calcular el hash, pero tampoco esto es descabellado. Además, utilizar una "sal" (salt) para la contraseña dificultaría el ataque, pero de momento seguimos con ejemplos en entornos más o menos sencillos.

Bien, pues introducida la expresión que he puesto, pulsamos Entrar y...

Imagen 3.3 Nos la han colado doblada

¡Vaya, ahí está el registro insertado!

Que luego esa información le sea más o menos útil al lobo en su lucha contra la Caperumadre es otra cosa, pero el caso es que ya ha conseguido introducir datos ficticios, basura, en la BD. ¡Hmmm, malo, malísimo!

La semana que viene continuaremos.

Referencia:

Las mejores inyecciones son chorizos y jamones (un cuento de inyección SQL). 

Parte 1
http://cosicasdeinformatica.blogspot.com.es/2014/01/las-mejores-inyecciones-son-chorizos-y.html

Parte 2
http://cosicasdeinformatica.blogspot.com.es/2014/01/las-mejores-inyecciones-son-chorizos-y_23.html

jueves, 23 de enero de 2014

Las mejores inyecciones son chorizos y jamones (parte 2)

En la parte 1 hablé de la teoría; ahora vamos a montar un entorno básico y a hacer algunas pruebas, a ver si lo que allí se contaba es así realmente.

2. Un entorno de pruebas

Para tener un entorno de pruebas, crearé dos páginas PHP, una con el formulario de solicitud de datos y otra con el resultado del procesamiento. Probablemente, en una aplicación real esta página sea la misma, o no, pero de momento estamos haciendo algunas pruebas "de juguete".

 1 <html>
 2     <head>
 3         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 4         <title>Pruebas SQL Injection</title>
 5     </head>
 6 <body>
 7     <h1>Introduzca usuario y contraseña</h1>
 8     <form action="test2_res.php" method=POST target=_blank>
 9         Usuario <INPUT TYPE="text" NAME="usuario" SIZE=20 MAXLENGTH=20>
10         <br>
11         Contraseña <INPUT TYPE="password" NAME="pwd"   SIZE=20 MAXLENGTH=20>
12         <br>
13         <INPUT TYPE="submit" CLASS="boton" VALUE="Entrar">
14     </form>
15 </body>
16 </html>
Listado 2.1. La página de prueba

que se ve más o menos así (con variaciones mínimas entre navegadores):

Imagen 2.1 Como véis, todo un derroche de diseño y buen gusto.

Y la parte de procesamiento en la página 2 podría ser algo más o menos así:

 1 <?php
 2     //...otras cosas
 3     
 4     $conn = conectar_bd(); //falta control de errores
 5     $usuario = $_POST['usuario'];
 6     $pwd     = $_POST['pwd'];
 7     $epwd    = strtoupper(md5($pwd));
 8     echo "Datos leídos '$usuario' y '$pwd' -->encriptada: '$epwd'<br>";
 9     $sql = "select login, epass from usuarios where login = '$usuario' and epass = '$epwd'";
10     $rs=odbc_exec($conn, $sql);
11     if (!$rs) {exit("Error en SQL");}
12     
13     $encontrados = 0;
14     while ($row = odbc_fetch_array($rs)) {
15         $encontrados++;
16         echo "encontrado registro " . $row['login'] . " " . $row['epass'];
17     }
18     
19     if ($encontrados == 0) {
20         echo "no se encontró el usuario";
21     }
22     
23     //... otras cosas
24 ?>
Listado 2.2. La página que procesa el login y la clave introducidos

Como habréis visto, si habéis leído el código (si no lo has hecho, vuelve unas líneas arriba y léelo antes de continuar), la clave no se almacena en claro, sino que se almacena su hash MD5, pero esto no cambia en nada la prueba de concepto y lo que hemos dicho hasta ahora (sólo añade un poco de realismo a la situación, ya que esto es algo habitual en sistemas reales). También veréis que el procesamiento se limita a listar todos los registros que se encuentren que cumplan la condición, que en principio es que coincida el login con el que ha introducido el usuario, y el hash de la contraseña introducida con el hash almacenado en el campo "epass" (e de encriptada). En un sistema real en producción, lógicamente este listado de los registros recuperados no se haría, pero para nuestras pruebas es más ilustrativo. También voy a mostrar la sentencia SQL que se ejecuta, ya que a efectos de muestra va a ser de ayuda para entender lo que está pasando por dentro, y el hash de la clave introducida, esto es simplemente porque durante las pruebas lo hice así y ahora no me apetece repetir las capturas de pantalla quitando esto.

Por otra parte, en la BD, montada sobre un servidor SQL Server, he dado de alta un usuario con nombre 'caperu' y contraseña 'reparto1'.

Primero insertamos un par usuario / clave normal y vemos que todo funciona como se espera:



Si introducimos una clave incorrecta:




Bueno, en apariencia todo funciona más o menos bien. Con esto ya tenemos el entorno de prueba montado. Manos a la obra.

3. Haciendo algunas pruebas

Ahora intentaremos probar casos similares al descrito en el apartado 1 para ver si conseguimos obtener el mensaje de acierto: "encontrado registro..."

3.1 ¿Es uno igual a uno?

En primer lugar, supongamos que el lobo está engandulado, y se limita a meter en el campo "usuario" la siguiente expresión:

' or '1'='1'--

y deja la contraseña en blanco (¿para qué teclear sin necesidad?). Le da a ejecutar... et voilà! (La explicación a por qué usar esta expresión está en la parte 1, así que no me voy a repetir aquí).




Vaya, esto pinta mal, ¿eh? El lobo malo ha conseguido revelar todos los nombres de los usuarios, incluyendo el de Caperucita (usuario "caperu"). Además, puede decir que ha entrado en la BD. Por supuesto, en un sistema real se comprobarían otras cosas, pero estamos trabajando con una prueba de concepto y el ejemplo ya nos permite atisbar algunos de los peligros de esta técnica.

Bueno, creo que hasta aquí ya está bien por hoy. Hemos montado un entorno de pruebas y esta primera prueba ha sido suficiente para tomar conciencia del problema. 

¿Qué pruebas se te ocurre que podría hacer el lobo a continuación? ¿Cómo podría la Caperumadre prevenirse contra esto? 

La semana que viene seguiremos con el tema...

Referencia:

Las mejores inyecciones son chorizos y jamones (un cuento de inyección SQL). Parte 1
http://cosicasdeinformatica.blogspot.com.es/2014/01/las-mejores-inyecciones-son-chorizos-y.html

martes, 14 de enero de 2014

Las mejores inyecciones son chorizos y jamones (un cuento de inyección SQL). Parte 1

Bien es verdad que hace casi 4 meses que no escribo en este blog, pero este año me he propuesto escribir un poco más que el pasado. Cosa que no será muy difícil, ya que el año pasado sólo escribí cinco entradas. De momento, he empezado con una serie que me dará para varias entradas.