[Curso] SQL Injection desde 0 - Union based y Blind Boolean Based.

Iniciado por M5f3r0, Agosto 24, 2013, 02:37:48 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Agosto 24, 2013, 02:37:48 AM Ultima modificación: Julio 21, 2016, 07:23:36 AM por blackdrake
La Inyección SQLi vendría siendo una técnica muy conocida en la internet, la cúal consiste en la ejecución de consultas SQL a la base de datos que se presentan en una aplicación web, La Inyección SQL se debe a la mala filtración de nuestras variables las cúales son llamadas en nuestras consultas SQL.

Existen dos formas en la vulnerabilidad SQLi, String o Integer. La String vendría siendo como cuando tenemos una variable la cúal está encapsulada entre dos "$id" y la integer en caso contrario.

- Union Based:

Para iniciar el curso comenzaremos con lo más básico, "Union Based", La cúal se basa en la selección de una union, en la que hacemos uso de la sentencia "SELECT", un ejemplo en una consulta SQL:

Código: php
SELECT id,0x7e,username,0x7e,password,0x7e,email FROM users


Vendría siendo una consulta SQL la cúal se encarga de seleccionar las columnas "id,username,password y email" que pertenecen a la tabla "users".

Y como lo pudieron notar use "0x7e" lo que equivale a ~ en hexádecimal y use al principio 0x para que el servidor MySQL lo pueda entender. Lo uso para distinguir los resultados.

1.- Consulta vulnerable en nuestro archivo PHP:

Código: php
$sql = "SELECT * FROM users WHERE nombre='m5f3r0'"; // Consulta SQL vulnerable en la variable $sql
mysql_query($sql) // Hacemos la consulta


La consulta SQL vulnerable se encontraría en nuestra variable $sql en la que hacemos una selecciçon de la tabla "USERS"

Y al final procedemos a realizar la consulta MySQL llamando a la variable $sql la cúal contiene nuestra consulta que haremos a la base de datos, y luego uso "WHERE" para llamar a la columna "nombre" y seguidamente de algún registro o valor, en este caso "m5f3r0".

2.- Identificación entre "String y Integer"

Bueno, ya entendemos la consulta SQL vulnerable en nuestro sitio, ahora procederemos a la extracción de los datos del servidor mediante el uso de consultas SQL. Antes de hacer esto, debemos conocer el tipo de vulnerabilidad, es decir, si es String o Integer. Anteriormente ya explique que son estás dos cosas.

En la URL del sitio web vulnerable, supongamos que tenemos la siguiente ruta:

www.vulnerable.com/categoria.php?id=1

En dónde procederemos a realizar nuestras consultas seguidamente del parámetro "ID" el cúal es el vulnerable.

Primero comprobaremos si es string, para ello coloquemos una ' al final del id 1, ejemplo: categoria.php?id=1'

Y nos reflejara el error "You have an error in your SQL;.." , ahora colocaremos al final algún comentario en MySQL. MySQL permite los siguientes comentarios:

1: -- - o -- Comentarios de 1 sola línea
2: # Comentario de 1 sola línea
3:
/*
y
*/ Comentarios de varías líneas

Lo que vaya seguido de estos comentarios no lo leera el servidor.

Entonces procedemos, para comprobar si es string seguido de la ' añadimos algún comentario, yo usare -- - . Si automáticamente se nos fixea (es decir, se nos quita el error) significa que es de tipo String.

En caso contrario, es decir, si no se fixea significa que es integer y tendremos que hacer la inyección sin una ' a partir de ahora, ej: categoria.php?id=1 SELECT 80+1 -- -comentario

3.- Comprobar las columnas vulnerables

Seguidamente debemos comprobar cuales son las columnas vulnerables a las que procederemos a inyectar, para ello, haremos uso de la clausula "order by" o "group by" una se encarga de ordenar y la otra de agrupar. Para ello inyectaremos lo siguiente en la URL:

categoria.php?id=1 order by 10 -- -comentario

Si nos sale algún resultado como "in order clause"

Esto significa que no coincide con el número especificado, es decir, tiene menos columnas. Pero si en caso de que nos salga la página normal, significa que tiene más columnas o tiene esa misma que hayamos especificado.

Yo probe con 10 y si coloco 9:

categoria.php?id=1 order by 9 -- -comentario

Y me sale la página normal significa que tiene 9 columnas, ahora haremos uso de las sentencias "UNION SELECT 1,2,3,4,5,6,7,8,9".

Ahora podemos proceder a la extracción de datos del servidor y del sitio web.

3.- Extrayendo los nombres de las bases de datos

