martes, 17 de diciembre de 2013

Vulnerabilidad en printf (II)


Continuamos analizando la función printf y la vulnerabilidad que lleva incorporada. En el post anterior finalizamos viendo como quitando una variable en la llamada a la función se lograba acceder a la siguiente entrada en la pila.

Lo mismo se hubiera obtenido si en vez de eliminar una variable hubiéramos colocado una definición de formato más.

Partiendo de la llamada original a la función

printf("%s - i = %d - J = %d - k = %d\n", string1, i, j, k);

Hemos llegado a obtener un valor que estaba más afuera del ámbito del programa modificando la llamada

printf("%s - i = %d - J = %d - k = %d\n", string1, i, j);

Y se hubiera obtenido el siguiente valor con la siguiente llamada a la función
printf("%s - i = %d - J = %d - k = %d  %s\n", string1, i, j, k);

Podremos avanzar en la lectura de la pila más allá del ámbito de la función según la siguiente resta:

(Núm. de especificaciones de formato - Núm. de variables)

Ejecutemos nuevamente el programa  hasta el breakpoint que está junto antes de la llamada a la rutina de impresión. Y  observemos la pila.


Según lo visto hasta ahora se podría acceder a cualquier valor, por ejemplo a la cadena ASCII que contiene el valor del valor del nombre del programa.

Pomgamos en nuestro programa entonces la siguiente llamada de función

printf("%x%x%x%x%x%x%x%x%x%x%x%x\n%s");

Compilamos y ejecutamos el programa

 Nos interesa la segunda línea de la salida que es el valor que buscábamos.

Vulnerabilidades y explotación de las mismas.

 Para finalizar  y antes de entrar en el siguiente post donde veremos si es posible ir directamente a una posición de memoria directamente, hay que aclarar la diferencia que hay entre vulnerabilidad y explotación de la vulnerabilidad. 

Es evidente que en este ejemplo, la información que hemos obtenido pues no nos sirve de mucho. Pero podría ocurrir que  una de las entradas en la pila fuera el puntero a una dirección de memoria con información sensible (por ejemplo el hash de una clave). Podríamos obtener ese hash y poder efectuar contra el un ataque de diccionario o de fuerza bruta.
También en este caso  estamos trabajando con un control total sobre la cadena de formato que confeccionamos a nuestro gusto. 
 En una situación real de intento de ataque aprovechando esta vulnerabilidad no tendremos esa posibilidad de forma directa y probablemente debamos llegar a ella a traves de otra vulnerabilidad, quizá un desbordamiento de memoria.
Pero lo que tiene que quedar claro es que una cosa es la existencia de una vulnerabilidad y  otra que esa vulnerabilidad sea explotable para sacar algún beneficio.

. 

Hasta la próxima

 




jueves, 21 de noviembre de 2013

Vulnerabilidad en printf (I)

Vuelvo a retomar este blog tras un parón motivado por causas ajenas (léase falta de tiempo).

Aunque sé que voy dejando alguna serie de entradas sin finalizar me ha animado a escribir este post una vulnerabilidad sobre la que leí algo y sobre la que me pareció instructivo profundizar: la vulnerabilidad de la cadena de formato (format string).

La forma más fácil de empezar a explicar lo que es la cadena de formato es recurrir a la función printf() que todo el que haya programado un poco ha conoce.
¿Quien no ha escrito alguna vez printf( "hola mundo"); ?.

Lo más llamativo de esta función es que no tiene un número fijo de parámetros. Gracias a esta flexibilidad podemos confeccionar textos que contengan tantas variables como necesitemos. Pero en esta bendición lleva grabada su maldición.

Lo primero que necesitamos es ver como el compilador resuelve el paso de un número variable de parámetros. Para necesitaremos un depurador y algo de conocimientos de arquitectura x86.

La Pila

