***************************************************************************************
Artículo publicado en PCWorld Noviembre 2007:
- Técnicas Avanzadas en ataques Blind SQL Injection (I de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (II de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (III de III)
***************************************************************************************
Blind SQL Injection en base a tiempos usando consultas pesadas
Podríamos pensar, que si nuestro entorno no permite el acceso a las funciones enumeradas anteriormente no se podrá realizar nunca un ataque a ciegas basado en tiempos, pero esto no es cierto. El problema sigue persistiendo; el verdadero fallo de seguridad sigue siendo el mal filtrado de los datos que van a ser utilizados en la construcción de una sentencia SQL y van a poder ser explotados.
Supongamos un entorno en el que las páginas de error no difieren de las auténticas, es decir, que aunque se genere una inyección no se aprecia ningún cambio medible entre las páginas de Verdad y las de Mentira. Además, se han anulado las funciones enumeradas anteriormente, luego parece imposible medir un retardo de tiempo en el comportamiento de una aplicación ante una inyección SQL. Sin embargo, esto sigue siendo posible. Aún en ese entorno un atacante puede inferir información mediante técnicas a ciegas usando consultas pesadas que hagan trabajar al motor de bases de datos y por tanto generen retardos de tiempo ante respuestas positivas.
Supongamos una aplicación web que utiliza una base de datos Microsoft Access y esta aplicación web tiene un fallo de SQL Injection que solo puede ser explotado a ciegas. Los motores de Microsoft Access no tienen funciones de retardo, ¿cómo generamos un retardo de tiempo ante respuestas positivas?
En la siguiente URL el parámetro vulnerable es id_pista y deseamos saber si existe la tabla “contrasena”.
http://www.servidor.com/pista.asp?id_pista=1
Bastaría para averiguar si existe o no esa tabla realizar una inyección en la que hiciéramos trabajar mucho al motor si y solo si existiera esa tabla. Para eso hemos de entender como evalúan los motores de bases de datos las condiciones en las claúsulas “where” de las consultas SQL.
Claúsulas where
Si una claúsula “where” está formada por condiciones enlazadas con el operador lógico OR éstas se evaluarán mientras no se haya encontrado ninguna que devuelva un resultado positivo, pero en el momento que se encuentre un condicionante que haga cierta la claúsula, ésta se dejarán de evaluar. Por el contrario, en una clausula enlazada con operadores AND se evaluarán las condiciones mientras no se encuentre una condición que haga que el resultado sea negativo, es decir, una que no sea cierto. Conociendo este funcionamiento, es probable que nunca se tengan que evaluar todas las condiciones por lo que si el motor realiza los cálculos correctamente se podrán optimizar los tiempos de respuesta.
Tradicionalmente los motores evalúan los condicionantes en un determinado orden y la labor de elegir el orden de los condicionantes en la claúsula where es del programador. Hoy en día, los motores más modernos realizan una estimación de rendimiento, es decir, estiman el tiempo que les va a llevar el resolver cada condicionante y empiezan por el de menor coste computacional. Aprovecharse de estas características puede permitir realizar las inferencias en función del tiempo en ataques a ciegas.
En el ejemplo actual, si deseamos averiguar si una tabla existe podemos realizar la siguiente operación:
- http://www.servidor.com/pista.asp?id_pista=1 and [consulta pesada] and exists (select * from contrasena)
Esta operación haría que la consulta pesada se ejecutará si y sólo sí la última clausula “exists (select * from contrasena)” es TRUE. Si la consulta pesada genera un retardo de tiempo medible tendremos algo que nos indicará que la tabla contrasena existe y además tiene filas. ¿Qué consulta pesada se puede utilizar? Pues cualquier combinación múltiple de joins entre tablas que conozcamos. Para ello se puede utilizar alguna tabla que se sepa que siempre existe y además es accesible. En aplicaciones que ataquen a Microsoft Access 2000 se puede utilizar la tabla MSysAccessObjetcs y en Microsoft Access 2003 y 2007 se puede usar la tabla MSysAccessStorage. Un ejemplo de consulta pesada para extraer información sería el siguiente:
http://www.informatica64.com/retohacking/pista.aspx?id_pista=1 and (SELECT count(*) FROM MSysAccessObjects A 20T1, MSysAccessObjects AS T2, MSysAccessObjects AS T3, MSysAccessObjects AS T4, MSysAccessObjects AS T5, MSysAccessObjects AS T6, MSysAccessObjects AS T7,MSysAccessObjects AS T8,MSysAccessObjects AS T9,MSysAccessObjects AS T10)>0 and exists (select * from contrasena)
Imagen: Medición de tiempos en Access 2000. La consulta tarda 6 segundos. Luego es cierto, la tabla contrasena existe y tiene registros.
Imagen: Medición de tiempos en Access 2000. La consulta tarda 1 segundo porque hemos negado la condición.
Este mismo sistema se puede aplicar a cualquier motor de base de datos del que se conozca o se averigüe una tabla con algún registro. Como se ha visto, basta con realizar una consulta lo suficientemente pesada como para que genere un retardo medible su ejecución.
***************************************************************************************
Artículo publicado en PCWorld Noviembre 2007:
- Técnicas Avanzadas en ataques Blind SQL Injection (I de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (II de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (III de III)
***************************************************************************************
Artículo publicado en PCWorld Noviembre 2007:
- Técnicas Avanzadas en ataques Blind SQL Injection (I de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (II de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (III de III)
***************************************************************************************
Blind SQL Injection en base a tiempos usando consultas pesadas
Podríamos pensar, que si nuestro entorno no permite el acceso a las funciones enumeradas anteriormente no se podrá realizar nunca un ataque a ciegas basado en tiempos, pero esto no es cierto. El problema sigue persistiendo; el verdadero fallo de seguridad sigue siendo el mal filtrado de los datos que van a ser utilizados en la construcción de una sentencia SQL y van a poder ser explotados.
Supongamos un entorno en el que las páginas de error no difieren de las auténticas, es decir, que aunque se genere una inyección no se aprecia ningún cambio medible entre las páginas de Verdad y las de Mentira. Además, se han anulado las funciones enumeradas anteriormente, luego parece imposible medir un retardo de tiempo en el comportamiento de una aplicación ante una inyección SQL. Sin embargo, esto sigue siendo posible. Aún en ese entorno un atacante puede inferir información mediante técnicas a ciegas usando consultas pesadas que hagan trabajar al motor de bases de datos y por tanto generen retardos de tiempo ante respuestas positivas.
Supongamos una aplicación web que utiliza una base de datos Microsoft Access y esta aplicación web tiene un fallo de SQL Injection que solo puede ser explotado a ciegas. Los motores de Microsoft Access no tienen funciones de retardo, ¿cómo generamos un retardo de tiempo ante respuestas positivas?
En la siguiente URL el parámetro vulnerable es id_pista y deseamos saber si existe la tabla “contrasena”.
http://www.servidor.com/pista.asp?id_pista=1
Bastaría para averiguar si existe o no esa tabla realizar una inyección en la que hiciéramos trabajar mucho al motor si y solo si existiera esa tabla. Para eso hemos de entender como evalúan los motores de bases de datos las condiciones en las claúsulas “where” de las consultas SQL.
Claúsulas where
Si una claúsula “where” está formada por condiciones enlazadas con el operador lógico OR éstas se evaluarán mientras no se haya encontrado ninguna que devuelva un resultado positivo, pero en el momento que se encuentre un condicionante que haga cierta la claúsula, ésta se dejarán de evaluar. Por el contrario, en una clausula enlazada con operadores AND se evaluarán las condiciones mientras no se encuentre una condición que haga que el resultado sea negativo, es decir, una que no sea cierto. Conociendo este funcionamiento, es probable que nunca se tengan que evaluar todas las condiciones por lo que si el motor realiza los cálculos correctamente se podrán optimizar los tiempos de respuesta.
Tradicionalmente los motores evalúan los condicionantes en un determinado orden y la labor de elegir el orden de los condicionantes en la claúsula where es del programador. Hoy en día, los motores más modernos realizan una estimación de rendimiento, es decir, estiman el tiempo que les va a llevar el resolver cada condicionante y empiezan por el de menor coste computacional. Aprovecharse de estas características puede permitir realizar las inferencias en función del tiempo en ataques a ciegas.
En el ejemplo actual, si deseamos averiguar si una tabla existe podemos realizar la siguiente operación:
- http://www.servidor.com/pista.asp?id_pista=1 and [consulta pesada] and exists (select * from contrasena)
Esta operación haría que la consulta pesada se ejecutará si y sólo sí la última clausula “exists (select * from contrasena)” es TRUE. Si la consulta pesada genera un retardo de tiempo medible tendremos algo que nos indicará que la tabla contrasena existe y además tiene filas. ¿Qué consulta pesada se puede utilizar? Pues cualquier combinación múltiple de joins entre tablas que conozcamos. Para ello se puede utilizar alguna tabla que se sepa que siempre existe y además es accesible. En aplicaciones que ataquen a Microsoft Access 2000 se puede utilizar la tabla MSysAccessObjetcs y en Microsoft Access 2003 y 2007 se puede usar la tabla MSysAccessStorage. Un ejemplo de consulta pesada para extraer información sería el siguiente:
http://www.informatica64.com/retohacking/pista.aspx?id_pista=1 and (SELECT count(*) FROM MSysAccessObjects A 20T1, MSysAccessObjects AS T2, MSysAccessObjects AS T3, MSysAccessObjects AS T4, MSysAccessObjects AS T5, MSysAccessObjects AS T6, MSysAccessObjects AS T7,MSysAccessObjects AS T8,MSysAccessObjects AS T9,MSysAccessObjects AS T10)>0 and exists (select * from contrasena)
Imagen: Medición de tiempos en Access 2000. La consulta tarda 6 segundos. Luego es cierto, la tabla contrasena existe y tiene registros.
Imagen: Medición de tiempos en Access 2000. La consulta tarda 1 segundo porque hemos negado la condición.
Este mismo sistema se puede aplicar a cualquier motor de base de datos del que se conozca o se averigüe una tabla con algún registro. Como se ha visto, basta con realizar una consulta lo suficientemente pesada como para que genere un retardo medible su ejecución.
***************************************************************************************
Artículo publicado en PCWorld Noviembre 2007:
- Técnicas Avanzadas en ataques Blind SQL Injection (I de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (II de III)
- Técnicas Avanzadas en ataques Blind SQL Injection (III de III)
***************************************************************************************
mmm, usando PNGs.......
ResponderEliminarQue paso con el Capitulo III, o ahy termina...?
ResponderEliminar@Rickjack, nop, no termina aquí, la publicaré la semana que viene, a finales... más o menos. ;)
ResponderEliminarSaludos!