lunes, 19 de febrero de 2018

SQL Injection para dummies (Segunda parte)

Hola de nuevo.

Aquí tenemos la segunda entrada sobre SQL Injection. En la anterior nos quedamos en descubrir un parámetro vulnerable y el por qué de que esto sea así. Ahora vamos a pasar a jugar con la vulnerabilidad y a hacer cosas más vistosas.
Sabiendo la estructura exacta de la consulta SQL podríamos llevar a cabo ataques mucho más precisos, pero rara vez vamos a tener acceso al código a la hora de realizar un pentest. Por tanto, vamos a ir dando palos de ciego y viendo qué nos encontramos a medida que avanzamos con el ataque.


Para empezar, vamos a probar el mágico “ ' or ‘1'='1 “ a ver qué nos muestra. Colocamos la comilla simple y a continuación la estructura anterior, y vemos que se muestran todos los usuarios de la base de datos.



Analicemos el por qué. Con la comilla simple cerramos el parámetro id, y hacemos una OR con la comparación 1 = 1 (que siempre es verdadera), por tanto la condición del WHERE será verdadera para todos los casos.
Es importante observar que el último 1 no tiene comilla simple de cierre, ya que empleamos la que tiene por defecto la consulta SQL que estamos explotando, de manera que ya no tengamos un error de sintaxis, y se ejecute bien lo que queremos.

Si bien mostrar todos los usuarios de la base de datos es una fuga de información muy grande, nosotros no nos contentamos con ello solamente, porque si podemos ejecutar consultas a nuestro antojo dentro de la base de datos, podemos hacer lo que queramos con ella.

Para continuar con el ataque vamos a averiguar cuántas columnas se muestran al realizar la consulta SELECT. Aunque pueda parecer que es visible a priori, en otros casos no lo será tanto, y por tanto voy a explicar el proceso. Para esto vamos a emplear el operador UNION, que combina el resultado de dos SELECT. En este caso lo que introduciremos en el formulario será “ ‘ union select 1 # “. Desglosemos un poco esta sentencia. Con la ‘ cerramos el parámetro id, con el union combinamos el select anterior con lo que pongamos a continuación, y el select 1 intentará mostrar solo un 1, por tanto una columna. El # del final es empleado para poner comentarios, por tanto todo lo que se escriba a continuación se pasará por alto. Así se ejecutará solamente lo que nosotros hayamos especificado.
¿Qué pasa aquí?, que el operador UNION solo funciona si ambos SELECT tienen el mismo número de columnas, por tanto dará error en caso contrario. De esta forma, probando averiguaremos el número de columnas de la sentencia principal.
Al introducir la sentencia anterior, vemos un mensaje The used SELECT statements have a different number of columns que nos indica que no tiene el mismo número de columnas.

Probemos con “ ‘ union select 1, 2 # “.



En este caso no nos salta ningún error, lo que significa que hemos acertado con el número de columnas. De ahora en adelante debemos hacer un SELECT con dos columnas para hacer el UNION e ir explotando la vulnerabilidad poco a poco.
En este caso ha sido rápido encontrar el número de columnas, pero según el escenario en el que os encontréis puede ser más tedioso, pero el mecanismo a seguir es el mismo.

Comencemos pues a obtener más información del sistema objetivo. Lo más básico podría ser obtener el usuario con el que se ejecutan las sentencias que introducimos, y por ejemplo también el nombre de la base de datos objetivo. Para este caso la sentencia que emplearemos será “ ' union select user(), database() # “ que emplea funciones que devuelven los datos que deseamos.



Observamos que el usuario se llama “root”, y que la base de datos se llama “dvwa”. Empleando la misma estructura de consulta, y cambiando las llamadas a esas funciones por otras, podríamos obtener más información del objetivo. Con “version()” obtendríamos la versión (valga la redundancia); con “concat()” y pasándole por parámetros campos de la base de datos, obtendríamos los datos de dichos campos en el mismo resultado, lo cual veremos más adelante.
También podemos emplear “@@datadir” para obtener el directorio donde se encuentra la base de datos en el sistema objetivo, “@@port” para ver en qué puerto está corriendo el servicio, y “@@version_compile_os” para ver para qué sistema operativo está compilado el programa de gestión de base de datos.
Adicionalmente tenemos una función que nos permite leer archivos del sistema objetivo en el que está la base de datos: LOAD_FILE('[ruta del archivo]'). Con él podemos leer cualquier archivo sobre el cual el usuario del sistema que posee el proceso del programa de gestión de la base de datos tiene permisos.



Y hasta aquí la segunda entrada sobre SQL Injection.

Un saludo y nos vemos en la siguiente!

AlDr0id

0 comentarios:

Publicar un comentario