La pila, también conocida por su nombre en ingles: stack, es una zona de memoria que es referenciada por dos registros y gestionada por unas instrucciones determinadas.
Tres conceptos básicos del manejo de pila:


  1. Las instrucciones que manejan de forma explícita (1)  la pila son: push y pop. La primera coloca en la pila y la segunda la extrae. La pila es una cola LIFO (last input - first output).
  2. La pila está referenciada por dos registros: el registro base de la pila (BSP) y el registro indicador del tope (ESP) de la pila.
  3. En la arquitectura x86 la pila va desde las posiciones altas a las bajas. Esto quiere decir que a cada push que hagamos el registro ESP disminuye en 4 porque cada entrada de la pila es una palabra (4 octetos).


Conceptualmente hay que ver la pila como sistema en que las piezas se colocan y extraen por debajo.

No necesitamos saber nada más para poder entender el resto del artículo.

Las Herramientas.

Necesitamos el depurador para ser capaces de sacar el estado de un programa en un momento determinado de su ejecución. Por estado del programa se entiende: la memoria, los registros, la pila y la instrucción siguiente a ejecutar.
Vamos a usar el conocido ollydbg.
Este programa puede ser descargado de su página web y no necesita instalación. Simplemente con descomprimir el fichero ya podemos trabajar con él.

Necesitaremos también un compilador C. Para este ejemplo he usado Tiny C Portable  que no necesita instalación y que se puede descargar de esta página.
Podemos usar cualquier otro compilador pero en este caso no será posible seguir la práctica tal cual. Cada compilador resuelve de forma diferente las referencias a funciones, la estructura de los datos y otros procesos.

En este enlace podréis encontrar tanto los fuentes, aunque son mínimos, como las compilaciones para aquellos que tenga pereza por compilar programas.

En esta práctica voy a omitir bastantes pasos intermedios que he he debido realizar para centrarme en el concepto por lo que si no se tienen conocimientos de ensamblador ni se tiene habilidad con el manejo de ollydbg lo que aconsejo es usar el mismo compilador que he usado para la práctica.

Empezando

Tenemos  este simple programa:

main()
{
char string1[] = "123456789abcdef";
int i, j, k;
    char _userin[80];
    i = 100;
    j = i + 1;
    k =  4194382; //j + 1;
   
    //printf("%s - i = %d - J = %d - k = %d\n", string1, i, j, k);

    return 0;


}


Arrancamos Ollydbg y lo cargamos

Podemos ver la ventana dividida en 4 secciones en sentido de las agujas de reloj:
  1. Área de programa
  2. Registros
  3. la Pila
  4. La memoria


      

   Compilamos y ejecutamos:



                                      
                    
Cargamos el programa en Ollydbg. 




En la ventana del programa podemos observar que está marcada la siguiente instrucción a ejecutar, que es en este caso el inicio de programa (Module Entry). Nos vamos un poquito más arriba hasta la dirección 

004010B6. 

Nos posicionamos con cursor sobre ella y hacemos click para seleccionarla.
Creamos un breakpoint en esta instrucción pulsando F2. Veremos que la línea queda en rojo.
Analicemos la línea que hemos seleccionado. 
Se trata de una llamada a la función printf (ollydbg siempre que puede resuelve las direcciones con nombres)
                       
Ejecutamos pulsando la tecla F9 (O bien en el menú superior Debug -> Run) y el programa se ejecutará hasta llegar al breakpoint marcado. Observamos la ventana 3  que es la ventana de la pila.

                           


Ahí tenemos los parámetros que se van a pasar a la función: La cadena de formato, el primer parámetro con la cadena de caracteres, y los siguientes parámetros con los valores 64, 65 y 66 que se corresponde con la representación hexadecimal de 100, 101 y 102.

Con esta información podremos entender un poco mejor como se realiza el análisis de parámetros de la función printf.

