sábado, 27 de julio de 2013

Mutation Testing Framework


Presento aquí el resultado de mi trabajo colectivo de mutación de código para testing. Digo "colectivo" por las horas que invertí en análisis y diseño viajando en colectivo[1]. Seguramente estoy reinventando la rueda[2], pero no me importa, el camino avasalla en importancia al destino.

If you need an english version, ask me and I will add it to the top of my backlog

He utilizado bastante TDD pues de no ser así hubiese incurrido en pecado mortal. Hay que predicar con el ejemplo. Es más, el proceso fue reflexivo, se aplicó contra su mismo codigo fuente. Con respecto a este tema, me interesa aclarar que para mi TDD es tan sólo una técnica más, un recurso en nuestra valijita de herramientas. No significa que uno se sienta con la mente en blanco y tira un test y el código y así avanza. Me parece correcto hacerlo así en un taller de TDD, pero si nos detenemos ahí, es como quedarse con la idea de que la danza clásica son las posiciones de los pies y agarrarse de una barra frente a un espejo, que tocar el piano son unas escalas, boxear es saltar la soga y perseguir gallinas o programar es implementar sort() y search().

Mi idea original fue utilizar php que tiene un tokenizador[3] y es lo que más conozco, para mi desgracia. Cuando en los primeros viajes comencé a percibir que podía haber mucha recursividad pensé en erlang, el cual necesito practicar para recupera mi autoestima. Inmediatamente rechacé la idea, KISS[4]. Dos viajes después, tras haber visto que python tambien tiene un sencillo tokenizador[5] (y quizas ruby[6] y cobol[7]) y percibiendo el potencial de utilizar multicores en múltiples máquinas, había reincorporado erlang y en lugar de un mutador de código para php tenía en mente un framework para usar con cualquier lenguaje que alguien se tomara la molestia en preparar. Bueno, ese era el plan.

Testing por mutación


El testing por mutación de código se basa en la idea de que si los test están bien hechos, deberían detectar cualquier cambio en el código fuente. Entonces, hay que modificar arbitrariamente el código respetando las reglas del lenguaje y ejecutar los tests, alguno tiene que fallar. Si no es así, falta cobertura o faltan casos.

Las mutaciones sobre las que decidí trabajar son las más sencillas: cambiar operadores aritméticos y de comparación, no mucho más que eso. Para hacer cambios más complejos hay dos opciones: usar un AST[8] y ver como manipularlo o generar más mutaciones que serán eliminadas por el compilador (o interprete en la primera etapa).

El proceso consiste en tomar un archivo fuente, obtener los tokens, generar un archivo fuente variando un token, luego otro y así, siempre ejecutando los tests y esperando que no falle, en cuyo caso, se corta y avisa al humano para que mejore los tests.

En [9] cuento superficialmente mi experiencia académica de uso con Jumble, un mutador de código para java y otras técnicas de automatización de test. Este proyecto es resultado de haber tomado el curso "Generación Automática de Tests Unitarios" (ECI 2012 N2) [10] a cargo de Nazareno Aguirre [11], Universidad Nacional de Río Cuarto, Argentina

Alcance

Mis metas fueron haciéndose cada vez más ambiciosas:
  1. mutador de codigo para php
  2. framework para varios lenguajes
  3. usando erlang
  4. con procesamiento paralelo y distribuido
  5. comprender el trasfondo teórico
  6. para poder usar otros lenguajes que no tienen el tokenizador tan accesible y hacer mutaciones más complejas
He decido que hay tres etapas y sólo transitar la primera, quizás la segunda. Eventualmente, si surge la necesidad, la tercera.

Loops


Un problemas interesante que intuí es que si tocás la condición de un loop, podés entrar en infinito. Esto produce que haya que darle un tiempo máximo de ejecución a cada test. Lo que debe hacer al comienzo el framework es una ejecución normal de referencia en cada nodo para tomar el tiempo y usarlo como base para el timeout de las ejecuciones sobre el código mutado. Si hay timeout, considero que el test falló, o sea que esta ok.

Código original:

for ($i = 0; $i < 5; $i++)

Mutaciones:

for ($i = 0; $i <= 5; $i++) -> debería fallar el test

for ($i = 0; $i <= 5; $i--) -> loop infinito

Aunque luego exploro la posibilidad de controlar de modo selectivo algunas mutaciones, lo que implementé fue ejecutar un test de referencia para tomar el tiempo y luego usar timeout para cortar en caso de anomalía.

 

Combinatoria


Otro problema es la combinatoria. Si para cada token que es mutable se hace toda la combinatoria con los otros, el número puede llegar a ser muy, muy alto. No sé por que esa fué mi primera idea, pero pronto caí en cuenta de mi error y sólo se hacen las combinatorias para cada token independiente de los otros.

Dado

if a + b == c

tenemos

if a (+,-,*,/,%,^) b (<,>,<=,>=,!=,==) c

Si combinara todo tendría  6 x 6 = 36 ejecuciones, pero sólo hago 6 + 6 = 12. Con dos tokens mutables parece poca diferencia, pero si fueran cien tokens tendriamos 6100 = 6100 en lugar de 6 x 100 = 600. Unos pocos segundos contra algunos millones de años.

Falsos positivos


El siguiente código tiene una mutación que es inocua ya que produce el mismo comportamiento y sin embargo parece un error:

<?php 
$i = 0;
while ($i != 5) {
   print "$i\n";
   $i++;
}
<?php 
$i = 0;
while ($i < 5) {
   print "$i\n";
   $i++;
}

