2019/05/19

OWASP Latam Tour 2019


Me perdí el comienzo y el final por logística laboral y familiar, pero pude asistir a tres charlas aparte de dar la mía.

Soy un tanto reacio a estar contando lo que los mismos autores pueden contar, así que sólo cuento lo mínimo y alguna opinión de haberla. 
Muchas gracias a  Andrés, Martín y la nueva organización por confiarme ese rato.

La primera charla fue la de Miguel Summer Elias (http://www.informaticalegal.com.ar/) que suele dar explicaciones claras y amenas y esta vez no fue la excepción. Tuvo la innovación de usar una tela touch, con la cual podía controlar con la mano y el audio la presentación ;-)

Luego la mía, "Forzando brutalmente MD5...", que originalmente eran cuatro de cinco charlas, tratándose de calcular MD5 con CPU, SIMD, multicore, supercomputadora y GPGPU.
La última, de un modo radicalmente distinto y que es la que realmente me interesa, la tengo elaborada, me falta implementar el código y trata de hacer lo mismo con FPGA.
Había presentado CPU y SIMD en H4CK3D 2018 pero ahora se le ha hecho largo en nombre, "Forzando brutalmente MD5 con CPU, SIMD, threads, forks, supercomputadora y GPU". Dos días antes caí en cuenta que debió llamarse "Forzando brutalmente MD5 con computadoras" y la última "Forzando brutalmente MD5 sin computadoras".

Primero hice un breve resumen de hashing, para que sirve, la implementación de MD5, optimizaciones como las que menciono más abajo como "mías", la descripción de cada caso, caminos fallidos y teniendo 40 minutos medio que algunas cosas quedaron muy superficiales, otras se cayeron y alguna me la olvidé.

Lo que me han dado ganas de hacer y lo intentaré, es un análisis cuantitivo en tres dimensiones:

  • pasar de CPU a SIMD que son dos casos
  • optimización de compilador que son dos casos
  • optimizaciones mías, como padding fijo, hardcodeo de constantes y loop unroll

Esto último podría ser considerando las ocho combinaciones o quizas cinco asi:

  • padding fijo
  • padding fijo + constantes
  • padding fijo + loop unroll
  • padding fijo + constantes + loop unroll 

Me quedarian entonces 32 o 16 combinaciones, tedioso pero factible.

Para el año pasado cuando estaba por mostrar en el trabajo la parte de GPGPU,  Andrés me había ofrecido acceso a su minador pero se fué de vacaciones y no llegó a configurarme el acceso, lo cual fué una suerte para mí, pues no mucho después, mientras él monitoreaba remotamente el consumo halló 0 Watts. Fué a fijarse y los aislantes de los cables de alimentación se habían fundido, si hubiera ocurrido mientras yo la usaba... Más suerte para Andrés que no tuvo un incendio.


Luego Leandro Mantovani nos contó como utilizar unos logs de certificados TLS como alerta temprana para detectar sitios vulnerables, muy ingenioso

Finalmente, nuevamente suerte en relación a Andrés, su charla la dió en el slot previo, si no me la hubiese perdido. Fue una muy buen ensayo para... BlackHat! ¡qué capo!



La agenda y los links, ...


https://www.owasp.org/index.php/LatamTour2019#tab=ARGENTINA_-_Buenos_Aires


...la presentación, ...


https://www.owasp.org/images/d/d5/Forzando_Brutalmente_MD5_con_computadoras_-_OWASP_2019_-_Carlos_Pantelides.pdf


...las cifras a medio cocinar, ...


https://www.owasp.org/images/5/53/Forzando_Brutalmente_MD5_con_computadoras_-_Cifras_-_OWASP_2019_-_Carlos_Pantelides.pdf


...las entradas en este blog y ...


https://seguridad-agile.blogspot.com/p/indice.html#md5


...el código.

https://github.com/cpantel/Forzando-Brutalmente-MD5

 

Forzando Brutalmente MD5 - parte 5 - GPGPU


¿Venís de leer la intro, la parte 1, la parte 2, la parte 3 y la parte 4?



El tema


Finalmente, dentro del terreno de usar computadoras para calcular MD5, llegamos si no a lo último en términos tecnológicos a lo más potente.

El origen de esta técnica está en los gráficos. Siempre los gráficos han sido muy demandantes. Desde hace décadas se ha dedicado hardware especializado para convertir una zona de memoria en caracteres o imágenes en una pantalla. A medida que fué creciendo la demanda se detectó que habían ciertas operaciones muy frecuentes de alto consumo que comenzó a tener sentido darle a ese hardware la capacidad de hacerlo y quitarle esa tarea a la CPU.

Esta evolución no es exclusiva de los gráficos, de hecho en las primeras computadoras hogareñas de 8 bits, se usaban chips especializados para sonido y ya desde la primera IBM PC el teclado ha tenido su propia CPU, diminuta y ultra especializada pero CPU.

Paulatinamente estas placas han provisto aceleración para gráficos 2D y 3D, haciéndose más potentes que las CPUs que las usaban. Entonces a alguien se le ocurrió que tal si usamos esas placas para cálculos en lugar de para gráficos?

La situación actual es que existen la GPGPU, General-Purpose computing on Graphics Processing Unit y una interfaz programática que no es un hack como pudo serlo la comienzo.

En la misma linea de la supercomputadora, se usan CPUs sencillas, casi ni califican, optimizadas para cálculo. Y son muchas, centenares o miles.

Como dato de color, estuve intentando conseguir una PS3, anterior a cierto modelo para poder ejecutar linux pero no pude. El interés estaba dado por que esa consola tiene un antecesor de GPGPU, llamado Cell Processor en el cual se pueden ejecutar programas arbitrarios.

Contacté a uno de los que habían desarrollado las librerías y me dijo:

 

I have left IBM quite a few years ago and I can offer no reliable reference on IBM products; however the Cell Processor is long past its end of life.
 
My personal suggestion to you is that your time is vastly better spent learning how to optimize code for NVidia GPUs, rather than for the Cell Processor.
 

 

Cuando le expliqué mejor mi propósito:

Oh, I see, you are doing computer archaeology. Yes, that makes sense. You should be able to find the Cell SDK v3.0 mirrored on the Internet. You'll have some troubles running it on a modern linux, but with some patience you'll be alright.

 

Pero no pude conseguir el hardware y se me fueron las ganas.


Para portar lo que tenía usé CUDA, es parecido a supercomputadora pero se puede meter todo en un mismo programa, es un poco más difícil de explicar mostrando código pero la esencia es que preparás la tabla de rangos a explorar, la copias a la memoria de la placa, llamás a la función que se va a desplegar en los centenares de cores, la función toma el rango sobre el que va a explorar y luego copiás los resultados de la placa a la memoria principal.



cpucpu unrollavx2 + unrollthreads x 4
+ avx2
threads x 32gpu x 64gpu x 4096
velocidad5.79.647.9153.417933.551090.1
rendimiento watt0.861.444.267.194.8823.013.1
rendimiento dolar2.38411.8319.9613.5463.9213.16

 

Acá el rendimiento es aún más difícil de interpretar pues para que funcione la GPU hace falta la CPU, el valor calculado es aislado. Se pueden usar múltiples GPU distribuyendo el costo y consumo de la CPU entre estas.

 



cpucpu unrollavx2
+ unroll
threads
x 4
+ avx2
threads
x 32
gpu
x 64
gpu
x 4096


5.709.6047.90153.40179.0033.551090.1
cpu5.701.001.688.4026.9131.405.89191.25
cpu unroll9.60
1.004.9915.9818.653.49113.55
avx2 + unroll47.90

1.003.203.740.7022.76
threads x 4
+ avx2
153.40


1.001.170.227.11
threads x 32179.00



1.000.196.09
gpu x 6433.55




1.0032.49
gpu x 40961090.1





1.00




Código

  • https://github.com/cpantel/Forzando-Brutalmente-MD5/tree/master/v7_cuda

Seguí con la parte 6 y con la implementación FPGA en nexys4ddr

 

 

 

 

 

 

Forzando Brutalmente MD5 - parte 4 - supercomputadora


¿Venís de leer la intro, la parte 1, la parte 2 y la parte 3?


El tema


Lo que veníamos viendo es como aprovechar mejor una CPU cada vez más compleja y luego varias pero con la ilusión de usar una sola. Cada una de estas CPU es capaz de ejecutar al sistema operativo, de hecho es probable que por momentos lo estén haciendo. Este enfoque generíco produce un inconveniente, que es que las CPU deben ser capaces de comunicarse entre si y con los dispositivos de almacenaminento y entrada/salida, cuando lo que nos interesa es que ejecuten programas que no son parte de la gestión del sistema operativo y comunicarse entre sí.

Existen varios enfoque que consisten en usar muchas CPUs genéricas simples interconectadas. Entonces en un mismo chip se pueden poner muchos cores pues necesitan menos silicio.

 
La que uso es la parallella, que es una mini supercomputadora. Mini en términos de que tiene muy pocas CPUs, por ende, bajo rendimiento. Super en la arquitectura, son CPUs simples con un bus de interconexión que no he usado, no necesito comunicar información entre los cores.

Este chip está pensado para experimentar, la versión siguiente de 64 cores y la siguiente de 1024 aparentemente han "desaparecido", DARPA contrató al diseñador y nada más se ha sabido.




Una dificultad que tuve fue el cambio de endiannes, mis programas originales son para x86 y estos cores son ARM, la tienen invertida.

Mientras estaba haciendo las primeras pruebas, no presté suficiente atención a la disipación de calor y pasé un momentó de pánico cuando se freezó, mmh, que raro decir que se freezó cuando en realidad se sobrecalentó y se detuvo.

Con respecto a la dificultad que esperaba en esta etapa respecto a las demás, resultó sorpresivamente sencillo que funcionara.

Para hacer funcionar esto hacen falta dos programas, uno para la CPU y otro para enviar a cada core. Este último programa se fija cual es su core y usa ese número como índice para decidir sobre que parte del set de datos trabajar.

 

El programa de la CPU principal es:


#include <host_bsp.h>
#include <stdio.h>

int main(int argc, char **argv) {
    // Initialize the BSP system
    bsp_init("ecore_find.elf", argc, argv);

    // Initialize the Epiphany system and load the binary
    bsp_begin(16);

    // Run the program on the Epiphany cores
    ebsp_spmd();

    // Finalize
    bsp_end();

    return 0;
}


La esencia del programa en los cores es:


typedef struct {
     uint64_t hashcount;
     char init;
     char stop;
} Data;


int main(int argc, char * argv[]) {

   bsp_begin();

   int n = bsp_nprocs();
   int p = bsp_pid();

    Data data[] = {
      {0,';','>'},
      {1,'?','B'},
      {2,'C','F'},
      ....
      {14,'s','v'},
      {15,'w','z'}
    };

   uint64_t hashcount = data[p].hashcount;
   char init          = data[p].init;
   char stop          = data[p].stop;

   for (char0 = init; char0 <= stop ; ++char0) {...

En data están los rangos a procesar, con bsp_pid() se obtiene el core actual y se usa como índice en data y el for usa los valores apropiados.

 

 

El clock es de 1Ghz, así que tiene un consumo muy bajo, la placa entera consume 5W de los cuales 2 o 3 son del chip multicore. 

 


cpucpu unrollavx2avx2 + unrollthreads x4threads x 4
+ avx2
threads x 32cores x 16
velocidad5.79.628.447.932.5153.417915.2
rendimiento watt0.861.444.267.194.8823.013.16.84
rendimiento dolar2.38411.8319.9613.5463.9213.1623.75





cpucpu unrollavx2avx2 + unrollthreads x4threads x 4
+ avx2
threads x 32cores x 16


5.709.6028.4047.9032.50153.40179.0015.2
cpu5.701.001.684.988.405.7026.9131.402.67
cpu unroll9.60
1.002.964.993.3915.9818.651.58
avx228.40

1.001.691.145.406.300.54
avx2 + unroll47.90


1.000.683.203.740.32
threads x432.50



1.004.725.510.47
threads x 4 + avx2153.40




1.001.170.10
threads x 32179.00





1.000.08
cores x 1615.2






1.00



Código

  • https://github.com/cpantel/Forzando-Brutalmente-MD5/tree/master/v6_ebsp
Seguí con la parte 5