Inyección SQL : Manual básico
Conocimientos previos:
Saber nociones básicas sobre SQL.
Definicion de SQL Injection: El sql injection es un tipo de ataque a una base de datos en el cual, por la mala filtración de las variables se puede inyectar un código creado por el atacante al propio código fuente de la base de datos.
Listado de comandos básicos en SQL:
Grant Utilizado para otorgar privilegios
Revoke Utilizado para eliminar privilegios
Create Utilizado para crear nuevos elementos(tablas,idices…)
Drop Utilizado para eliminar elementos
Alter Utilizado para alterar campos de las tablas
Select Utilizado para consultar registros de una tabla y comprobar que satisfagan una condición determinada
Insert Utilizado para cargar lotes de datos en la base de datos
Update Utilizado para cambiar valores de registros y campos
Delete Elimina registros de una tabla de la base de datos
Lista de clausulas básicas en SQL:
From Selecciona la tabla sobre la cual se va a operar (o sobre sus registros)
Where Especifica las condiciones que se deben cumplir los registros que se seleccionan
Group by Utilizado para separa registros en grupos
Having Especifica las condiciones que cumple cada grupo
Order by Ordena registros selecionados
Instalación del programa
El programa viene configurado y preparado para funcionar sin ningún tipo de instalación previa. Sólo se debe copiar todo el programa (ejecutable y asociados) y la base de datos en la misma carpeta, sea cual sea, manteniendo el nombre de la base de datos intacto.
Ejecutar insertarHorariosTrabajadores.exe y se verá el programa de inicio.
Descargar programa Inyección SQL
Introducción
Antes de nada aclarar la razón de por qué estos ataques son tan peligrosos: pueden no solo sacar información de la base de datos (usuarios, contraseñas, etc), sino también pueden borrar la base de datos, dejarla inservible o aplicarse a ataques DDOS entre otros.
Introducción al método error y comprobación de la vulnerabilidad del servidor
Previo paso al comienzo del manual, que quede claro que esta información es puramente informativa y va enfocada al conocimiento y preparación del desarrollador para evitar errores, nunca a la realización de prácticas ilegales.
Bien, empecemos a analizar la vulnerabilidad de nuestro objetivo, en cuanto a ataques SQL.
Base de datos para probar SQL Injection:
http://www.redeszone.net/app/uploads/cdn/down/soft/seginf/sql_inyeccion/inyeccion%20sql.rar
Comencemos: lo primero que necesitamos es buscar algún indicio de que la web o el programa es vulnerable. Enfoquemos este apartado a sitios web.
SQL Injection a páginas web.
Imaginad que estáis diseñando una página web, es muy bonita, al cliente le gusta, se pone en marcha y a los 5 minutos es hackeada por algún indeseable que ha borrado la base de datos, sería un desastre. Es de recibo que, actualmente, los diseñadores de páginas deben tener en mente un poco de seguridad informática para que su página no resulte vulnerable, al menos en los casos típicos. Es lo que se pretende con este manual: que el diseñador tenga nociones de seguridad típicas.
Veamos primero si la web en cuestión tiene este tipo de sentencias en su url: «celebraciones.asp?ID=», «libros.php?view=», o cualquier otro tipo parecido. En muchas ocasiones, introduciendo ahí nuestro código inyectado empieza el ataque , pero esto lo explicaremos más adelante.
Nota1: no siempre que tenga este tipo de sentencias es vulnerable
Nota2: si ves ASP,ASPX,etc , piensa en que en un elevado tanto por ciento de los casos, la base de datos será SQL.
Nota3: Para comenzar el ataque, también podemos buscar formularios ligados a una consulta a una base de datos SQL.
Si , con SQL injection podemos “saltarnos” algunos logueos pero el SQL Injection es mucho mas, como se explicó al comienzo: podemos borrar una base de datos, cambiarle el nombre a las tablas o hacer mil maldades. Imaginad por ejemplo una página de venta de teléfonos móviles, podemos hacer que la persona que se nos ocurra de la BD compre 1000 teléfonos, por ejemplo.
2. Ataque blind SQL Injection.
El BLIND SQL Injection se considera un ataque a ciegas, es decir, sin conocer nada sobre el server (Versión de SQL, nombre de las tablas, numero de tablas, etc, que deberemos saber para concluir el ataque y para saber defendernos.)
2.1-. Sacando el número de columnas de la BD
Bien para sacar el numero de columnas de la base de datas (BD,DB), vamos a inyectar un código que cause un conflicto al llegar a un numero de columna, el cual no se encuentra en la base de datos .
Bien para esto vamos a utilizar la clausula order by. Este tipo de ataque se basa en ordenar columnas hasta llegar a la ultima. Así al poner la siguiente, al no existir , nos devolverá un error tipo:
Unknown column ‘numerodecolumna’ in ‘order clause’
El error puede sufrir variaciones pero lo que nos interesa es que nos devuelva el unknown column y el número que es lo que nos indica que columna es la que no está definida(no existe).
Este no es el único método para sacar el numero de columnas (si el que me parece más fácil), pero hay varios si no les funciona con unos, estudien un poco de SQL y piensen como hacerlo es simple fíjense de este método y sabrán como sacar errores con otras clausulas.
Pongo un ejemplo sencillo, para que se vea una parábola de lo anteriormente dicho.
2.2.- Sacando el nombre de la tabla.
Imaginad una web con este tipo de enlace:
http://www.soyunaweb.com/soyunapagina.extension?id_pregunta=2
Es muy común encontrar este tipo de enlaces en casi cualquier web y también es muy común pensar que detrás de este enlace, existe una sentencia SQL que determina que mostraremos o el contenido de dicha página, por ejemplo.
El formato de la sentencia SQL que podría estar detrás de ese enlace sería algo parecido a esto:
“SELECT * FROM pregunta WHERE id_pregunta=” + parámetro
Viendo el enlace, es lógico presuponer que la tabla se llame pregunta y el campo id_pregunta. Este podría ser un fallo de seguridad . Al diseñar Webs con ese tipo de enlaces, debemos intentar asegurarnos de que el nombre del parámetro no sea tan explicativo. Simplemente con haber puesto id_p se soluciona el problema, por ejemplo, acabándose así nuestro ataque de Blind SQL Injection. (Salvo utilizar la fuerza bruta, por supuesto).
Hemos pensado que la sentencia SQL podría ser válida, pero no sabemos a ciencia si lo es, tendremos que comprobarlo (podría ser también un simple código escrito dentro de la página).
Para comprobarlo, podemos hacer lo siguiente, poner una condición que nos devuelva siempre cierto, a ver si lo que evalúa la condición es un pedazo de código o una sentencia SQL. Se nos ocurre probar con algo como esta sentencia:
SELECT * FROM pregunta WHERE id_pregunta=2 AND 1=1
Que traducido a un enlace:
http://www.soyunaweb.com/ soyunapagina.extension?id_pregunta=2 and 1=1
Si por defecto aparece la pagina de la pregunta 2, bingo, hemos acertado, es una sentencia SQL. (En realidad podría ser un switch por ejemplo, pero supondremos que se trata de una sentencia SQL sin mas preámbulos).
A partir de aquí, tendríamos que demorarnos en conseguir mas información (nombre de las tablas, por ejemplo). Yo aconsejo atacar a los servidores mas comunes, Access o SQL Server, por ejemplo, con sus tablas de sistema. Lo que nos indica otro fallo importante de seguridad: al diseñar, debemos prohibir la lectura a este tipo de tablas. Al intentar atacar, el atacante verá que o bien no existen o bien no tiene permiso para leerlas y esa vía queda descartada.
Inyección SQL en aplicaciones de Escritorio.
Imaginemos el siguiente escenario: tenemos una red local, con una aplicación que accede a diferentes sitios de una intranet o de archivos de configuración de un servidor o cualquier otra tarea que se requiera.
Supongamos que detrás de esa aplicación hay una base de datos de Access, que controla todo el proceso de la identificación del usuario sirviendo de apoyo a una aplicación construida con Visual Studio 2008, en Visual Basic.
Este será nuestro escenario de ataque. Para este manual se ha construido un programa de ejemplo con un acceso por usuario y contraseña que constituye nuestra herramienta para el aprendizaje. La base de datos sobre la que se sustenta la aplicación está creada en Access XP, una herramienta común en el mundo de las Pymes.
La inyección de SQL de una Web con un servidor SQL Server es ligeramente distinta a la de un programa de escritorio con base de datos Access, pero, en esencia, no difiere demasiado.
El carácter que permite inyectar SQL es la comilla simple. Este carácter es interpretado por SQL como el inicio de una instrucción y podemos concatenar nuestras instrucciones si lo hacemos con habilidad.
Imaginad que somos un usuario malicioso que ha quedado muy descontento con el gerente de la empresa TodoAdsl porque no le ha dado un día de asuntos propios para ver el Madrid-Barça (por ejemplo). En el trabajo, tenemos un programa que funciona para insertar el Horario de los Trabajadores, las tareas que han realizado al cabo del día y en qué franja del día. Se nos ocurre, que, si podemos saltarnos la contraseña, podemos hacer grandes destrozos en la empresa.
Vamos a trabajar, encendemos el ordenador y arrancamos el programa.
Tenemos esto:
Un simple formulario de entrada con un usuario y una contraseña, con la imagen de la persona elegida en el combobox de nombre de usuario a la derecha. (Se ha dejado el control pero se han omitido las imágenes, para que la BD no pese mas de lo necesario para el manual).
Lo primero que se nos ocurre es poner un usuario y una contraseña al azar para saber que ocurre.
Ponemos de contraseña la palabra “contraseña” y como usuario el que aparece en la imagen:
Al pulsar sobre el botón “Entrar” , aparece una ventana que se ha creado específicamente para que veais la sentencia SQL que el programa tiene detrás para controlar el acceso.
Obviamente, esta ventana no se muestra en ningún programa que precise de usuario y contraseña, sería un error de seguridad imperdonable, se muestra aquí para facilitar la comprensión del manual.
Como podéis ver, la sentencia SQL es muy sencilla.
Tenemos una tabla “TRABAJADOR”, un campo “clave personal” que sería el campo donde se almacena la clave y un campo “TRABAJADOR” que sería el usuario. En este caso, el nombre de la tabla y el nombre del campo coinciden, pero no es lo habitual.
Lo primero que debemos probar es a poner entradas extrañas, como el usuario vacío o la contraseña vacía, a ver que ocurre. Probamos y nos sale la siguiente ventana:
En este caso, hemos errado: el programador ha sido lo suficientemente inteligente como para capar esos casos extraños y no dejar posibilidad al error.
La siguiente treta será intentar la Inyección de SQL. (Ya era hora).
Ahora necesitamos saber como inyectar SQL en una base de datos Access. Los motores de SQL tienen un carácter de escape que sirve para delimitar qué es sentencia SQL de qué no lo es.
En este caso, tenemos ya que la sentencia SQL que realiza la consulta el del tipo:
«SELECT * FROM TRABAJADOR WHERE [clave personal]='» & pass & «‘ AND TRABAJADOR='» & usuario & «‘»
Ahora hemos de pararnos a pensar durante un minuto. ¿Cómo podemos insertar código SQL en la sentencia de forma que podamos burlar el logueo?.
Podemos probar con lo mas sencillo que se nos ocurre: introducir una condición lógica que siempre sea verdadera. O sea: ‘1=1
Probamos esa sentencia en la contraseña, con cualquier usuario de la base de datos y tenemos esto:
De nuevo, nuestra suposición era equivocada, no puede ser algo tan simple como eso, pero nos ha dejado una idea de cómo sacar la sentencia SQL en un caso normal (en el caso que nos ocupa, el programa, muy amablemente, se encarga de hacerlo por nosotros, pero repetimos que eso no sucede nunca.
Si podemos introducir valores que den como resultado una sentencia SQL equivocada, entonces podríamos saber la consulta que se realiza. ¿Cuál ha sido el error del programador en este caso?. Simplemente, no filtrar la entrada. Si tan sólo hubiera aplicado un filtro para no permitir caracteres extraños, el error nunca sucedería, y el malintencionado usuario (nosotros en este caso) se queda con un palmo de narices.
No desesperemos. Probemos con otra cosa. La sentencia SQL que ejecuta la consulta es de este modo:
SELECT * FROM TRABAJADOR WHERE [clave personal]='» & pass & «‘ AND TRABAJADOR='» & usuario & «‘»
¿Y si probamos a introducir una sentencia lógica siempre a cierto en el campo trabajador?.
Probamos con esto:
Pepe ‘ OR ‘a’=’a en el campo trabajador y esto otro, contraseña en el campo contraseña. Esperanzados vamos a pulsar el botón de entrar y nos muestra esta ventana:
Observamos la consulta y ya vemos que no funcionará: el programador ha filtrado los contenidos del campo usuario para permitir tan sólo los usuarios que el programador eligió en el combobox.
Pulsamos Aceptar y nos encontramos con la ventana siguiente:
De nuevo hemos fracasado. Nos ponemos a pensar y se nos ocurre otra estrategia: probar a introducir una sentencia lógica que de cierto sólo con que uno de los valores sea cierto.
Sería algo así:
SELECT * FROM TRABAJADOR WHERE [clave personal]= ‘loqueseteocurra’ OR ‘a’=’a’ AND TRABAJADOR='» & usuario & «‘»
¿Qué realiza esta sentencia?. Compara el valor de la clave con Or a=a y realiza un AND con el trabajador. ¿Qué va a ocurrir?. ¡Pues que OR a=a siempre devuelve cierto, sea cual sea el valor de la contraseña puesta!, realizando un AND con el trabajador (que en este caso sirve cualquiera que pongamos y que el programador haya permitido).
Nos vamos al programa y ponemos las siguientes valores:
En contraseña: loqueseteocurra’ OR ‘a’=’a
En usuario: cualquiera que el combobox tenga almacenado.
Pulsamos en entrar y tenemos esto como salida:
Bingo. Hemos dado con la sentencia correcta, el programa nos ha permitido insertarla y ahora, con todo el placer de nuestras malévolas mentes pulsamos en aceptar. Efectivamente, nos muestra la ventana de insertar el horario del trabajador. Hemos logrado ingresar con un usuario cualquiera sin conocer la contraseña.
Y ya estaríamos dentro del programa, podríamos hacer lo que nos apeteciera con ese usuario, desde insertar horarios falsos, a números de expedientes falsos, etc, etc..
El programa ya no realizará mas acciones, los botones insertar y sacar horario no hacen nada.
Conclusiones
Se puede abstraer lo visto en el manual para intentar otro tipo de sentencias que provoquen un daño irreparable a la base de datos. Por ejemplo, podríamos intentar realizar un drop table y borrar una tabla o eliminar la base de datos. Como se explicó antes, este tipo de problemas son muy peligrosos y vale mas prevenirlos cuanto antes.
Lo mas sensato que debemos tener en cuenta al prevenir estos ataques es filtrar el carácter ‘ (comilla simple), si hablamos a nivel de web, hacerlo siempre en cliente y servidor, si hablamos en un entorno de red local, filtrar la entrada del campo en el programa.
A nivel de web, si sólo se filtra en el cliente, es fácil saltarse la validación y provocar un fallo del estilo de los que hemos visto, para extraer información, de ahí la necesidad de hacerlo en el cliente.
Para seguir avanzando en el tema os recomiendo la lectura de dos documentos que son de obligada lectura para el que esté aprendiendo SQL Injection:
Inyección de SQL
http://www.redeszone.net/content/uploads/Tecnicas-de-SQL-Injection.pdf
Inyección de SQL avanzada:
http://www.redeszone.net/content/uploads/advanced_sql_injection.pdf
Manual realizado por Ethiel para REDESZone.net