Queda un criterio humano final para decidir.

Concurrencia


Otro problema más, relacionado a la ejecución simultánea de los tests es la concurrencia sobre las distintas versiones del código. Una manera es replicar el ambiente para cada instancia. Dije "instancia", no "nodo", o sea que en una misma máquina con N cores hay N instancias. La otra es... tuve un esbozo pero lo olvidé, ya volverá cuando haga falta.


Arquitectura



La comunicación entre el componente del lenguaje y el core es mediante un mensaje json[12]. El componente del lenguaje debe identificar cada token con su valor y su clase. Había pensado que los tokens no mutables se simplifiquen en uno solo, de modo tal que:

if a + b == c {
  printf("hola");
}

se tokeniza:

if
a
+
b
==
c
{
printf
(
"hola"
)
;
}

y se simplica:


"if a" 
+ operadorAritmético
b
+ operadorComparación
c { printf("hola"); }

pero esto es optimización prematura, y le da a cada componente de lenguaje la responsabilidad duplicada de simplificar, así que decidí que el core se encargue de simplificar, aun así es responsabilidad del componente del lenguaje identificar la clase:

if       -> inmutable
a        -> inmutable
+        -> operadorAritmético
b        -> inmutable
==       -> operadorComparación
c        -> inmutable
{        -> inmutable
printf   -> inmutable
(        -> inmutable
"hola"   -> inmutable
)        -> inmutable
;        -> inmutable
}        -> inmutable

y definirla:

operadorAritmético extiende simétrica
   mutaciones: +,-,/,%,*

habiendo dos tipos de clases, las simétricas y las asimétricas, esto es porque hay elementos completamente intercambiables y otros que no:

operadorControl extiende asimétrica
   elemento: break
     mutaciones: continue, exit, blanco
   elemento: exit
     mutaciones: blanco
   elemento: continue
     mutaciones: break, exit, blanco

Por ejemplo, clone se puede reemplazar por =, pero no al revés.

El mensaje en json se parece a esto:

{
"header": [
     {"version":"1.0"},
     {"language":"php"}
   ],
"classes": [
     { "name":"assignment",
       "type":"symmetric",
       "pool":[ "+=","-=","*=","/=",".=","="]
     },
     { "name":"clone",
       "type":"asymmetric",
       "genes": [ {"gene":"clone",
                  {"pool":["="]
                ]
     },
     ...
  ],
"tokens: [ {
     "class":"inmutable",
     "value": "<?php"
   },
   {

     "class":"inmutable",
     "value": "$a"
   },
   {

     "class":"assignment",
     "value": "="
   },
   .... 
 ]
}

Aunque firmemente empeñado en no hacer el componente de python y mantener el alcance del proyecto reducido, recordé que hay un framework de unit testing de python llamado doctests [13] que tiene el código embebido en el mismo archivo fuente, como comentarios. Era lo que se usaba en w3af[14], pero me ha dicho Andrés, el papaito de w3af, que no escala.

Si el mutador mutara el código de testeo estariamos en problemas, ¿no? Hay que inventar algún mecanismo para lidiar con esto. Me imaginé, no probé, que el tokenizador lo consideraría comentario y no habría inconvenientes. Pero un segundo antes, ya había hallado la solución, que por casualidad sirve para lidiar con los falsos positivos y los loops.

La idea es usar una nueva clase "signal", que indique al core si debe mutar o no. Por ejemplo

<?php

se convertiría en:

{
 "class":"signal",
 "value":"<?php",
 "action":"start"
}


o en dos tokens, el normal de "<?php" y el signal, al que le podríamos quitar "value". Me gusta más la segunda opción, así tenemos dos canales, el de datos y el de control.

El componente python debería insertar como primer elemento:

{
 "class":"signal",
 "action":"start"
}


Luego, en el código, habría que insertar comentarios con una etiqueta arbitraria, a gusto de quién implemente. En php será #code_mutator_start|stop.

while... /*#code_mutator_stop*/ ) {
  ...
#code_mutator_start
  ...
}


Esto es feo, pero simple.

Uno puede sentir la tentación de usar tambien "action":"pause", como para que el core tenga un comportamiento distinto según sea "pause" (sigue aplicando la lógica) o "stop" (concatena todo el resto), pero sería optimización prematura.

La precaución que hay que tener es como procesar en el componente el manejo de estas etiquetas, ya que el código del componente debe ser mutable.

Por ejemplo,

if ($value == "#code_mutator_stop" )

provocaría que el core deje de mutar no siendo esa nuestra intención.

Se soluciona asi:

if ($value == "#code_mutator"."_stop" )

Esta técnica para falsos positivos abre la puerta a solucionar los loops infinitos, usando una nueva action:
{
 "class":"signal",
 "action":"restrict",
 "genes":["-=","/="]
}


Esto le avisa al core que no puede usar esos genes en los próximos pools, hasta que venga una nueva restricción, que puede ser vacía. Por ahora, dejemos esta puerta cerrada.

Otra puerta que tampoco quiero abrir es una clase para poder mutar valores enteros.

Por fortuna, justo me puse a leer Domain Specific Languajes[15] de Fowler, lo cual me ayudó a reflexionar mucho acerca de este mensaje que circula desde los componentes hasta el core. No califica de DSL, pero sí aplican muchos conceptos.

En algún momento, había resuelto simplificar la estructura de los token:

"tokens: [ {
     "signal": "start"
   },
   {
     "inmutable": "<?php"
   },
   {
     "inmutable": "$a"
   },
   ....   ]


