SQL Injection: Introducción

En este nuevo post vamos a hablar sobre una de las técnicas más conocidas y a su vez más frecuentes de encontrar hoy en día: las SQL injections. Voy a hacer una introducción muy simple para iniciar a aquellos que no conozcan cómo se realizan este tipo de ataques, y a continuación explicaré otros tipos de SQL Injection más complicadas.

La técnica de SQL injection permite descubrir información de una base de datos, elevar privilegios, suplantar usuarios y realizar una denegación de servicios.

Para que se pueda realizar correctamente una SQL injection, es necesario encontrar un fallo en la comprobación de los parámetros de entrada. Esto sucede cuando solo se comprueban los parámetros en el lado del cliente o cuando las comprobaciones realizadas son incorrectas o incompletas.

El problema surge cuando el programador realiza la construcción de las sentencias SQL como una cadena de texto a la que va concatenando los parámetros introducidos por el usuario. De esa forma, cuando se acaba de construir la cadena no se distingue qué parte de la cadena son comandos y qué parte parámetros.

 

Ejemplo de ataque SQL Injection

Veamos un ejemplo muy simple. Para ello, utilizaré una sandbox que se encuentra en la página web hack.me, que es una página con distintos retos que permiten probar y mejorar las habilidades de hacking.

SQL Injection: Introducción

Tan solo tenemos un formulario con un usuario y una contraseña, como encontraríamos en cualquier otra web. Si probamos a introducir cualquier valor, por ejemplo «carlos» y «pass«, nos indica que las credenciales son inválidas:

Al introducir las credenciales, probablemente se esté ejecutando una query de SQL con la siguiente estructura:

SqlQuery = " SELECT IDUser from user_table WHERE user ='$User' AND password = '$Pwd'"

Donde $User y $Pwd son dos variables que se obtienen del formulario cuando un usuario introduce sus credenciales. De esa forma, con las credenciales que he introducido anteriormente, se ha hecho una petición a la base de datos, pidiendo que se seleccionase el ID de usuario de la tabla «user_table» cuyo campo user sea «carlos» y  el campo password «pass«:

SqlQuery = " SELECT IDUser from user_table WHERE user ='carlos' AND password = 'pass'"

Como no se encuentra ningún usuario con esa combinación de nombre y contraseña, se devuelve el mensaje de error «Invalid Username/Password. Please try again.«

Bien, ahora probaremos si realiza algún tipo de  comprobación en sus parámetros. Para ello, probaremos a introducir una comilla simple ( ‘ ) al final del nombre de usuario, poniendo de usuario » carlos’ » y de pasword «pass«. Veamos que pasa:

¡El mensaje de error es distinto! Ahora nos indica que se ha producido un error en la sintaxis SQL. Esto es debido a que al meter una comilla extra, la sentencia SQL ahora ha quedado malformada:

SqlQuery = " SELECT IDUser from user_table WHERE user ='carlos'' AND password = 'pass'"

En el momento en el que nos sale un mensaje similar a este, está claro que esa página web es vulnerable a SQL Injection. Ahora hay que comprobar si somos capaces  de explotarla.

Vamos a añadir en el campo usuario un comando SQL que se confundirá con el parámetro y modificará la sentencia SQL. El comando es el siguiente:

 

Así, la sentencia SQL pasará a ser la siguiente:

SqlQuery = " SELECT IDUser from user_table WHERE user ='' or '1' = '1' -- a' AND password = 'pass'"

De esa forma la sentencia indica «Selecciona el IDUser de user_table donde el usuario sera ‘ ‘ o 1 sea igual a 1«. Como 1 es igual a 1, da igual si el usuario es ese o no, porque la sentencia va a dar True en cualquier caso.

Los guiones ( – – ) se utilizan en SQL para indicar comentarios, por tanto al ponerlos al final, todo lo que siga a continuación será descartado (de esa forma, el final de la query anterior no hace que se nos quede una query mal formada). Es importante poner un espacio y cualquier caracter detrás de los guiones, porque aunque a priori daría igual, a veces al pasarlo a la base de datos no lo reconoce como comentario si sólo hay dos guiones al final del parámetro inyectable.

