domingo, julio 05, 2009

Arithmetic Blind SQL Injection (I de II)

***************************************************************************************************
- Arithmetic Blind SQL Injection (I de II)
- Arithmetic Blind SQL Injection (II de II)
***************************************************************************************************

1.- Introducción

Una de las limitaciones de los ataques a ciegas viene impuesta por la posibilidad de inyectar de forma eficaz, es decir, obteniendo el resultado deseado o no, dentro de una aplicación web.

Existen ciertos entornos en los que, aunque el parámetro es vulnerable a inyección de código, la inyección práctica para la extracción de datos no es posible mediante el uso de operadores lógicos. Esto es debido al entorno concreto dónde se encuentra la vulnerabilidad y la limitación concreta en la inyección.

Uno de estos entornos clásicos es la inyección en funciones matemáticas en las que no existe posibilidad de inyectar código para crear una lógica booleana con operadores AND u OR. La explotación mediante técnicas a ciegas se realiza basándose en construir inyecciones de cambio de comportamiento cero, es decir, la inyección es ejecutada pero no se cambia la lógica de la aplicación, y cambio de comportamiento positivo, es decir, la inyección es ejecutada y se cambia el comportamiento de la aplicación, utilizando para ello los operadores OR y AND, como se explica en "Blindfolded SQL Injection", por ejemplo, pero hay entornos dónde esto no va a ser posible.

Supongamos una aplicación web que recibe un parámetro numérico id que va a utilizar en dos consultas SQL. Estas dos consultas utilizan un factor de anidamiento de paréntesis distinto y la aplicación no devuelve ningún resultado visible hasta que no se han procesado las dos consultas SQL. Es decir, el cliente de la aplicación web no recibirá ningún dato hasta que ambas hayan terminado. El esquema de funcionamiento de esa aplicción sería el siguiente:

Recibir_parámetro(id)
Select c1 from tabla1 where id=id
Select c2 from tabla2 where id=abs(id)
Devolver_datos()


Esta sencilla estructura hace que no sea posible conseguir una inyección de comandos SQL que sea sintácticamente válida en las dos instrucciones SQL si estas necesitan el uso de operadores lógicos AND u OR.

Una inyección del tipo 1 and 1=1 será correcta en la primera consulta SQL pero no en la segunda. Una inyección que sea sintácticamente correcta en la segunda, como por ejemplo 1) and (1=1 dará error en la segunda consulta.

Para ilustrar este ejemplo se va a utilizar la aplicación web. Primero, hay que analizar cuál es el comportamiento normal de la aplicación sin que se produzca ninguna inyección de comandos SQL. Como se puede apreciar en la Imagen 1, la aplicación muestra, en su comportamiento normal, una noticia.


Imagen 1: La aplicación muestra una noticia

Si se intenta realizar una inyección de comportamiento cero como las propuestas en los entornos tradicionales se puede apreciar que la aplicación genera un error. Esto es debido a que sintácticamente no es correcta porque el parámetro está introducido en un procedimiento matemático tal y como se ha ilustrado en este apartado.


Imagen 2: Inyección en procedimiento matemático

Es por tanto necesario establecer una lógica con inyecciones de cambio de comportamiento cero y cambio de comportamiento positivo sin utilizar operadores lógicos. En estos entornos se hace necesario construir la lógica booleana de extracción de datos utilizando operaciones matemáticas.

2.- Solución 1: División por 0

Este método fue explicado por David Litchfield y fue el primero válido para resolver esta indeterminación. El objetivo es conseguir un error de base de datos cuando la condición de búsqueda sea cierta. Para ello, la inyección de cambio de comportamiento cero buscará construir divisiones del tipo 1/1 y la inyección de cambio de comportamiento positivo, la que marcará en este caso el "TRUE" será obtenida con operaciones 1/0.


Imagen 3: Inyección de cambio de comportamiento cero

La inyección 1/1 genera un cambio de comportamiento cero debido a que 1/1 devuelve 1 en el lenguaje SQL. Esto funciona de esta manera porque el motor de base de datos está ejecutando la operación matemática de división entera con los valores 1 y 1.

Sin embargo, si se cambia el valor del divisor por un 0 se estará incurriendo en una división por cero que genera una excepción en todos los motores de bases de datos que, en el caso de no estar tratada por la aplicación web, puede generar algún cambio en los resultados.


Imagen 4: Excepción producida por el intento de división por cero

A partir de este entorno, ya es posible establecer toda una lógica para obtener los datos de la base de datos. En este entorno el primer usuario de la tabla sysusers es dbo, luego el valor ASCII de su primera letra, la “d”, es 100. Si se realiza un inyección como la siguiente:

id=1-(0/(select top 1 ascii(substring(name,1,1))-99 from sysusers order by name asc))

se estaría inyectando algo igual a id=1-(0/(100-99)), o lo que es lo mismo id=1-0 o directamente id=1. Cualquier valor que se reste al valor ASCII de la letra buscada que no sea exactamente el valor del caracter buscado dejará la consulta sin cambios. Lo que significará que el valor no es el correcto.


Imagen 5: El valor buscado NO es 99

Por el contrario, si en este entorno se introduce el valor 100, es decir, haciendo que se cumpla la condición de igualdad entre el valor buscado y el valor probado se puede observar que se obtiene una excepción de división por cero que significa la confirmación de la condición.


Imagen 6: Excepción de división por cero

***************************************************************************************************
- Arithmetic Blind SQL Injection (I de II)
- Arithmetic Blind SQL Injection (II de II)
***************************************************************************************************

7 comentarios:

ramandi dijo...

Fantásticamente explicado, como siempre!! :-))

Ayak dijo...

Cal y arena

Acabo de leer vuestro artículo en PCworl de julio, muy bueno, útil y didáctico, Lo mismo que este.

"va a utilizar un dos consultas SQL"->va a utilizar en dos consultas SQL


"váldido"->válido

Maligno dijo...

@ramandi, gracias.

@Ayak, gracias y corregido.

Anónimo dijo...

Interesante, aunque creo que para aclarar el ejemplo que se pone se deberian poner unos paréntesis. En lugar de escribir:

"...estaría inyectando algo igual a id=1-(0/100-99),..."

Entiendo que lo que se pretende decir es:

"...estaría inyectando algo igual a id=1-(0/(100-99)),..."

Ya que para que el resultado no no se vea afectado, es indispensable que el cálculo quede en el denominador de la operación.

Saludos

Maligno dijo...

@anónimo, cierto. Lo corrijo.

Alvaro dijo...

Hola!

He estado probando estas técnicas, y me surge una duda:
Wordpress, la paginación funciona con el siguiente comando: ?paged=3
Parece que le metas lo que le metas, solo coge el primer número, todo lo que venga detras lo desecha. ¿Hay algún método para saltarse esta protección?

Otra duda:
En mi página hay un index.php?id=1 Ese 1, se va a una consulta SQL, en ppio sería inyectable. Pero cuando pongo &id=11' and '1'='1 ejecuta esto: [...]id='11\' and \'1\'=\'1'; Es decir, me escapa las comillas. ¿Hay algún método para saltarse esta protección?

Maligno dijo...

@Álvaro, no necesitas las comillas, puedes hacerlo con espacios, son valores numéricos...

Leéte los artículos de Blind SQL Injection de esta lista:

http://elladodelmal.blogspot.com/2009/05/lista-de-articulos.html

Saludos!

Entradas populares