pero me encontré con un inconveniente. ¿Qué pasa si quiero pasar metadata, como por ejemplo la linea y columna del token en el archivo fuente? Esto es algo indispensable para python:


"tokens: [ {
     "signal": "start"
   },
   {     "inmutable": "<?php"
   },
   {
     "metadata": [{ "row":"1"},{"col":"0"}]
   },
   {
     "inmutable": "$a"
   },
   {
     "metadata": [{ "row":"1"},{"col":"6"}]
   },
   ....   ]
No me gusta, me complica el procesamiento, asi que mejor conservo la estructura original que permite procesar de modo mucho más sencillo elementos adicionales y le agrego un campo "info".

"tokens: [ {
      "class":"signal",
      "action":"start"
   }

   {
     "class":"inmutable",
     "value": "<?php",
     "info": [{ "row":"1"},{"col":"6"}]
   },
   {
     "class":"inmutable",
     "value": "$a",
     "info": [{ "row":"1"},{"col":"6"}] 
   },
   {
     "class":"assignment",
     "value": "=",
     "info": [{ "row":"1"},{"col":"6"}] 
   },
   .... 
 ]

Este ejemplo es una ilusión en php, que sólo provee información de lineas y lo hace mal. Python da más información.


Seguridad

Más por disciplina que por una necesidad real:

Los puntos de ataque son mensajes json mal formados y el resultado de la ejecución.

Resultado de la ejecución: el proceso se agota cuando se hacen todas las mutaciones o no falla alguna, asi que no hay denegación de servicio por ahí.

json: no hay loops, no hay denegación de servicio por ahi. Quizás si hay muchos tokens o tienen valores muy largos haya que tomar alguna precaución.

Lo que si podría ocurrir es que el componente inyecte código malicioso para que sea ejecutado luego por xUnit. Pero esto no afecta al core, no me importa.
Como Tom Lehrer le hizo decir a von Braun: "'Once the rockets are up, who cares where they come down? That's not my department', says Wernher von Braun."[16]

Ahora en serio, el componente podría por si mismo ejecutar el código malicioso. Sólo tendría valor en caso de que este sistema progresara a la arquitectura multinodo, para propagarse a otros nodos.



Alcance de la primera etapa

Me contento con que funcione una sola instancia que entienda php y python. Esto es para respetar el espíritu agile: sólo implemento lo que produce valor tangible. Yo no necesito ahora los componentes para otros lenguajes ni necesito analizar tanto código que justifique múltiples instancias. Si bien me vendría bien ver como funcionan otros tokenizadores, estaría invirtiendo trabajo en algo que quizás nunca desarrolle.


Esta visión aparentemente de corto alcance no se contradice con mirar al horizonte y hacer una apuesta, es por eso que el framework de ejecución tiene su core en erlang:

  • Es más sencillo pasar luego a una versión concurrente y distribuida
  • Me sirve para practicar. Aunque no al proyecto, me da valor a mi.
No es que me haya lanzado a codear con la mente en blanco, tuve casi dos semanas de análisis "colectivo" hasta que pude ponerme frente a una máquina

Como mencioné antes, los componentes han sido mutados, no así el core en erlang y bash, al que sólo apliqué eunit[17] y sshunit2[18].



El código completo está disponible en https://github.com/cpantel/codeMutator, hay un Makefile que corre diversos tests, pero antes hay que instalar unas dependencias, lee REAME.md

Me faltan varias refactorizaciones como poner la definición de las clases (las de los tokens) en modo composición para poder modificarlas sin tener que rehacer los tests. Tambien que los .sh sean más generales.


[1] http://es.wikipedia.org/wiki/Colectivos_de_Buenos_Aires
[2] http://stackoverflow.com/questions/246495/what-mutation-testing-frameworks-exist
[3] http://php.net/manual/en/book.tokenizer.php
[4] http://en.wikipedia.org/wiki/KISS_principle 
[5] http://docs.python.org/2/library/tokenize.html
[6] http://pic.dhe.ibm.com/infocenter/pdthelp/v1r1/index.jsp?topic=%2Fcom.ibm.debugtool.doc_11.1%2Fvrmu1mst109.htm
[7] http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ripper/rdoc/Ripper.html
[8] http://en.wikipedia.org/wiki/Abstract_syntax_tree
[9] http://seguridad-agile.blogspot.com.ar/2012/09/automatizacion-de-test-eci-2012.html
[10] http://www.dc.uba.ar/events/eci/2012/cursos/aguirre
[11]  http://dc.exa.unrc.edu.ar/staff/naguirre/Pagina_personal_de_Nazareno_Aguirre/Principal.html

[12] http://www.json.org/
[13] http://docs.python.org/library/doctest.html
[14] http://w3af.org
[15] http://martinfowler.com/books/dsl.html
[16] http://en.wikipedia.org/wiki/Tom_Lehrer 
[17] http://www.erlang.org/doc/apps/eunit/chapter.html
[18] http://code.google.com/p/shunit2/

jueves, 25 de julio de 2013

Ethical carroñero

Objetivo: memoria


Años de entrenamiento no son en vano. ¿Recordás a Jason Bourne diciendo "I can tell you the license plate numbers of all six cars outside. I can tell you that our waitress is left-handed and the guy sitting up at the counter weighs two hundred fifteen pounds and knows how to handle himself. I know the best place to look for a gun is the cab or the gray truck outside"? Bueno, no es lo que me pasa a mi. Sin embargo, el otro día mientras caminaba pasé al lado de un gabinete maltrecho y me bastó una rápida ojeada para ver que no había sido depredado aún.