Ahora procederemos a la extracción de los nombres de las bases de datos, para ello haremos la extracción de metadatos (datos de otros datos por decirlo así) los cuales se encuentran en una base de datos especial del servidor MySQL llamada "information_schema" , la cúal almacena todo tipo de datos de nuestro servidor, como nuestro usuario MySQL, privilegios, nombres de tablas, bases de datos, etc..

En la base de datos "information_schema" hay una tabla llamada "schemata", en la cúal se almacenan los registros de los nombres de nuestras bases de datos, que creamos nosotros mismos.

En está tabla se encuentra una columna llamada "schema_name" , que es en la que se almacenan los registros. Procederemos a extraer dichos datos, pero antes de esto haremos la siguiente consulta para extraer las columnas vulnerables:

categoria.php?id=1 UNION SELECT 1,2,3,4,5,6,7,8,9 -- -comentario

Y añadimos un - a un lado del 1. Y lo ejecutamos en la página y de repente nos dispara unos números, los cúales son las columnas vulnerables dónde procederemos a inyectar.  Supongamos que la columna vulnerable es la 2, inyectaremos allí.

Bien, ahora procederemos a la extracción de los nombres de las bases de datos, para ello usaremos la siguiente consulta:

categoria.php?id=1 UNION SELECT 1,group_concat(schema_name),3,4,5,6,7,8,9 from information_schema.schemata -- -comentario

Aquí hacemos uso de la función group_concat() , la cúal es para la concatenación con un separador de los registros en la columna "schema_name" , aunque solo extrae 1 mb de datos. Y seguidamente al final de los números uso from information_schema.schemata , con esto especifico "de la base de datos de la tabla schemata" . Y automáticamente empezara a reflejar los datos con los nombres de todas las bases de datos del servidor MySQL.

Ciertas veces, pueden haber más datos de lo que soporta el group_concat() , así que podemos usar "LIMIT" el cúal es para limitar los resultados, lo añadimos al final de toda la consulta, limit 0,1 , limit 1,1 , limit 2,1 y así sucesivamente. Ej: categoria.php?id=1 UNION SELECT 1,group_concat(schema_name),3,4,5,6,7,8,9 from information_schema.schemata limit 1,1 -- -comentario


Y si solo queremos extraer el nombre de la currente base de datos del sitio web, hacemos uso de la función database() el cúal lo inyectamos en la columna vulnerable. ej: categoria.php?id=1 UNION SELECT 1,database(),3,4,5,6,7,8,9 -- -comentario

Automáticamente nos lanzara el nombre currente de la base de datos.

4.- Extracción de los nombres de las tablas

En la base de datos information_schema existe una tabla llamada "TABLES" , la cúal tiene una columna llamada "table_name", en la que se almacenan todos los nombres de todas las tablas que existen en todas las bases de datos. En dónde procederemos a extraer los nombres de las tablas. Para ello, usaremos la siguiente consulta:

categoria.php?id=1 UNION SELECT 1,group_concat(table_name),3,4,5,6,7,8,9 from information_schema.tables where table_schema=0xnombredeladb -- -comentario

En dónde table_name vendría siendo el nombre de la columna en la que se encuentran los datos de las columnas y "tables" que vendría siendo el nombre de la tabla en dónde se encuentran los datos, y use where para especificar que los resultados pertenezcan a uno de los datos de la columna "table_schema" y al final podemos usar la función char() la cúal es para codificar algún texto en charcode, o usamos hexadecimal para ello mismo. haciendo 0x+elnombredeladb+ .

Y automáticamente se nos empezara a lanzar los nombres de todas las tablas que existen en la base de datos que especificamos por su nombre. Aunque también podemos usar LIMIT para limitar los resultados y búscar 1 por 1 .

5.- Extrayendo los nombres de las columnas de una tabla

En information_schema se encuentra una tabla llamada "columns" en la que existe una columna con el nombre "column_name" la cúal contiene los nombres de las columnas que existen en todas las bases de datos. Para proceder a la extracción de los nombres de las columnas usaremos la siguiente consulta en la URL:

categoria.php?id=1 UNION SELECT 1,group_concat(column_name),3,4,5,6,7,8,9 from information_schema.columns where table_name=0xusers -- -comentario

Y cómo lo pueden notar, lo que cambio fue el "table_name" el cúal lo reemplaze por "column_name" , information_schema.tables por columns el cúal es el nombre de la tabla "COLUMNS" en information_schema , y por último el "table_schema" por "table_name" , en dónde especifico el nombre de la tabla a la que extraeré las columnas, en este caso especifique la tabla "users". Luego ejecutamos la consulta en la URL y automáticamente nos empezara a lanzar todos los nombres de las columnas de la tabla currente.