Extrae el primer elemento de la pila que es la cadena de formato. La analiza carácter a carácter. Si encuentra el caracter "%" analiza la siguiente letra.

  •  Si la siguiente letra es una s extrae el siguiente elemento de la pila. Y coloca la cadena de caracteres apuntada por esa dirección en el lugar de %s.
  •  Si la siguiente cadena de caracteres es d, extrae el siguiente elemento de la pila y coloca su valor en decimal.

 Análogos procesos realiza para las otras posibilidades: %x, %n, etc.

Como se puede ver en algunos parámetros se pasa el valor y en otros la dirección de memoria donde esta el valor. Esto es lo que se conoce como paso de parámetros por valores o por referencia. Las variables de tipo string (%s) siempre se pasan por referencia y las de tipo numérico (%d, %x) siempre se pasan por valor. Para el resto de los otros tipos de variables es necesario consultar la documentación.

Antes de continuar con la ejecución de programa nos más abajo, hasta encontrar la llamada a la función exit que en este caso estará en la dirección 00401159. Ponemos aquí otro breakpoint para detener el programa justo antes de salir y poder ver el resultado. Damos nuevamente run (F9) y cuando se detenga en la llamada a la función exit nos vamos a la salida del programa que en este caso es la ventana de DOS que se ha abierto al cargar el programa en Ollydbg. Y vemos, una vez más la salida esperada.

 Empezando a torcer las cosas.


 Una vez tenemos clara tanto la lógica básica de la función como el paso de parámetros empezamos a pensar de forma agresiva. ¿Y si cargo menos variables y mantengo el número de caracteres %?
 Vamos a sustituir la sentencia:

 printf("%s - i = %d - J = %d - k = %d\n", string1, i, j, k);

 por

 printf("%s - i = %d - J = %d - k = %d\n", string1, i, j);  //hemos quitado el último parámetros. La variable k

 Lo compilamos, lo ejecutamos y obtenemos lo siguiente:

                           


Antes de analizar el resultado, podemos pensar que el compilador debería haber detectado que se pasan menos variables de las que se pueden deducir analizando la cadena de formato. Bueno, eso es cierto en este caso en el que la cadena de formato es un texto fijo y predeterminado. En otras situaciones la cadena de formato es una variable cuyo valor solo es conocido en el momento de ejecución. El compilador poco tiene que hacer en esta situación.

Aclarado este punto vemos que donde debería estar el valor 102 sale 1244928.

Para entender lo que ha ocurrido arrancamos este nuevo programa en ollydbg y marcamos los dos breakpoint, uno en la llamada a printf que está por arribe del Punto de Entrada y otro en la salida que está por debajo. Recordemos que arrancamos otro programa y es necesario volver a definir estos puntos. Run (F9) nuevamente y una vez detenido el programa nos vamos a ver la pila

                           
                           
Vemos que el siguiente elemento en la pila pasa a formar parte de los parámetros. El valor en hexadecimal de ese elemento es 12FF00 que en decimal es 1244928 que coincide con el valor que nos ha salido en la ejecución.
Nuevamente Run (F9) comprobamos el resultado en la pantalla de ejecución y nuevamente Run F9 para finalizar el programa.

Antes de seguir avanzando en las posibilidades exploración de elementos en la pila vamos a ver el impacto que puede tener en esta vulnerabilidad el tipo de datos.
Cambiemos la sentencia printf por esta:

printf("%s - i = %d - J = %d - k = %s\n", string1, i, j);

Hemos cambiado el último tipo de variabla de númerico decima (%d) a string(%s).

Compilamos y ejecutamos.

                           
                           
Y nos saldrá la interpretación en carácteres de lo que haya en la dirección de memoria 12FF00. El paso de parámetros es igual en este caso como en el anterior, pero la función al ver %s en vez de usar ese valor lo usa como referencia para encontrar el valor que debe colocar en el buffer de impresión.

Más adelante veremos como también podemos usar esto para ir a otras direcciones. Por el momento paramos aquí y en la próxima entrega expandiremos la posibilidad de explorar la pila.