Regresé los quince metros que me había llevado evaluar que no podía llevar todo pues mi Ama y Señora me lo prohibe, pero sí la memoria. Una cuadra y media evaluar que no tenía donde probarla, que necesitaba todo y que tendría que desobedecer y volver. El instinto carroñero triunfó sobre la razón y subrepticiamente introduje en el santuario de mi hogar el gabinete más sucio por afuera que jamas nadie halla visto. Por dentro lo normal, hedía a cigarrillo y tenía telarañas, nada especial.

Objetivo: mother, micro, memoria y video


Si alguien tiró todo esto, razoné, no fue un servicio técnico, fué un civil. Estaba lista para funcionar, las únicas irregularidades eran que le faltaba una tapa, estaba deformado por un fuerte pisotón (alguien usó la computadora de escalera) y tenía una regrabadora de dvd desconectada. Como el disco rígido estaba, me imaginé que eso era lo que había fallado.

Me puse ambicioso, quizás funcione y tiene medio giga de ram, es usable. El único problema era que al conectarla, si la fuente estaba en corto me hallaría en problemas.

Arrancó lo más bien, hasta que en el POST[1] tiró los tres pitidos fatales. Así que la memoria o el mother estaban rotos. Cambié de slot e incluso la quité y no hizo diferencia. No me acordé de lo más elemental, limpiar los slots y los contactos,  cuando recordé, ya me había deshecho de los despojos.

La placa de video tenía los capacitores hinchados, se la regalé a un compañero de trabajo que suele resucitarlas.

Objetivo: disco y lectoras


La memoria me la quedo, pensé, algún día hallaré donde probarla. Se la regalé a otro compañero de trabajo. La fuente será backup de algo, al cajón del olvido. El micro, un P4 de 2.66 fue al estante de los micros, al lado del abuelo baldosa Pentium Pro 200. Vamos a por el disco de 80 GB y las lectoras.

Mi fiel Pentium III de 800 del 2002 se ofreció como voluntaria para probar los componentes. El disco arrancó pero se detuvo al inicio de windows. Luego pensé que podía ser de 64 bits y fallara por el cambio de hardware, linux avisa pero windows quizás no. Me dije, no importa, arranquemos de otro lado, un kali linux[2] debería sobrar.

En este momento obtuve el primer fruto intelectual: las computadoras no arrancan cuando se ponen dvds en las lectoras de cd.

Probé con un trinity [3] y todo ok, ahí estaba servida la vida de una persona.


Objetivo: información


La verdad es que no me agrada para nada escarbar en los asuntos personales ajenos, pero este era el escenario ideal: el disco de un persona absolutamente desconocida, con windows, que dista de ser mi fuerte. Era una excelente experiencia de investigación informática forense. Explorar esta máquina me iba a obligar a aprender a usar muchas herramientas y hacer algo que para divertirse es aceptable pero insoportable para trabajar: aprender windows internals.

Ya había cometido un error metodológico. El haber intentado arrancar con el sistema operativo del disco pudo haber destruido información, ya sea por que hubiera un bichito o porque windows restaurara algo para intentar salvarse.

El siguiente paso fue conectar el disco y ver que se podía extraer una imagen para no depender de que el disco fallara y no perder nada en las pruebas.


Tuve una interminable cantidad de dificultades técnicas, como que el adaptador pata/usb no funcionara y tuviera que usar la PIII. De todos modos, dijo la zorra, no tenía espacio libre en mi máquina. Que parted no entendiera ntfs shrink, etc.

Hora de priorizar y planificar.

Los objetivos estratégicos

  • Aprender el proceso completo.
  • Aprender las distintas herramientas necesarias.
  • La diversión.

Los objetivos tácticos y el alcance

  • No perder la imagen original.
  • Obtener credenciales.
  • Recuperar y continuar sesiones activas.
  • Armar un perfil del usuario.

Primer camino, la restauración


Este es el camino más sencillo. Intentar arrancar la imagen del disco dentro de una virtual y confiar en que no hayan bichitos, ni nada que me haga perder nada. El pronóstico es bueno, ya que la máquina fué descartada por fallo de hardware. Es vital que no se pueda conectar a Internet.



  • Extraje una imagen del disco.
  • Desconecté el disco original.
  • Dupliqué y copié la imagen a un disco externo como resguardo.
  • Reduje la partición de windows para que entrara en el disco interno.




Detalles

$ dd if=/dev/sdb of=windows.img

Para montar las particiones dentro de la imagen, que en este caso era una sola, hice esto[4]

$ fdisk -lu windows.img

Disk windows.img: 0 MB, 0 bytes
255 heads, 63 sectors/track, 0 cylinders, total 0 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x4fe54fe5

             Device Boot  Start        End    Blocks   Id  System
windows.img       1   *      63  160810649  80405293+   7  HPFS/NTFS



Hay que obtener el offset que es start * 512 y montar

mount -o loop,offset=32256 windows.img /mnt0

para obtener el espacio ocupado:

df /mnt -h


Reparticionar con gparted[5]

qemu-system-x86_64 -hda windows.img -cdrom gparted-live-xxx.iso  -boot order=d





Una vez reducida la partición, pude copiar parte de la imagen al disco interno

 fdisk -lu windows.img

Disk windows.img: 82.3 GB, 82348277760 bytes
255 heads, 63 sectors/track, 10011 cylinders, total 160836480 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x4fe54fe5

      Device Boot      Start         End      Blocks   Id  System
