martes, 9 de febrero de 2016

PoC: Inyección SQL simple (I)

La inyección SQL se mantiene como Top 1 en el Top 10 de OWASP de los riesgos de seguridad más explotados en el año 2013. Actualmente, la cifra no debería ser muy diferente.

Aunque la mayoría de los frameworks utilizados para el desarrollo web incorporan ya herramientas para evitar este tipo de filtraciones mediante el uso de funciones propias para el tratamiento de los formularios y las solicitudes, podemos aún encontrar una gran cantidad de páginas web vulnerables a este tipo de explotación. La inyección SQL no pasa de moda.

La razón de que este riesgo de seguridad esté tan extendido es, en primer lugar, la relativa facilidad con la que puede explotarse una vulnerabilidad de este tipo. Mediante unos conocimientos mínimos de SQL y algunos lenguajes de programación web puede deducirse a priori algunas características de la aplicación víctima que nos puede llevar a la explotación tras nos pocos intentos; sin hablar de herramientas automatizadas que realizan el trabajo de forma fácil y rápida.

En primer lugar, os recomiendo explorar un poco los fundamentos importantes de las bases de datos relacionales y el lenguaje SQL, utilizado para realizar consultas sobre ellas. A grandes rasgos, es un tipo de base de datos que almacena y organiza la información en entradas sobre diversas tablas, sobre las que se pueden realizar posteriormente consultas que permiten añadir, recuperar o modificar información sobre estas tablas. Estas consultas se realizan mediante lenguaje SQL.

Por la facilidad en el manejo y la velocidad que ofrecen estas bases de datos, son el recurso más utilizado para almacenar la información de aplicaciones y servicios web. Entre ellas, las más utilizadas son Oracle, MySQL y Microsoft SQL Server.

En esta pequeña prueba de concepto pretendo mostrar el fundamento básico de una vulnerabilidad web explotable de forma sencilla mediante inyección SQL. Para ello será necesario tener instalado tanto un servidor web y un sistema gestor de base de datos, que alojarán la aplicación vulnerable. Como consejo, una máquina virtual Linux con Apache2 y MySQL no tarda mucho tiempo en configurarse para estar operativa.

Por cierto, incluiré enlaces a GitHub para cada fragmento de código para que podáis verlo y copiarlo de manera más sencilla.

El primer paso será crear el formulario vulnerable. Es tan simple como crear un formulario HTML con campos para el usuario y la contraseña. Lo mantendremos simple y sin adornos para la prueba.

No se puede crear más simple
Asimismo, necesitamos un fichero PHP que recibirá los datos del formulario, conectará con la base de datos y ejecutará la consulta que nos permitirá identificarnos como un usuario del sistema. Atención a esta parte del código, que realiza la consulta a la base de datos:

Consulta a la base de datos
En la consulta, guardada en la variable llamada $sql, indicamos que queremos que se nos devuelvan todos los datos (a modo de ejemplo) de aquel usuario identificado con las credenciales recogidas por el formulario anterior, que están almacenados en la tabla login_table. Por último, se mostrará un mensaje de bienvenida para el usuario cuyos datos hemos recuperado, como puede verse en el código más adelante.

Aunque no es un login como tal, dado que no creamos o mantenemos una sesión, sirve para ejemplificar un tratamiento de formularios y una consulta en la base de datos para realizar la autenticación.

Supongamos que los usuarios almacenados son solamente dos: admin, que puede ser fácilmente el mismo administrador de la aplicación y cuya contraseña a modo de ejemplo será adminPass, y pepe, un usuario cualquiera, cuya contraseña será userPass (¡malas elecciones en el mundo real!). Podemos identificarnos correctamente como cualquiera de los dos usuarios.

Ahora empecemos con las pruebas de verdad. Una de las formas de inyección más extendidas es introducir una condición no prevista en la consulta SQL. ¿Cómo podemos hacerlo? Mediante la manipulación de la entrada que introducimos en el formulario.

De forma "normal", la query o consulta a la base de datos con el usuario pepe y su contraseña sería:

select * from login_table where usuario='pepe' and contraseña='userPass';

A grosso modo, lo que hace es preguntar a la base de datos por los datos de un usuario cuyo nombre es pepe y su contraseña es userPass; amablemente, la base de datos nos los devuelve. Tenemos por tanto dos condiciones en la búsqueda: que el usuario sea pepe Y que la contraseña sea userPass.

¿Qué pasa si manipulamos un poco la entrada de la contraseña, jugando con las comillas simples que suelen utilizarse para introducir los campos de la consulta? Que podemos introducir una condición extra, ya que el código en este caso lo permite. Introduzcamos en el campo de contraseña el valor 'or'1'='1. De esta manera, la consulta a ejecutar quedaría de la siguiente manera:

select * from login_table where usuario='pepe' and contraseña='userPass' or '1'='1'; 

¡¡Boom!!

El resultado es que hemos sido identificados como administrador. ¿Qué ha pasado aquí?

La explicación es simple: con el código introducido en el campo de contraseña, la consulta busca los datos de un usuario cuyo nombre es pepe Y cuya contraseña es userpass O 1 es igual a 1. Dado que 1 siempre es igual a 1, la primera entrada de la tabla es verdadera, y son sus datos los que se devuelven como resultado. Como la primera entrada es la del administrador... ¡nos hemos identificado como el mismo!

Para entender la lógica de esta consulta es necesario conocer una ley básica del álgebra de Boole, en la que se basan las operaciones lógicas como esta. La operación AND tiene precedencia sobre OR; es decir, se evalúa antes. En este caso, ello implica que  al comprobar si una entrada de la tabla concuerda con los criterios, se dan como correctos los casos en los que o tanto el usuario como la contraseña coinciden, o 1 es igual a 1 (o ambas). Por tanto, siempre se devolverá la primera entrada que se encuentre, dado que será correcta.

Esta forma de inyectar SQL es la más básica y comúnmente probada, pese a que a estas alturas debería estar prácticamente erradicada; la realidad, por desgracia, no es tan ideal. Muchas aplicaciones web son aún, por desgracia, débiles a este tipo de ataques.

Más adelante intentaré ampliar el ejemplo con otras sentencias de inyección que funcionarían, e intentaré ampliar un poco la explicación teórica. Espero que hasta el momento os sirva para conocer de forma muy básica la inyección SQL.

Un saludo!!
hartek

No hay comentarios:

Publicar un comentario