Veamos que nos dice el servidor al introducir esto:

 

¡Conseguido! Hemos logrado entrar en la base de datos. Esto ha sido un ejemplo muy sencillo para introducir las bases de la SQL Injection.

Dependiendo de qué coloquemos en los parámetros, podemos conseguir obtener distintos resultados de la base de datos. De esta manera hemos accedido con la autenticación del primer usuario que hay en la base de datos.

Si quiseramos acceder con un usuario concreto, deberíamos haber escrito:

Usuario = «cualquiera»        Password = » ‘ or user = ‘carlos

Para que la consulta SQL se quedara como sigue:

SqlQuery = " SELECT IDUser from user_table WHERE user ='cualquiera' AND password = '' or user = 'carlos'"

Si lo que queremos es obtener información sobre una tabla de la base de datos concreta, por ejemplo, la tabla «admin_table«, entonces debemos adaptar la query para obtener esa información, introduciendo en el usuario « ‘; SELECT * from admin_table; — a «:

SqlQuery = " SELECT IDUser from user_table WHERE user =''; SELECT * from admin_table; -- a' AND password = ''"

O también podemos hacer esta misma query mediante un UNION.

Y no solo podemos leer de la base de datos, sino que podemos modificarla (UPDATE), eliminarla (DELETE) o añadir información falsa (INSERT).

A la hora de intentar explotar una página web para intentar realizar una SQL Injection, lo primero que debemos averiguar es qué tipo de base de datos utiliza. Según el tipo de base de datos, la sintaxis SQL difiere. Las bases de datos más utilizadas son Oracle, MSSQL, MySQL y PostgreSQL.

Te recomiendo este enlace a pentestmonkey.net, donde hay una Cheat Sheet con ejemplos sobre distintas querys que se pueden hacer según lo que queramos hacer y el tipo de base de datos que sea. A mi me ha sido muy útil en multitud de ocasiones.

Tipos de ataques SQL Injection

Existen diferentes tipos de ataques para explotar una SQL Injection en una web. El tipo de ataque a realizar depende fundamentalmente de cómo sea la query sobre la que se está realizando y de lo que devuelve la página al intentar introducir una SQLi:

  • Staqued Queries. Consiste en colocar nuevas consultas al final de la consulta inyectable. El ejemplo anterior que hemos visto pertenece a este tipo. Es el mejor método puesto que es el que más cosas permite sacar de la base de datos, por lo que es la mejor opción si está disponible.
  • Union query based.  Recupera datos añadiendo una query a la original mediante el comando UNION. Necesitas poder ver los resultados de la query en la página web para que funcione.
  • Error based. Manipula los mensajes de error para mostrar en ellos los datos de la base de datos. Un ejemplo de este tipo de SQLi lo encontramos en el CTF de Juego de Tronos que publiqué hace un tiempo.
  • Inline queries. Este tipo de ataque consiste en embeber una query en otra (SELECT(SELECT…)…).
  • Boolean blind. Consiste en hacer queries de tipo true/false y según los cambios en las respuestas, ir descubriendo información sobre la base de datos. Por ejemplo, si inyectamos ‘ or ‘1’ = ‘1’ y nos devuelve un mensaje de error A, e inyectamos ‘ or ‘1’ = ‘2’ y nos devuelve otro mensaje de error B que es distinto del mensaje de error A, podemos inyectar ahora ‘ or current_user = ‘carlos’. Si nos devuelve el mensaje de error A, el usuario es carlos, en caso de que devuelva el mensaje de error B, no lo es. A base de ir probando con inyecciones así, podemos averiguar toda la información que contiene la base de datos.
  • Time based blind. La lógica es la misma que en el caso anterior, pero en vez de contrastar entre distintas respuestas, comprueba distintos tiempos de respuesta. Por ejemplo, para averiguar si el usuario es carlos, inyectaríamos ‘ or (current_user = ‘carlos’ and WAITFOR DELAY ‘0:0:10’). Si el usuario es carlos, la consulta tardará 10 segundos más de lo habitual en ejecutarse, si no lo es, el tiempo de respuesta será el habitual en esa web.
 