windows.img1   *          63    46000127    23000032+   7  HPFS/NTFS/exFAT


ahora hacemos End * 512 = 23552065024 Bytes
/ 1024 = 23000064 KBytes
/ 1024 = 22461 MBytes


dd if=externo/windows.img of=interno/windows.img bs=1M count=23000


El problema con este acercamiento es que perdí el espacio libre donde podía haber información, quedará para la autopsia. El archivo de swap ya lo había perdido antes, al probar si la máquina arrancaba.

Tras reiniciar un par de veces mientras el sistema operativo limpiaba el desastre, pude comenzar el análisis.

Segundo error: qemu provee networking por default, me di cuenta cuando el antivirus me dijo que se estaba actualizando.

-net none       use it alone to have zero network devices. If no -net option
                is provided, the default is '-net nic -net user'


Vamos otra vez, esta vez más generosos con la memoria, que por default es 256:

qemu-system-x86_64 -hda windows.img -net none -m 1G

Tras cometer una interminable serie de errores adicionales, llegué a la conclusión que tenía que comenzar otra vez. Para poder resetear la imagen hay que ejecutar otra vez el dd anterior.



Escarbando...


Tiene 2 antivirus y ccleaner, hay búsquedas en el historial de un mother y el nombre de la cuenta me cuentan que tiene alguna idea, no es un end-user.




Nada en la basura, 1G1 de música bajada de internet, links a soft ilegal.

La fecha de modificación de los archivos indica cerca de dos años sin uso.

Hay fotos personales con amigos, mascotas, contexto barrial.

Microsoft Office OneNote tiene muchas capturas de pantalla de... facebook

Quizás ya sabemos el nombre y la cara y varios amigos, el fondo de pantalla provee caras de amigos.

Ya sé donde estuviste de vacaciones: fotos de un complejo turístico con el nombre, no había información de gps en las fotos, pero si de marcas de cámara/celular, que se complementa con el soft de conectividad al teléfono.

Viendo el historial de navegación sé de que clubes sos:

Mercado pago
Mercado libre
hotmail
facebook
identidad racinguista...

Tengo algunas cookies, tipo 2800, no deben servir para nada

Ah, me olvidaba, tengo varias de tus contraseñas


Segundo camino, la autopsia

Consiste en analizar tanto desde linux como desde windows el disco sin escribir nada ni ejecutar nada que esté en disco, sin respetar el sistema de archivos. De hecho lo tomé para ver la información exif[6] de las fotos sin setear carpetas compartidas.

Debería corre un antivirus pero ya ha rendido suficientes frutos la experiencia y le dediqué demasiado tiempo.

Aprendizaje


Como se puede ver, una y otra vez, dejando de lado los errores, hay que hacer concesiones y no respetar a rajatabla el procedimiento forense. Si no tengo 80 GB libres en donde pueda hacer el análisis, tengo que sacrificar algo. Si hubiese tenido mucho apuro, sin tiempo para aprender a usar las herramientas, ni estar transfiriendo backups de un lado a otro, tendría que haber tomado atajos que de salir mal hubiesen provocado pérdidas de información. Además el cambio de objetivos durante el transcurso del proyecto, afectó a los pasos siguientes, cuando sólo me interesaba determinar lo que estaba roto, no tomé las precauciones necesarias para preservar la información.

Para hacerlo en serio, hay que tener en cuenta que se puede tardar mucho. En esa situación, que no haya espacio no es excusa para alterar la imagen original.

Conclusiones


Los elementos arrojados a la basura recuperados, según mercado libre tienen un valor de $460
  • Memoria pc400 512MB $110
  • Lectora cd $20
  • Disco 80GB $170
  • Fuente 430W $90
  • Micro P4 2.6 GH $70

Si alguien quiere comprar, ejem, me avisa...


Lo que sí pudo haber tenido valor es toda la información expuesta. En mi posición de ethical hacker, las copias del disco fueron sobreescritas y borradas. El disco sobreescrito, reformateado y reubicado.

Agradezco profundamente a Miguel Sumer Elías de Informática Legal por el asesoramiento gracias al cual intenté no incurrir en ningún delito.


Referencias


[1] http://en.wikipedia.org/wiki/Power-on_self-test
[2] http://www.kali.org
[3] http://trinityhome.org/

[4] http://www.jefferyfernandez.id.au/2007/06/14/mounting-partitions-that-are-within-a-disk-image/
[5] http://gparted.sourceforge.net/

[6] https://en.wikipedia.org/wiki/Exchangeable_image_file_format

miércoles, 17 de julio de 2013

Vulnerabilidad de ingeniería social en mundo gaturro

Antes que nada, entiendo que el padre, madre, tutor o encargado (gatutor) que tenga hijos o niños a cargo (gaturritos) tales que le hagan lo que voy a contar tiene problemas mucho peores que perder las contraseñas de mundo gaturro.


Mundo Gaturro[1] es un Second Life[2] tercer mundista para niños. Para respetar el buen gusto y no sé si alguna normativa, los gaturritos deben manejar su cuenta por medio de sus gatutores. No me he fijado todas las cosas que hay para configurar y controlar, sólo me interesa la gestión de cambio de contraseñas, que puso a un conocido en posición de víctima.

User Story


El gaturrito quiere cambiar su contraseña, entonces entra al diálogo de cambio de contraseña del gaturrito y pone la dirección del gatutor. Éste recibe un link con un código y al seguirlo, cambia la contraseña del gaturrito.


¿Qué encontré "in the wild"?


