martes, 20 de diciembre de 2011

TDSL

¿Qué? ¿Yet another acrónimo ofensivo?

No, Test Driven Self Learning, esto es, utilizar TDD para aprender.

Al encarar la escritura de esto, busqué "test driven learning", que por supuesto trajo innumerables referencias, asi que no hay nada nuevo bajo el sol.



Ya me había cruzado con la idea en un curso de hibernate y otro de ruby, en los cual me daban los tests e implementaciones parciales y para hacer pasar los test, tenía que implementar el código y de paso aprender. Es realmente un buen método.



Ahora bien, ¿qué pasa cuando no existe el curso? Me hallo en la situación de tener que aprender un nuevo lenguaje, tecnología e incluso agregaría paradigma, sin tener a ninguna persona real o virtual conocida que me asista. Así que decidí ir generando yo mismo los tests, como si aprender no fuera el objetivo.

El proyecto tiene que ver con obtener contraseñas a partir de una base de datos. Veamos primero que es lo que podemos encontrar, como pueden estar almacenadas:

  • En texto plano: listo, no hay nada más que hacer.
  • Hasheada: se le ha aplicado una transformación tal que no sabemos la clave.
  • Hasheada con salt: al método anterior se agrega un valor arbitrario y conocido, ya veremos para que.
Para entrar en contexto, el mecanismo de autenticación suele funcionar asi:
  1. El usuario se identifica y provee su clave
  2. Se busca al usuario en la base de datos
  3. Se aplica una transformación a la clave y se controla que el resultado coincida con lo almacenado. Esta transformación puede ser nula, cuando se ha almacenado la clave en texto plano.

Contra un sistema de autenticación hay varios métodos de ataque, algunos son:

  • Online: se prueban diversas claves hasta acertarle utilizando el sistema. Este puede detectar los intentos y bloquear o limitar el acceso.
  • Ingeniería Social: se obtiene la clave directamente del usuario mediante algún tipo de engaño, que va desde tan sencillo como pedírsela directamente como hacerle entrar en un sitio falso.
  • Offline: se obtiene la base de datos y se prueba en la tranquilidad del hogar.

El último método es el que más me interesa ahora, ya que de eso se trata el proyecto. Una suerte de framework para atacar offline eficientemente una base de datos y que eventualmente facilite un ataque personalizado.


Dado un par(usuario,hash), entonces el objetivo es recuperar la contraseña. Los pasos pueden ser:
  1. Buscar hash en internet, si esto falla, continuar.
  2. Determinar que tipo de hash es.
  3. Determinar si y cual salt puede haber.
  4. Reproducir el algoritmo que lo genera
  5. Utilizar una lista de claves frecuentes, aplicar el algoritmo y ver si le pegamos.
