***************************************************************************************
Artículo Publicado en la revista Hackin9 en Ene'08
-
Time-Based Blind SQL Injection using Heavy Queries (I de II)-
Time-Based Blind SQL Injection using Heavy Queries (II de II)***************************************************************************************
SQL InjectionOWASP (The Open Web Application Security Project) ha publicado recientemente un documento en el que recoge las 10 vulnerabilidades se seguridad más críticas en Aplicaciones Web. En él, se recogen las vulnerabilidades que más siguen afectando y que siguen siendo “viejas conocidas” para el gran público. En primer lugar se encuentran los ataques Cross-Site Scripting, con todas sus variantes de ataques persistentes y no persistentes mientras que en segundo lugar quedan las inyecciones de código malicioso y especialmente las vulnerabilidades de SQL Injection. Sí, parece que fue ayer cuando se publicó en el año 1998 el primer documento que hablaba de la posibilidad de inyectar código SQL en consultas firmado, por el ya famoso, rain.forest.pupy y titulado “NT Web Technology Vulnerabilities”, pues bien, ya casi 8años se cumplen desde que se habló de esa posibilidad y a día de hoy sigue siendo una de las vulnerabilidades más peligrosas.
Blind SQL InjectionEs cierto que las formas de explotarlas han ido cambiando, en parte, por la fortificación de sistemas, que, aunque no evita la vulnerabilidad si dificulta su explotación. En el año 2002 Chrish Anley hace referencia en su documento “(more) Advanced SQL Injection” a la posibilidad de realizar ataques de inyección de código a ciegas y utilizando métodos tan curiosos, en aquel entonces, como forzar una parada de tiempos en las bases de datos SQL Server si se cumple una condición llamando a un procedimiento almacenado para ejecutar un Ping a localhost o llamando a la función waitfor de Microsoft SQL Server. Fue en ese momento cuando se puede decir que ven la luz las técnicas de explotación de vulnerabilidades de inyección de comandos SQL a ciegas. Es decir, Blind SQL Injection.
En el año 2004, Cameron Hotchkies, en las Blackhat Conferences, presentando la herramienta SQueal, que más tarde se convertiría en Absinthe, hablaba de los métodos de automatizar la extracción de información mediante ataques Blind SQL Injection. El documento publicado “Blind SQL Injeciton Automation Techniques” mostraba las diferentes posibilidades a la hora de conocer cuando una respuesta significa un valor positivo o negativo. Se echa de menos en el documento y también en la herramienta la posibilidad mostrada por Chrish Anley de usar retardos de tiempo en la automatización.
Imagen: Extracción de datos con AbsintheTime-Based Blind SQL Injection
A las técnicas que automatizan la extracción de información a ciegas usando retardos de tiempo se las conoce como Time-Based Blind SQL Injection y han ido especializándose en diferentes tecnologías de bases de datos para generar retardos de tiempo. Así, por ejemplo, la herramienta SQL Ninja, utiliza el sistema de tiempos descrito por Chrish Anley en aplicaciones web que utilizan motores de base de datos Microsoft SQL Server. Otras herramientas como SQL Power Injector utilizan el sistema de inyectar funciones Benchmark que generan retardos en motores de bases de datos MySQL o inyectar la llamada a la función PL/SQL DBMS_LOCK.SLEEP(time) en sistemas con motores Oracle. Para otros sistemas de bases de datos como Access o DB2 no existe forma similar de generar retardos de tiempo. Los métodos de generar estos retardos de tiempo quedan por tanto restringidos bastante. En primer lugar para Access, DB2 y otros motores de bases de datos no se conoce ninguna forma; en segundo lugar, para hacerlo en motores Oracle se necesita acceso a una inyección PL/SQL que no es común encontrarse con un entorno que lo permita y, por último los sistemas de fortificación suelen tener en cuenta la restricción del uso de funciones Benchmark en entornos MySQL y waitfor en entornos Microsoft SQL Server.
En el presente artículo vamos a ver como poder realizar un ataque a ciegas usando inyecciones de código que generan retardos de tiempo utilizando consultas pesadas, es decir, Time-Based Blind SQL Injection with Heavy Queries.
“Booleanización”
El término “Booleanización” no es mío, la primera vez que lo leí fue en el documento “Blind XPath Injection” de Amit Klein y que desconozco si existía previamente o no, pero en el caso de que no existiera hay que crearlo. La idea consiste en como extraer un dato mediante una secuencia de condiciones booleanas que devuelve True o False. Por ejemplo, supongamos queremos extraer el valor del campo username de la vista all_users en un motor Oracle y este valor es “sys”. El proceso de “booleanización” sería el siguiente:
255>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> True [255 > ASCII(‘s’)=115]
122>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> True [122 > ASCII(‘s’)=115]
61>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> False [61 < ASCII(‘s’)=115]
92>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> False [92 < ASCII(‘s’)=115]
107>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> False [107 < ASCII(‘s’)=115]
115>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> False [115 = ASCII(‘s’)=115]
119>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> True [119 < ASCII(‘s’)=115]
117>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> True [117 < ASCII(‘s’)=115]
116>(Select ASCII(Substr(username,1,1)) from all_users where rownum<=1
-> True [116 < ASCII(‘s’)=115]
En este punto se ha averiguado que el valor ASCII de la primera letra del nombre es 115 ya que no es mayor que 115 y es menor que 116. Y se pasaría a realizar el mismo proceso con la segunda letra. Como se puede ver el proceso va a exigir una serie de repetición de peticiones para cada valor, pero al final se obtiene el resultado. El problema, como se explica al principio de este artículo, es determinar cuando la respuesta es True y cuando es False.
Time-Based Blind SQL Injection
Hasta el momento, lo sistemas que se conocían para extraer información estaban basados en las funciones que ofrecía cada motor de bases de datos, así, por ejemplo, en una aplicación web que utilice Microsoft SQL Server podría realizarse una inyección como la siguiente:
http://servidor/prog.cod?id=1; if (exists(select * from contrasena)) waitfor delay ‘0:0:5’--
Esta consulta, en el caso de existir la tabla “contrasena” y tener algún registro va a pausar la respuesta de la página web un tiempo de 5 segundos. Si la respuesta se obtiene en un periodo inferior podemos inferir que la tabla “contrasena” existe y tiene algún registro. La misma idea puede ser utilizada para una aplicación con Oracle:
http://servidor/prog.cod?id=1; begin if (condicion) then dbms_lock.sleep(5); end if; end;
Y con MySQL, usando por ejemplo la función Benchmark del ejemplo, que suele tardar unos 6 segundos en procesarse o la función Sleep(), que ya viene en las versiones 5 de MySQL.
http://servidor/prog.cod?id=1 and exists(select * from contrasena) and benchmark(5000000,md5(rand()))=0
http://servidor/prog.cod?id=1 and exists(select * from contrasena) and sleep(5)
Heavy Queries
Las consultas pesadas han sido y siguen siendo un quebradero de cabeza en la optimización de sistemas de bases de datos. Un motor puede almacenar cantidades de información tan grandes y con tal cantidad de usuarios que si no se optimizaran las bases de datos dejarían de ser útiles. Los ajustes de rendimiento son constantes en los grandes sistemas de bases de datos para conseguir mejorar los tiempos de respuesta. Con los años los motores de bases de datos se han ido evolucionando para que sean ellos los que optimicen las consultas que generan los programadores y no al revés como se hacía antaño, aunque hay algunos motores que siguen requiriendo del programador para optimizar una consulta. Es decir, supongamos una consulta Select como la siguiente:
Select campos from tablas where condición_1 and condición_2;
¿Con que orden evaluar las condiciones para que se ejecute esta consulta y el sistema lo más rápido posible? En este ejemplo, al utilizar una condición AND, si la primera condición que evaluamos da como resultado un valor FALSO el motor ya no tiene que evaluar la otra. Si hubiera sido un operador OR el funcionamiento hubiera sido al revés, es decir, si la primera da VERDADERO ya no hay que evaluar la segunda condición. La conclusión varía en cada motor de bases de datos. En algunos se establece una precedencia y se hace recaer la optimización sobre el programador. Es decir, se evalúan las condiciones de izquierda a derecha o de derecha a izquierda y es responsabilidad del programador elegir el orden de evaluación en función de la probabilidad de obtener el resultado en menos tiempo. Si por ejemplo se estima que en evaluar la condición_1 el motor tarda 6 segundos y en evaluar la condición_2 unos 2 segundos y el motor utiliza precedencia por la izquierda entonces habrá que situar a la izquierda la condición de menos tiempo. Para entenderlo vamos a ver la tabla de tiempos posibles:
Tabla con la condición_1 (la pesada) a la izquierda
Tabla con la condición_2 (la ligera) a la izquierda
Como se puede ver, en una probabilidad similarmente distribuida de que cada condición pueda tomar valores TRUE o FALSE, es más optimo evaluar siempre primero la consulta ligera. Esto puede cambiar en función de las densidades. Es decir, en una clausula Where con operador AND en la que la condición ligera tenga una probabilidad del 99 % de ser TRUE y la pesada una probabilidad del 5 % de ser TRUE puede ser más eficiente utilizar una precedencia distinta.
Motores como Microsoft SQL Server u Oracle implementan optimización de consultas en tiempo de ejecución. Es decir, analizar las condiciones que pone el programador y eligen el orden de ejecución “correcto” según su estimación. Para ello utilizar reglas básicas, avanzadas e incluso datos estadísticos de las tablas de la base de datos en concreto.
***************************************************************************************
Artículo Publicado en la revista Hackin9 en Ene'08
-
Time-Based Blind SQL Injection using Heavy Queries (I de II)-
Time-Based Blind SQL Injection using Heavy Queries (II de II)***************************************************************************************