El gatutor quiere cambiar su contraseña, entonces entra al diálogo de cambio de contraseña del gatutor y pone la dirección del gatutor. Éste recibe un link con  un código y al seguirlo, cambia la contraseña del gatutor.

Si te desenchufás de la vida a mil que llevás, te sacás la impaciencia y volvés a leer los dos párrafos anteriores con atención y jugás a encuentrar las tres diferencias, vas a ver que hay algo interesante.

Está bien, es razonable que los workflows sean parecidos. Tampoco es posible evitar que cualquiera pueda iniciarlo.



Ahora te voy a mostrar las capturas de pantalla, para que veas como, un gaturrito podría pedir cambio de contraseña muchas veces hasta dejarle las gatubolas por el piso al gatutor y ahí aprovechar y pasarle el link de cambio del gatutor y pedirle que se ponga una contraseña al conocida por el gaturrito.

Attacker Story

Etapa de ablande


El gaturrito inicia el trámite de cambio de su contraseña


 El gatutor recibe un mail con un link y un código


El gatutor ingresa el código y la nueva contraseña del gaturrito.







Ejecución del ataque

El gaturrito inicia el trámite de cambio contraseña del tutor

El gatutor recibe un mail con un link y un código


El gatutor ingresa el código y la nueva contraseña del gatutor.


Si, ya sé, dice "Ingresá tu plin plin plin para padres". Pero, ¿quién, hoy en día, se pone a leer todas esas frasecitas donde, como somos todos gatutores jóvenes modernos las frases y los dibujitos son equivalentes con el otro procedimiento?


Este ataque fue perpetrado de modo involuntario por un gaturrito que se equivocó y seleccionó el procedimiento de cambio de contraseña del gatutor en lugar del propio.

¿Y a quién le importa esto? Que hay un dinero virtual circulando en gatulandia y se paga con dinero real...

Que algún pervertido que logra obtener la dupla (gatuID, mail del gatutor), puede controlar los controles de la cuenta del gaturrito.

Mitigación


La solución que le propuse a mundo gaturro es destacar mucho más que estás cambiando la contraseña tuya, no la del bastardito que te quiere hackear. Lo dije de otro modo, pero el significado era el mismo. El escenario del pervertido del algún modo lo tenía no lo mencioné, pero recién lo descubrí ahora mientras escribo.

Es verdad que no me maté, pero mandé mail a info@gaturro y alguna otra dirección para que me pasaran a donde reportar y no me han dado peloturra, así que comparto esto para la diversión de todos. Consideré enviarlo a full disclosure[3] pero me pareció overkill y además podría atraer la atención de atacantes de verdad. Si tenés contactos en mundo gaturro, avisales por favor.



[1] http://www.mundogaturro.com/
[2] http://secondlife.com is a free 3D virtual world where users can socialize, connect and create using free voice and text chat.
[3] http://lists.grok.org.uk/full-disclosure-charter.html es una lista donde se exponen vulnerabilidades de sistemas operativos, protocoles, aplicaciones y sitios web.

domingo, 14 de julio de 2013

Retrospectiva Agile Open Seguridad 2013


Como siempre propusimos y votamos la agenda

La agenda quedó así:

track 1track 2
sesión 1Arquitectura seguraPentesting
sesión 2Hackers y delito
sesión 3Agilidad y desarrollo seguroEducación de seguridad



JP dió una charla relámpago del Scala Users Group y comentó del proyecto Secure Social for Play[1] A module that provides OAuth, OAuth2 and OpenID authentication for Play Framework application.

Como tuvimos poco tiempo y no respetamos mucho los horarios, la tercera sesión se cayó.

Con respecto al de pentesting fue una lástima que no hubiera ningún pentester de profesión, comentamos la poca experiencia que teníamos algunos de los presentes, tanto de pentesting como de la gestión de sus resultados.

Hackers y delitos fue un extracto de la exposición "La delgada linea entre el hacking y el crimen" a cargo de Miguel Sumer Elías que ya había expuesto con variantes en ekoparty. No estaba muy cómodo pues no conocía el formato, pero yo no ví inconveniente. Lo que más me quedó fue que no seas tarado, si estás haciendo investigación, pentesting o curioseando, o conseguís permiso o lo expresás de modo tal que quede claro que no estás dañando.

Y ahora lo más importante, ¡la comida!: JP trajo sandwiches y masitas, pero nadie pensó en la bebida hasta que habíamos comido la mitad, hubo que mandar emisarios a buscar...

[1] https://github.com/jaliss/securesocial


Apreciación personal

He sobrevivido otra vez al Agile Open Seguridad, ha sido la mejor AOS, la que menos sufrí, me fuí contento. No me quedo con la sensación de "es la última vez que hago esto".


Habiendo aprendido de las dificultades del año pasado, que fué la primera vez que tuve que ocuparme de conseguir realmente el lugar, esta vez fui extremadamente ejecutivo y despiadado, además de no preocuparme por si venía más gente de la que podía entrar en el lugar, vana ilusión.



Muchas gracias a JP de SCV por el apoyo alimenticio y el ofrecimiento de su lugar como plan B, a Juan Pablo Borgna de la eko que me indicó como conseguir el lugar y a Juan Gabardini por el apoyo en el momento. No agradezco  a Alejandro Rusell y Gabriel Gallo por sumarse a la organización ya que eso sería enajenarlos.

Lamento que no ví la manera de integrarlo a Fabián Quinteros que desde Mar del Plata ofreció su ayuda. El conseguir lugar ya fue suficiente esfuerzo, no tuve luego deseos de buscar sponsors. No vi que podía servir para traerlo.