(Para ser estricto, tras el paso 3 se podrían usar rainbow tables, pero eso lo dejamos para otro dia, ¿ok?)
    Para el primer paso contamos con los buscadores. A mano he llegado a lograr que google me confunda con un bot y me tire un captcha. Esto no escala, pues aunque de 400 entradas que me restaban de un ataque de 800 pude recuperar 60, me llevó un par de horas, mias, no va.

    ¿Por qué, Charli, que sos tan basher no hiciste un for HASH in $(cut users.txt -d" " -f 3); do wget http://www.google.com/search?q=$HASH -O $HASH.html; done?

    Pues lo hice, pero google me bloqueaba en la primera, supongo que por el user-agent. ¿Sabés que wget puede impersonar cualquier user-agent? Si, pero quería analizar bien los resultados y cuando llegue a 30 o 40, tras 200 intentos, ya fue. Igual iba a tener que inspeccionar los *.html de modo un tanto manual, otro dia será.

    Para determinar el tipo de hash, aprovechamos el paso anterior, en alguna página donde hubo acierto va a decir que tipo es.

    Si hubo salt involucrada la cosa se complica. Lo mejor es tener la base de datos, el código y la configuración, de ahi sale, sino... Ahora es el despues de "ya veremos para que".

    Siempre se deben guardar las claves hasheadas utilizando salt
    • Si no se hashea, se obtiene el 100% de las claves

    • Si se hashea, se obtiene el 99% de las claves débiles como "123456", "maradona", "c@Rl05", "pablo1974", "bugzilla", "klingon", "marsupilami", "newyork", "Oberon". A fines prácticos cerca del %50 del total.

    • Si se usa salt aunque esa salt caiga en manos del atacante, deshabilita buscar en internet y dificulta rainbow tables

    Ok, voy a explicar que son rainbow tables: ¿recuerdan el quinto paso, el de probar las palabras del diccionario contra cada clave? Es algo parecido, pero en lugar de probar y tirar el resultado que no sirve, se generan y guardan todos los hashes de un set para cada algoritmo. El set esta generado por ejemplo por todas las palabras posibles de una a ocho letras combinación de "a-zA-Z0-9". Esto lleva mucho tiempo, ocupa mucho espacio pero luego permite recuperar muy rápido. Más detalles en la internet. Ah, ¿pero por qué un hash interfiere con rainbow tables? Si a tu tonta clave "123456" antes de hashearla le agregás "hola" tal que te quede "123456hola" ahora mide diez y no está en la rainbow table.

    Si el atacante consigue la salt "hola", debe generar todas sus rainbow tables para esa salt. Esto es, debe generar las tablas para cada sitio que ataque. Si además le agregas una "salt local" (como yo la llamo en contraposición a la "salt global") tal que te quede "123456hola#{userid}", tiene que generar la rainbow table para cada usuario. Esto no imposibilita el ataque, pero lo dificulta. Si es la cuenta de alguien importante, mas vale que ponga una clave larga.


    Tras el rant, sigamos con reproducir el algoritmo. Es bueno tener el código fuente. Ah, ¿dije algo obvio? Si no, un par (usuario, clave) conocido en la base para utilizar como referencia, para usar algorimos equivalentes quizas en otro lenguaje.

    El problema es el último paso. En una ocasión, 1000 usuarios con un diccionario de 68.000.000 de claves calculo que me hubiera llevado dos dias. Dije "calculo" y ahi esta la clave de todo este asunto, pues como tenía 4+2 cores a mi disposición, de los cuales usé 3+1, pude paralelizar y me llevó medio dia. It's a bash of magic.

    Ahora entra erlang en la ecuación.

    No voy a repetir la marketinera introducción a erlang, podés leerla directamente de las fuentes. Tratándose erlang de un lenguaje orientado a la concurrencia y a ser distribuido, puede ser una buena elección, pero tengo que convertir mis scripts en bash, php, ruby y perl en algo coherente.

    Comienzo con el de php, que lo que hace es convertir "hola" en "h01@", "h014", "h01A", "h01a", "h0|@", "h0|4", "h0|A", "h0|a", "h0L@", "h0L4", "h0LA", "h0La", "h0l@", "h0l4", "h0lA", "h0la", "h@1@", "h@14", "h@1A", "h@1a", "h@|@", "h@|4", "h@|A", "h@|a", "h@L@", "h@L4", "h@LA", "h@La", "h@l@", "h@l4", "h@lA", "h@la", "hO1@", "hO14", "hO1A", "hO1a", "hO|@", "hO|4", "hO|A", "hO|a", "hOL@", "hOL4", "hOLA", "hOLa", "hOl@", "hOl4", "hOlA", "hOla", "ho1@", "ho14", "ho1A", "ho1a", "ho|@", "ho|4", "ho|A", "ho|a", "hoL@", "hoL4", "hoLA", "hoLa", "hol@", "hol4", "holA", "hola", "H01@", "H014", "H01A", "H01a", "H0|@", "H0|4", "H0|A", "H0|a", "H0L@", "H0L4", "H0LA", "H0La", "H0l@", "H0l4", "H0lA", "H0la", "H@1@", "H@14", "H@1A", "H@1a", "H@|@", "H@|4", "H@|A", "H@|a", "H@L@", "H@L4", "H@LA", "H@La", "H@l@", "H@l4", "H@lA", "H@la", "HO1@", "HO14", "HO1A", "HO1a", "HO|@", "HO|4", "HO|A", "HO|a", "HOL@", "HOL4", "HOLA", "HOLa", "HOl@", "HOl4", "HOlA", "HOla", "Ho1@", "Ho14", "Ho1A", "Ho1a", "Ho|@", "Ho|4", "Ho|A", "Ho|a", "HoL@", "HoL4", "HoLA", "HoLa", "Hol@", "Hol4", "HolA", "Hola" y es llamado mediante un vulgar system/exec desde perl y ruby (bugzilla y redmine respectivamente).

    Esta función que sorpresivamente se llama leet(), me costó bastante, ya que la solución es recursiva. ¡Qué bien! Erlang es funcional (o sea que todo se hace con recursividad), no debería ser tan terrible, ¿no?

    Varios dias despues:

    De modo colateral he hallado que erlang soluciona todas esas discusiones de como testear los métodos privados que asolan las listas de discusión ágiles de un modo muy sencillo.

    La unidad de compilación es el módulo, que podría ser asi:

    -module(cracker).
    -export([leet/1]).

    leet(Palabra) ->...

    funcion_interna() -> ok.

    otra_funcion_interna() -> ok.

    Los más sagaces podrán inferir que desde afuera se puede acceder a leet/1 y no asi a las funciones internas. Salteemonos un paso y veamos el código que prueba esto:

    -module(cracker_tests).
    -include_lib("eunit/include/eunit.hrl").

    leet_test()->?assertEqual(..,cracker:leet("hola")).

    otro_test()->?asserEqual(ok,cracker:funcion_interna()).

    ¡No! ¡A los sagaces nos diste a entender que el módulo cracker_test no puede ver a las funciones que no han sido exportadas!

    Es parcialmente verdad, si desde el interprete (erl), compilamos normal.

    1> c("src/cracker").
    {ok,cracker}
    2> cracker:otra_funcion().
    ** exception error: undefined function cracker:otra_funcion/0


    pero si pasamos la opción "export_all", vemos todo, testeamos todo.

    3> c("src/cracker", [export_all]).
    {ok,cracker}
    4> cracker:otra_funcion().
    ok



    Sin tocar el código, sin agregar funciones,  sin afectar nuestra política de lo que es público y lo que es privado.

    Sigo cuando logre implementar leet/1.

    jueves, 15 de diciembre de 2011

    1hackparaloschicos 2

    Baja concurrencia y bastante impuntual. De, según oí, 60 inscriptos, vino menos de la mitad, lo que me llama la atención ya que no era del todo gratis. Mientras esperábamos, Fernando Gont contó sus experiencias laborales en el puerto, sin desperdicio.

    Quizás parte de la inconcurrencia se haya debido a que había a la misma hora una charla de continuidad de negocio en ADACSI

    A beneficio de http://www.1hackparaloschicos.org 14 de Diciembre de 2011,Auditorio Universidad de Belgrano

    IPv6: Historia, presente y futuro


    IPv4 se está quedando sin direcciones, punto.

    Existe CGN/LSN (Carrier Grade NAT/Large Scale NAT) que puede mitigar (y lo está haciendo en algunos lugares de Asia y Europa), pero como uno ya está haciendo NAT, puede traer problemas. Además está el asunto legal, se torna más complicado rastrear el origen de una conexión. Y el monetario, sale u$s 1M. En África y LAC (Latino América y Caribe, vayan aprendiendo siglas) aún quedan direcciones libres, asi que se puede llegar a zafar si IPv6 llega primero.

    IPv6 no es más seguro que IPv4, no tiene mejor QoS. Ni siquiera es backward compatible. Lo que sí tiene es 96 bits más de direccionamiento, lo cual es MUCHO. Tambien esta soportado por casi todos los sistemas operativos. El problemas es que hay que reemplazar muchísimo equipamiento core.

    Tambien existe una profunda inexperiencia, sobre todo frente a los 30 años de IPv4 y su falta de uso extendido hace que aún no se haya descubierto una parte considerable de las vulnerabilidades que seguramente tiene.

    La performance puede ser mala tambien, pues suele estar implementado en software en lugar de hardware.

    Y la etapa de transición es aún peor, pues conviven IPv4, IPv6 y los sistemas de adaptación.

    Me imagino, aunque no es idea mia, que los proveedores de networking son los que frenan la implantación, pues el equipamiento lo van a vender igual, hoy o mañana. Pero los CGN no tienen sentido si nos vamos ya a IPv6. Primero te vendo NAT, luego IPv6.


    Correo electrónico seguro y cifrado - Santiago Cavanna


    Distinguió el cifrado de almacenamiento, de canal y de objetos circulando. En un canal encriptado entre dos servidores de mail el mail esta seguro en términos de integridad y confidencialidad, no? Pero si generamos un mail falso y lo metemos en ese canal...

    Luego un poco de historia de utilización de cifrados, ligado al aspecto militar == negocios.

    El ambiente actual es hostil y cada vez empeora, por lo cual no conviene intercambiar información importante (¿quién sabe cuál es importante y para quién?) por mail, chat o incluso teléfono.

    ¿Por qué cifrar correo si nunca me ha traido problemas no hacerlo? Bueno, hasta que te trae.

    Como inicio de solución PGP o SMIME.


    Agresores Sexuales - Identificación y aplicación de la técnica de perfilación criminal - Maria Laura Quiñones Urquiza


    Pidió no grabar, filmar ni fotografiar la exposición. Yo, fiel a mis promesas, ni tomé notas, entiendo el porqué. Sólo voy a decir que CSI, L&O SVU no son del todo fantasía.

    Vidas Reales, rastros digitales - Gustavo Daniel Presman


    Expuso de privacidad y trazabilidad. Distinguió entre la información cedida voluntariamente y la "otra". Quedémos con la otra.

    De como es bastante difícil borrar incluso en la propia computadora todo traza de actividad. Por ejemplo al borrar el historial de navegación, bien puede quedar en un archivo que es borrado por el sistema operativo, que bien puede no volver a escribirle nada encima y se torna recuperable.

    Exif en fotos, tipo GPS e IP, que puede conducir a GeoIP. Marca cámara y serial number. Buen modo de rastrear un celular o cámara robado o perdido...

    Mensajeria deja trazas en el archivos temporales.

    USB, es posible obtener información de dispositivos ya desconectados, al menos en windows.

    Propuso que además del log de ip/client de los ISP, se agregue el tráfico, esto es ip:port->ip:port, pero no de contenido.

    Contó de saber de varios casos en que por mala conversión horaria de logs ha provocado que la policía hallane la casa equivocada. Brillante.







    No me pude quedar a las otras dos charlas