5.- Extrayendo los registros

Para poder extraer los registros, reemplazaremos el group_concat() por concat(), el cúal extrae 16 mb (si no me equivoco) de datos. Seguidamente de los nombres de las columnas de una tabla currente, y al final usaremos from +el nombre de la tabla+ , Consulta en la url:

categoria.php?id=1 UNION SELECT 1,concat(id,0x7e,username,0x7e,password,0x7e,email),3,4,5,6,7,8,9 users -- -comentario

Y automáticamente se nos extraerán los registros de la tabla.

- Vídeo de muestra (es mío):



- Blind Boolean Based:

1.- ¿Qué es una "Blind SQLi Boolean Based"?

Si se pueden fijar en el nombre, este mismo se los dice todo. Cuando decimos "Boolean based" nos referimos a que está se basa en valores booleanos, es decir, true or false/verdadero y false. Y cuando digo "Blind" Me refiero a que la Inyección es a ciegas, es decir, no nos muestra alguna señal de error.

La única forma de extraer datos que se encuentren en la currente base de datos, sería usando el modo brute force, es decir, adivinando.

2.- Explicando dos funciones importantes

Una de las funciones más comúnes que usamos al momento de explotar una Blind Boolean Based, es ascii() , con este devolvemos algún carácter válidado de la tabla "ASCII" (si no me equivoco).

Otro vendría siendo substring() con esta devolvemos una subcadena de otra subcadena.

4.- Comprobando si el sitio es vulnerable

Existen algunas formas para comprobar si el sitio web que tenemos en las manos es vulnerable a una Blind SQLi Boolean Based, podemos usar la sentencia "AND" , seguidamente alguna operación, que de como resultado un valor verdadero o uno falso (booleanos), true or false, por ejemplo, podemos usar AND 1=1 , lo cúal vendría siendo igual a True/Verdadero, ya que 1 es igual a 1 :D.

Y si coloco, and 1=0 , me debería dar un resultado false/falso , ya que 1 no es igual a 0. Un ejemplo en un sitio web:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Como pueden observar, al final coloque un "-- -" , lo que es un comentario, el servidor solo lee lo que está entre la ' y el comentario -- - es decir, and 1=1 :D.  Todo lo que vaya luego de -- - el servidor no lo leera.

Y bueno, como pudieron observar en la página del sitio, se reflejo todo el texto de la noticia, ya que nos dio un resultado como true. Y ahora, si yo uso "and 1=0" me devolvería un resultado falso, ya que 1 no es igual a 0 como lo dije anteriormente, ejemplo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Y esto nos da señal de que es vulnerable :D.

Aparte de usar "AND" también podemos usar "having" , que sería otra de las alternativas. es decir, reemplazamos el and y colocamos having, ej:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta ;D.

Otra alternativa es, "DIV" , reemplazamos el having o el and y colocamos div , ejemplo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta .

4.- Explotación de la vulnerabilidad

La primera fase para explotar la vulnerabilidad, sería extraer el nombre de la base de datos, para ello, iremos búscando el nombre de la DB carácter por carácter.., haciendo uso de la función database(), ejemplo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Ok, explico, con esto le estoy preguntando al servidor si el primer carácter de la base de datos empieza por 116, en dónde 116 corresponde a "t" en la tabla ascii, entonces, el servidor me dara una respuesta basada en valores booleanos, es decir, si el primer carácter SI empieza por la letra t este me devolvera true, de lo contrario me devolvera false :D. Por ejemplo, si hago lo siguiente:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Me devuelve false, es decir, el primer carácter no comienza por la letra "s" la cual en decimal corresponde a 115, (está en la tabla ascii). Les dejo la siguiente que se apoyen más adelante:



Ok, ya yo por defecto se que el nombre de la db es "truji1_noticias", ya que le he hecho un escáneo al sitio :D.

Entonces, ustedes pueden ir aumentando el número de los carácteres y ir búscando letra por letra, aumentando de 1,1 , 2,1 y así sucesivamente. Aunque pueden llegar a aburrirse y duren mucho.

Ahora podemos seguir a extraer los nombres de las tablas existentes de la DB, para ello, hacemos lo siguiente:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Como pueden observar, aquí le estoy preguntando si hay una tabla llamada noticias y me devuelve un resultado como true, es decir, SÍ, hay una tabla llamada noticias en la base de datos :D. Y use select count(*) con un * ya que aún no tenemos las columnas de esa tabla :D.

Ustedes pueden colocar luego de from el nombre de una tabla y este se encargara de verificar si está existe.