En años anteriores, Agile Open Tour tenía dinero de sponsors que se usaba entre otras cosas para pagar viajes. En esta ocasión, la respuesta de la comunidad agile a la convocatoria fue la que se vió en la lista, sólo el mail de Fabián, no hubo ningún mail privado. Me dió vergüenza preguntar, tanto ese tema como los apoyos de SADIO e IEEE (que Alejandro consiguió por su cuenta), que entiendo que son casi automáticos, desde que agiles.org está en SADIO y tiene vínculos con IEEE.

Según el juego de las tribus, salvo Juan, no hubo concurrrencia de ágiles. Sin embargo, los meetups de Agiles BsAs [1] sí tuvieron concurrencia ágil. ¿O hay baja superposición de pertenencia entre los miembros del meetup y agiles-argentina? ¿O les resultó tan apestosa mi exposición?


Quizás el problema quede expresado en el comentario de uno de los invitados que realmente me encantó, no sé si asistió:

Me dio risa la justificación: asistir sin depender de otros... yo tendría que pedir más autorizaciones para rajarme un sábado a la tarde que un lunes a la mañana!!

o pueden ser otros motivos, sigamos.



[1] http://www.meetup.com/agiles-bsas/

Una reflexión muy personal acerca de agiles.org

Para quien no participa de agiles.org, no tiene sentido seguir leyendo.


Me he hallado ante un dilema. Al convocar ayuda para la organización, lo hice tanto en la lista de agiles[1] que es La Lista de los Agile Open, como en otros ámbitos[2], que nada que ver. De la primera recibí una sola respuesta bien intencionada pero difícil, de Mar del Plata. Del otro lado, tres personas respondieron,


  • una que comenzó a mover hilos en su organización
  • otra que hizo lo mismo en otra organización
  • y una que me contactó con otra que inmediatamente me contestó lo cual llevó a conseguir el lugar.

Las dos personas que se sumaron a la organización, no provienen de ágiles.


Entonces me surgió una pregunta: ¿pongo el agile open bajo la sombrilla de agiles.org o lo mudo a otro lado?

Hablando al finalizar el agile open con Juan, habiéndole comentado superficialmente esta situación, me convenció de que se puede convivir.

Las siguientes, más filosóficas:

¿A nadie le interesa, ni siquiera tratándose de "otras tribus", tema que tanto revuelo había causado pocos días antes?

¿Yo estoy haciendo algo mal, más allá de mi conocida y reconocida falta de marketing?

Si hay interés pero yo soy un zoquete, ¿por qué no ocupó alguien mi lugar? Yo no se lo iba a disputar, nunca quise hacer esto[3].

Si soy un zoquete, ¿importa? Este tipo de actividad es de quien la hace, no de quien la convoca.

Forman parte de agiles.org varias empresas y personas cuya actividad es brindar agile coaching, que se benefician de modo directo o indirecto de que hayan actividades, incluida esta. Yo no me beneficio, ni siquiera son porotos para algo del trabajo ya que poca oportunidad tengo de usar agile allí.

¿Puede haber un problema de comunicación y cuando yo solicito ayuda para conseguir un lugar, hay gente que se mueve pero como no consigue no avisa y yo no percibo su esfuerzo? Me parece que no, todo el mundo está todo el día tweeteando boludeces, ¿dónde está el "@dev4sec probé en XXXX y me dijeron lo lamento YYYY"?

Me siento un poco incómodo, como pasando factura, pero he colaborado activamente para varios eventos que distan del centro de mi interés, como Educación 2012, Rosario y ahora en Educación 2013 y siempre ayudo en algo en cualquier otro evento o circunstancia.

Entiendo que todo el mundo está muy ocupado, excedido de trabajo y toda la pelota. Y lo entiendo muy bien, ya que soy parte de todo el mundo. ¿Llegó la hora de ir a cuidar nuestras quintitas?


Llevo varios años trabajando en relacionar agiles y seguridad, quizás no me puedo quejar si a nadie le interesa, pero que no haya respuesta no resulta muy estimulante para seguir colaborando y participando. Cuando invito a la gente que viene del lado de seguridad a que se sume a Agiles me da la sensación más  de estar "sacrificándola" que de estar llevando seguridad a Agiles.



Nuevas tribus


Desde hace rato, hay una tendencia expansionista, ir a buscar otras tribus. Me da la sensación de que es tratar de suplir la falta de calidad con cantidad, lo nuevo es bueno, dar nuevos aires.



Cuando me hablan de atraer nuevas tribus, la sensación que tengo se ve extremadamente retratada en una frase de Chesterton:
 
New York is a cosmopolitan city; but it is not a city of cosmopolitans

Está sacada de su contexto original, pero es algo que aprendí en la secundaria, no sé en que materia, las herramientas tienen un propósito nominal y uno real.


[1] http://tech.groups.yahoo.com/group/agiles-argentina/message/2149
[2] http://listas.usla.org.ar/pipermail/flisol-caba/2013-May/003205.html
[3] http://tech.groups.yahoo.com/group/agiles-argentina/message/535

martes, 9 de julio de 2013

¿Qué tienen que ver las url acortadas con las campañas de reclutamiento?

Nada, fue como poner "Hard Core XXX Porno" para llegues hasta acá.

No, mentira. Pero cuando termines de leer, espero que entiendas por qué hice ese chiste.

Urls acortadas