SQLMap

Tal y como puedes intuir, realizar manualmente estos ataques puede ser muy tedioso. Para automatizar el proceso, se creó la herramienta SQLMap. Esta herramienta permite dumpear la base de datos completa una vez que ha encontrado un patrón, probando cientos de payloads con sentencias diferentes.

 

No obstante, mucha gente se conforma con pasar SQLMap con las opciones por defecto, y si no encuentra un comando inyectable, se da por vencida. SQLMap es una herramienta muy potente, pero es necesario configurarla bien para aprovechar el máximo potencial. Por ello, a continuación describiré los principales parámetros de configuración de SQLMap.

  • – – prefix: prefijo. Irá antes de cada query. Por ejemplo, » admin’ «.
  • – – sufix: sufijo. Irá siempre después de cada query. Por ejemplo, » – – a «.
  • – – test-filter: sirve para filtrar los payloads al tipo que pongas. Por ejemplo, con ‘- -test-filter=ORDER BY’ solo se ejecutarán las querys que contengan ‘ORDER BY’.
  • – -test-skip: quita los payloads del tipo que pongas. Por ejemplo, con ‘- -test-skip=ORDER BY’ se ejecutarán todas las querys excepto las que contengan ‘ORDER BY’.
  • – v3: verbosity
  • – p <parámetro vulnerable>: indicas qué parámetro es vulnerable a la sqli.
  •  – – technique: técnica a emplear. Puede ser Stacked queries (S), Union query based (U), Error based (E), Inline queries (I), Boolean blind (B) y Time based blind (T). Por ejemplo, con – – technique=SB le estaríamos indicando que queremos que intente inyectar las distintas sentencias asociadas al método Stacked queries y al método Boolean blind.
  • Risk: riesgo de que se produzca un error. Los payloads que menos riesgo tienen son las de riesgo 1, y las que más las de riesgo 2.
  • Level: cantidad de peticiones por payload. El nivel 1 realiza pocas peticiones mientras que el nivel 5 realiza muchas.
  • – – string: indicas que cadena de texto debe aparecer en la respuesta cuando el resultado sea TRUE.
  • – – no-string: indicas la cadena de texto que debe aparecer en la respuesta cuando el resultado sea FALSE.
  • – – regexp: indicas una expresión regular que debe coincidir con la respuesta cuando el resultado sea TRUE.
  • – – code: indicas el código HTTP que debe mandar el servidor cuando el resultado sea TRUE.
  • – – second-order: Si el SQLi afecta a otra página distinta a la que es vulnerable, indicas la página aquí y comprobará la respuesta en esta página y no en la que está inyectando el payload.

Además, existe una extensión de Burp Suite que integra SQLMap. Su nombre es Burp C02, y tan solo hay que rellenar las distintas opciones y la extensión genera el comando necesario:

 

En este caso, el comando sería:

sqlmap -u 'https://hackinglethani.com/es/ctf-juego-de-tronos/' --level=5 --risk=3 --string='user or password wrong' --technique=QTBS --cookie='ACCESOSESSID=a123e4fb567ba8c9'

Proximamente subiré un blog explicando cómo obtuve toda la información de una base de datos con una de las SQL Injection más dificiles que me he encontrado hasta ahora.

Lethani.

4.2/5 - (225 votos)

11 comentarios en «SQL Injection: Introducción»

    • Depende. Cada caso es un mundo. Depende de la base de datos, de que otros servicios están corriendo en ese servidor… Por ejemplo yo trataría de crackear la contraseña del administrador y probar a ver si reutiliza esa contraseña para algún otro servicio, como SSH. También puedes intentar ejecutar comandos en la query de SQL si tienes suficientes privilegios, aunque no esté corriendo como root, por ejemplo en MSSQL lo puedes hacer con «EXEC xp_cmdshell ‘‘;»… O quizá con esas credenciales de la base de datos puedas acceder a un servicio que esté corriendo en el servidor y que sea vulnerable, como una página web en la que puedas subir un archivo malicioso y realizar un RFI… Lo dicho, depende mucho de cada situación específica.

      Responder

Responder a Lethani Cancelar la respuesta