Ahora, el siguiente paso sería averiguar los nombres de las columnas de la currente tabla, para ello, reemplazamos el * por el nombre de la columna a verificar si existe, ejemplo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Con esto, le estoy preguntando si existe una columna llamada "id" en la tabla "noticias", y esto me devuelve como resultado true :D, es decir, que si existe una columna con el nombre "id", así podemos ir reemplazando nosotros y búscando nombre por nombre cada columna, ejemplo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Reemplaze id y puse fecha, y este me dice que si existe una columna con ese nombre jeje ;D.

La última fase vendría siendo la obtención de los datos de cada tabla, para ello, usaremos los siguiente:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Entonces, con esto le pregunto al servidor si el primer carácter de la primera fila de la columna "id" es 1 , lo cúal significa 49 en decimal :D, y así podremos ir búscando carácter por carácter hasta ir obteniendo los datos reales, aumentando el limit de 0,1 a 1,1 a 2,1 y así sucesivamente ;-). Y si queremos pasar a la siguiente fila, cambiamos el 1,1 por 2,1 y así vamos ;D.

- Link del tutorial del segundo post (mío también): No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Y bueno, eso ha sido todo amigos! Espero les haya gustado. Vere si próximamente actualizo el post y coloco sobre Time based u Error based/double query. Y saludos y agradecimientos a mi amigo arthusu por algunas explicaciones que me ha dado ;).

Saludos, @M5f3r0.
A veces, observo mi pasado y me arrepiento en la actualidad de todo lo que llegue a perder y olvidar por como me veía la sociedad, nunca dejes que las opiniones de los demás te lleguen a afectar moralmente hasta el punto en que dejes de hacer lo que más te apasiona, saludos! (msj escrito en el 2016)

Hola, espero que no te tomes a mal mi comentario, pero esto ya es spam.
¿Dices cómo explotar union based y blind boolean based?, perfecto, pero con una vez creo que es suficiente, no tienes porqué publicar lo mismo dos veces.
Blind Boolean Based: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Union Based: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Si quieres aumentar el contenido aumentalo en el mismo aporte para algo está la opción editar, ¿digo yo no?.
Un saludo!
Lo que sabemos es una gota de agua; lo que ignoramos es el océano.

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Hola, espero que no te tomes a mal mi comentario, pero esto ya es spam.
¿Dices cómo explotar union based y blind boolean based?, perfecto, pero con una vez creo que es suficiente, no tienes porqué publicar lo mismo dos veces.
Blind Boolean Based: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Union Based: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Si quieres aumentar el contenido aumentalo en el mismo aporte para algo está la opción editar, ¿digo yo no?.
Un saludo!

Gracias por el consejo, copie y pegue el texto de mi post de blind boolean based para poder unir ambos y convertirlo como un curso ;).

Saludos ;).
A veces, observo mi pasado y me arrepiento en la actualidad de todo lo que llegue a perder y olvidar por como me veía la sociedad, nunca dejes que las opiniones de los demás te lleguen a afectar moralmente hasta el punto en que dejes de hacer lo que más te apasiona, saludos! (msj escrito en el 2016)

Bueno esta bastante bien el curso mufero , los que recién andan entrando al tema les viene muy bien !


Saludos !
Passion informatic.


Excelente post, muy buena información.
Saludos cordiales.

Gracias! Muy interesante para probar con las páginas que monte!

Ahora si quisiera probar con otras para chusmear, ¿se puede? ¿queda algún registro?

Pregunto de curiosidad.

@No tienes permitido ver los links. Registrarse o Entrar a mi cuenta claro que se puede probar (testear) en cualquier sitio, y por lo general si quedan registros (logs) de los movimientos realizados en esos sitios atacados.
Aquí todos somos curiosos así que pregunta lo que se te ocurra mientras sean dudas puntuales.

Saludos!, EPSILON

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Gracias! Muy interesante para probar con las páginas que monte!

Ahora si quisiera probar con otras para chusmear, ¿se puede? ¿queda algún registro?

Pregunto de curiosidad.

Como me fuese gustado haberte respondido al momento, aunque sea un poco vieja la pregunta trae algo de nostalgia ver posts antiguos de la comunidad, gracias a la persona de arriba por haberlo hecho! lastimosamente ahora mismo no recuerdo ni quien era hace más de 3 años :-\ ;D.
A veces, observo mi pasado y me arrepiento en la actualidad de todo lo que llegue a perder y olvidar por como me veía la sociedad, nunca dejes que las opiniones de los demás te lleguen a afectar moralmente hasta el punto en que dejes de hacer lo que más te apasiona, saludos! (msj escrito en el 2016)