Este tipo de url se originan en la necesidad de aprovechar los pocos caracteres que ofrecen twitter o los mensajes SMS. Tambien sirven cuando abandonan la computadora y tienen que pasar por un papel o de una computadora a otra por intermedio de una persona.

Es más fácil equivocarse con una dirección como

    http://dx.com/s/magnetic%2bstripe%2breader.html?sort=Price

que con la url acortada, no?


    http://tinyurl.com/ky5fx7x

Los problemas de usar url acortadas son que
  1. dependés del sistema de acortamiento para que otros lleguen a tu página
  2. no sabés a donde vás hasta haber ido

Para mitigar el primero y el segundo a la vez, si tu sitio tiene su propio url shortener y está bien hecho, solucionás tu problema y el del usuario a la vez.

Sé que existe http://yourls.org/, que dice ser código instalable en php para esa tarea, pero no lo he probado y excede el alcance que me puse para esta entrada.

Para mitigar el segundo, como usuario de la url, en particular en tinyurl.com se puede usar la función de preview

    http://preview.tinyurl.com/ky5fx7x

En bit.ly, o goo.gl, agregar un signo positivo:

  http://bit.ly/Zz2vKv+
  http://bit.ly/12BaCnU+

Para cualquier otro acortador, buscar el site + preview... oh, si llegaste hasta acá, sabés usar Internet.


Como usuario, ya sea por desconfianza o por que el servicio no ofrece preview, se puede usar wget:

$ wget --max-redirect=0 http://tinyurl.com/cn69evr
--2013-07-09 10:14:52--  http://tinyurl.com/cn69evr
Resolving tinyurl.com (tinyurl.com)... 64.62.243.92, 64.62.243.91
Connecting to tinyurl.com (tinyurl.com)|64.62.243.92|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: http://d7e58g6x55ofekapx56gr6ogd7.hop.clickbank.net/ [following]
0 redirections exceeded.


Lo que nos acerca al motivo original de esta entrada.

Spammers


¿Cómo hace un spammer para saber si el destinatario de su mail existe, está activo y lee el mail? Fácil, en su mail incluye un link a su sitio y cuando uno lo navega queda registrado.

En el caso anterior, el spammer tiene la resolución de nombres del dominio hop.clickbank.net. Para cada destinatario crea un link a un host único

d7e58g6x55ofekapx56gr6ogd7

Se puede hacer un programa que procese esto o usando bind poner una regla que direccione todo a la misma ip y colgarse del log.


Otro mecanismo es poner la identificación del destinatario en los parámetros, como por ejemplo este inventado:

   <a href="http://xxx.xxxxxxxx.com/?id=lk23kjdssje34">



y otro es con forms, recién sacado de la carpeta de spam:

<form 
   id="yui_3_7_2_1_1373392008410_7524"
   action="http://xxx.xxxxxxxx.com"
>
   <input
      id="yiv7080379176kzsgxzarbaamuh"
      name="qps"
      value="CLICK HERE"
      type="submit"
   >
</form>

Cuando llega el request al servidor xxx.xxxxxxxx.com, esos ids se pueden usar para mapear a direcciones de mail.

Esto nos lleva a que no hay que hacer click en los mails de spam ni en los mails que dicen que hagas click.

¿Cuál es la relación con la url acortada? Qué ya hiciste click.


En conclusión, el spammer pasa el baldecito y los pescaditos se suben solitos. Ya se parece mucho al motivo original de esta entrada.

Me olvidaba, existe otra más, usar una imagen de 1x1 pixel, pero eso se puede resolver solamente configurando al cliente de mail para que no muestre imágenes, cosa que no es muy práctica y en los clientes de webmail puede no ser posible.


¡Eh, trucho! ¿qué me estás vendiendo? ¡¡¡Esos son todos recursos utilizados para las campañas de marketing!!!

¡Oops! me agarraste. Es verdad.

Campañas de reclutamiento


Acá tenemos un ejemplo "legal" del mismo mecanismo, de usar a la víctima para que no solo confirme su mail sino que haga un trabajito extra, sin ninguna artimaña tecnológica. No es nada nuevo, lo pongo para ilustrar el parecido entre las actividades. El resaltado es mío.




El esfuerzo del pescador tiende a cero. Si alguien lee este mail, se registra en el link provisto (tras verificar que no sea una estafa ilegal, claro) y llena los datos pedidos. Lo único que hay que hacer es obtener una lista de personas que puedan querer aumentar sus posibilidades de mejorar su condición laboral y ponerlos a trabajar.


Conclusión

No pretendo aportar ninguna novedad, esto se sabe desde hace mucho tiempo, sólo quiero recordarlo:

La diferencia entre los negocios como puede ser el marketing o las campañas de reclutamiento y el crimen, como spamming o el intento de extender redes de botnet, es extremadamente difuso. Que sea legal o no, es totalmente secundario. Los objetivos (dinero) y los medios (engaño) son los mismos.

¡Engaño! Yo no intenté engañarte, lee bien el mail.


Sí lo leí y dice que encontramos tu cv publicado en un portal online con lo cual ya estás admitiendo que no respetaste las reglas de ese portal por que yo sé donde he publicado, si es que no lo robaste de otro lado. Ni siquiera sé si lo tenés. De un modo u otro no lo leiste, por que no sabés cuantos años tengo, ni que hice ni que hago, que no soy un junior para que me faltes así el respeto, si lo tenés por que no lo cargás vos y te vas a la &#%#@,  (me salió la Violencia Rivas de adentro).


Las buenas prácticas de navegación e interacción en redes sociales, nos protegen tanto de los criminales como de otras amenazas.