Por hoy es todo, sólo queda practicar un poco y familiarizarse con ollydbg. 


(1) Otras instrucciones como CALL y RETURN también introducen y extraen datos de la pila









                         

martes, 6 de agosto de 2013

¿Ha sido la red TOR comprometida?

La noticia de que Eric Eoin Marques  dueño de un ISP llamado Freedom Hosting y que según el FBI este ISP es el mayor distribuidor de pornografía infantil,  ha sido detenido gracias a que ha sido localizado usando la red TOR ha causado cierta inquietud en los entornos preocupados por el anonimato.

Antes de sacar conclusiones vamos a ver que ha pasado realmente….

¿No garantizaba TOR el anonimato?

Pues sí, y lo sigue garantizando, pero para entender lo que ha pasado y saquemos conclusiones primero hemos de saber algunas cosas más que ofrece TOR y no son tan conocidas.

Los Servicios ocultos (Hidden Services).
Lo más fácil para entender lo que es un servicio oculto es pensar que es un servicio cuyo anonimato está garantizado por la red TOR. El anonimato en el otro lado de la conexión. Dentro la red TOR los servidores anonimos están en el dominio .onion
Veamos lo que dice la wikipedia sobre los Servicios ocultos de TOR:

"Tor can also provide anonymity to websites and other servers. Servers configured to receive inbound connections only through Tor are called hidden services. Rather than revealing a server's IP address (and thus its network location), a hidden service is accessed through its onion address. The Tor network understands these addresses and can route data to and from hidden services, even those hosted behind firewalls or network address translators (NAT), while preserving the anonymity of both parties. Tor is necessary to access hidden services"

The Freedom Hosting
Un proveedor de alojamiento con la posibilidad de alojar una web completamente anónima y secreta en sus servidores. Esto, en principio, no tiene nada de ilegal, pero los responsables de este ‘hosting’ tenían la manga demasiado ancha y, según cuentan, se convirtió en un nido de pedófilos y ya en 2012 Anonymous denunciaba su existencia. Se estima que la cantidad de pornografía infantil alojada en Freedom Hosting podría rondar los 100 GB.

Si bien están demostrados los beneficios de la red TOR para mantener el anonimato de la gente, sobre todo en los regimenes opresores. Los servicios ocultos  presentan una cara bastante más negra ya que se han convertido en un nido de webs con actividades ilegales: pornografía infantil, tráfico de armas y drogas, etc.
Muchas webs activistas han decidido alejarse de este submundo y han optado colocar sus servidores en sitios más transparentes.

¿Que ha pasado?. 

Primero indicar que el ataque no se ha realizado contra la red TOR, que en otros usos sigue garantizando el anonimato. Por suerte.

El  ataque ha tenido dos etapas.

  • Han hackeado un número indeterminado de servidores de Freedom Hosting colocando un JavaScript.
  • El JavaScript utiliza una vulnerabilidad conocida: MFSA 2013-53 del navegador que usa TOR y se ha distribuido entre los usuarios de estos servicios. 
 Este JavaScript obtiene la MAC y el nombre del equipo en el que se ejecuta y envía por fuera de la red TOR esta información. Y también de forma implícita la dirección IP del  equipo. 

Epílogo. 

Esta información era enviada a uno servidores que al parecer estaban alojados en una agencia gubernamental relacionada con el FBI. 


Los responsables del proyecto TOR han informado que esta red no tienen ninguna vinculación con TOR Project BLOG y que seguirán trabajando para reforzar la privacidad de la red.

Conclusiones. 

Los nodos TOR no han sido comprometidos ni los mensajes que circulan por la red han sido descifrados. El ataque ha sido realizado explotando vulnerabilidades  en los extremos las conexiones que usaban esta red.
La conocida vulnerabilidad  MSFA 2013-53 y otra no hecha pública que existía en los servidores del Freedom Hosting.