Binario – S3lab http://s3lab.deusto.es S3lab Security Blog Wed, 06 May 2020 12:51:35 +0000 es hourly 1 https://wordpress.org/?v=5.1.5 Crea un binario ilegible con estas técnicas http://s3lab.deusto.es/binario-ilegible-tecnicas/ Fri, 23 Jun 2017 09:55:39 +0000 http://s3lab.deusto.es/?p=9190 Ya bien sea por fines maliciosos, como el caso de los autores de malware, por fines corporativos, o por otras razones, las técnicas de ofuscación son utilizadas para proteger un programa haciendo que una vez compilado, el análisis estático del

The post Crea un binario ilegible con estas técnicas appeared first on S3lab.

]]>
Ya bien sea por fines maliciosos, como el caso de los autores de malware, por fines corporativos, o por otras razones, las técnicas de ofuscación son utilizadas para proteger un programa haciendo que una vez compilado, el análisis estático del binario sea más costoso. La ofuscación por tanto, consiste en transformar un programa de forma que sea más difícil de entender, pero que al mismo tiempo mantenga la semántica original.

Estas técnicas de ofuscación pueden aplicarse a nivel de datos, de instrucciones o de flujo de control del programa, pasamos a explicar algunas de ellas. Estas son algunas de las técnicas de ofuscación de datos:

  • Cegar las constantes (constant blinding): en vez de tener un valor en claro, esta técnica busca sustituir los valores de las constantes, generalmente mediante una XOR con un valor aleatorio, por datos aparentemente sin sentido.
  • Cambio del encoding de las variables: de forma similar al constant blinding, cambiando el encoding de las variables se busca ocultar el valor original de la variable, por ejemplo un string, por su valor equivalente en otro encoding. Ejemplos típicos son la codificación en Base64 o los cifrados sencillos mediante XOR, ROT13 etc.
  • Agregación de datos: consiste en agrupar variables en estructuras más complejas, por ejemplo juntando enteros en un mismo struct.
  • Separación de datos: en contraposición a la agregación de datos, la separación de datos consiste en dividir los datos en unidades más pequeñas, por ejemplo transformando un int de 4 bytes en dos shorts de 2 bytes.

Para ofuscar el flujo de control del programa existen diversas técnicas:

  • Inserción de código muerto (dead code insertion): una de las fases de optimización que hacen los compiladores modernos por defecto es la eliminación de código que no afecta al programa  (opción -fdce en GCC); la inserción de código muerto es todo lo contrario, es decir, inserta código en el programa que es redundante. Los ejemplos más sencillos son la inserción de nops, guardar el valor de una variable, hacer operaciones matemáticas con ella para luego restaurar el valor original etc.
  • Uso de predicados opacos: un predicado es una expresión lógica que se evalúa a true o false, y que generalmente se usa para dirigir el flujo de un programa. Los predicados opacos tienen como objetivo hacer que esa decisión de si algo se evalúa a true o false no sea posible saberse en tiempo de compilación o de forma estática, aunque siempre vaya a tener el mismo resultado. De esta forma se generan más ramas en el control flow graph (CFG) y se molesta en la fase de reversing. Tratar de detectar predicados opacos y desofuscarlos es una línea de investigación abierta. Se pueden ver ejemplos en estas respuestas de Reverse Engineering Stack Exchange.
  • Aplanado del flujo de control (control flow flattening): esta técnica consiste en modificar y reordenar los bloques básicos de un programa  (basic block, BB) de forma que, en vez de tener en el CFG una estructura de decisión if-else típica en la que se sigue la ejecución a un BB o se salta a otro BB dependiendo del valor de los flags, se pasa a una estructura aplanada, en la que un BB llamado dispatcher decide a qué BB saltar en base al valor de una variable artificial. Cada BB de las ramas de decisión tiene el dispatcher como predecesor y sucesor, dificultando así averiguar la lógica del programa detrás del CFG aplanado.
  • Desenroscado de bucles (loop unrolling): en las fases de optimización de la compilación de un programa se utiliza el loop unrolling para evitar añadir instrucciones de salto condicional y variables adicionales para emular bucles. El loop unrolling, además de ser computacionalmente menos costoso (se activa con la opción -O1 en adelante en GCC) genera bloques de instrucciones muy parecidos entre ellos, lo que aumenta la confusión en el análisis estático del código.

Finalmente a nivel de instrucción se busca sustituir la instrucción original por otra serie de instrucciones equivalentes más complicadas, generalmente mediante el uso de operaciones matemáticas. Algunas de estas técnicas pueden aplicarse con Obfuscator-LLVM, una suit de compilación sobre LLVM que en vez de aplicar las optimizaciones típicas del middle-end de LLVM, permite ofuscar el programa. 

Por otro lado, las técnicas de ofuscación también pueden servir para dar seguridad. Por ejemplo, PointGuard es una antigua extensión de GCC para proteger punteros. PointGuard cifra los valores de los punteros cuando estos están en memoria aplicando una XOR con una clave generada aleatoriamente cuando el proceso del programa arranca. Cuando un puntero se va a dereferenciar se descifra el valor del puntero, de esta forma, si un atacante consigue sobrescribir el valor del puntero, cuando este se dereferencie y por PointGuard se descifre, el atacante estará accediendo a una dirección de memoria aleatoria, y muy posiblemente si el acceso no es válido hará que el programa falle, frustrando así la explotación del programa.

 

The post Crea un binario ilegible con estas técnicas appeared first on S3lab.

]]>
Hardening de binarios (II) – PIE http://s3lab.deusto.es/hardening-binarios-2/ Tue, 28 Jun 2016 09:55:48 +0000 http://s3lab.deusto.es/?p=8304 Siguiendo con las opciones clásicas de compilación de GCC para tratar de tener binarios más robustos, en esta entrega vamos a hablar de las opciones -fpie y -fPIE, que permiten compilar ejecutables como “Position Independent Executables” y permiten que sus

The post Hardening de binarios (II) – PIE appeared first on S3lab.

]]>
apple-pieSiguiendo con las opciones clásicas de compilación de GCC para tratar de tener binarios más robustos, en esta entrega vamos a hablar de las opciones -fpie y -fPIE, que permiten compilar ejecutables como “Position Independent Executables” y permiten que sus secciones se carguen en posiciones aleatorias.

PaX Team presentó en 2001 ASLR (Address Space Layout Randomization), un parche para introducir aleatoriedad en las direcciones usadas por un programa. ASLR trata de evitar que las direcciones de memoria sean conocidas y así prevenir ataques que dependen del conocimiento de estas direcciones (tipo return2libc y otros). Hoy en día, Windows, Linux, Mac OS X, Android e iOs implementan alguna variante de ASLR.

ASLR se configura mediante el parámetro /proc/sys/kernel/randomize_va_space en Linux. Un valor 0 deshabilita ASLR, tendremos este valor cuando nuestra arquitectura no soporte la aleatorización o cuando nuestro kernel haya booteado con la opción norandmaps. Un 1 habilita la aleatorización de las bibliotecas compartidas (shared libraries), las direcciones base de mmap y la pila. Finalmente, un 2 tiene las opciones de 1 y añade la aleatorización del heap. En los sistemas actuales tendremos la opción 2, sin embargo, antiguamente (en tiempos pre-mmap) se utilizaban las llamadas del sistema brk y sbrk para reservar y liberar memoria, ASLR es posterior a esto. Por tanto, si CONFIG_COMPAT_BRK está activado por razones de compatibilidad hacia atrás, por ejemplo en binarios viejos que usen libc5 (no confundir con glibc), tendremos únicamente una aleatorización de tipo 1.

Por ejemplo, comprobamos la posición de libc en 5 procesos de /proc/X/maps con ASLR desactivado (32 bits):

start-end  perm  offset  major:minor  inode  image
f7dfe000-f7fa6000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so

y podemos ver que la dirección es siempre la misma; mientras que con ASLR activado:

start-end  perm  offset  major:minor  inode  image
f7508000-f76b0000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f751d000-f76c5000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7533000-f76db000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f75eb000-f7793000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so
f7566000-f770e000   r-xp   00000000   08:05   262413   /lib/i386-linux-gnu/libc-2.19.so

Tenemos un offset que siempre cambia.

Una vez que sepamos si nuestro sistema soporta ASLR haciendo $ cat /proc/sys/kernel/randomize_va_space podremos utilizar ASLR en nuestros binarios si están compilados con las opciones -fpie y -fPIE.

Hay que subrayar que ASLR es una defensa estadística, y por tanto limitada. El rango de entropía de ASLR está limitado por la memoria virtual disponible, y se ha demostrado que los sistemas de 32 bits son susceptibles a ataques de de-aleatorización. Por otro lado ASLR puede superarse con info leaks, como se muestra en un famoso artículo de Phrack.

¿Es esto suficiente? Lo descubriremos en los siguientes posts.

The post Hardening de binarios (II) – PIE appeared first on S3lab.

]]>
Hardening de binarios (I) – La pila http://s3lab.deusto.es/hardening-binarios-1/ Tue, 03 May 2016 10:15:08 +0000 http://s3lab.deusto.es/?p=8113 Dentro de las múltiples opciones de compilación que nos facilita GCC, algunas están hechas para hacer que nuestros binarios sean más robustos contra técnicas de corrupción de memoria. Las técnicas de protección de la pila tratan de evitar que se sobreescriban

The post Hardening de binarios (I) – La pila appeared first on S3lab.

]]>
Dentro de las múltiples opciones de compilación que nos facilita GCC, algunas están hechas para hacer que nuestros binarios sean más robustos contra técnicas de corrupción de memoria. Las técnicas de protección de la pila tratan de evitar que se sobreescriban bloques contiguos de memoria, causados por un buffer overflow, y que pueden contener información crítica de control del programa, como direcciones de memoria, punteros a función y el frame pointer. Entre las soluciones disponibles en los compiladores tenemos a StackGuard, Stack Shield, ProPolice (Stack Smashing Protector, SSP) y -fstack-protector.

StackGuard se presentó en 1998 en Usenix Security como un parche para GCC,  se basa en la colocación de “canary words” (haciendo alusión a los canarios que utilizaban los mineros para saber si el aire de la mina era venenoso) pegadas a la dirección de retorno de la pila. Por aquella época los ataques de buffer-overflow más comunes utilizaban stack smashing, es decir, causar un overflow de un buffer, para cambiar la dirección de retorno de una función a una zona de memoria controlada por el atacante. StackGuard se basaba en que si se protegía la dirección de retorno de las funciones, entonces el atacante no podría invocar su código; para esto se utilizaban canary words. Antes de pasar a ejecutar la instrucción de retorno de una función se comprobaba que la integridad del canary se mantenía, sino el programa se abortaba.

pilaStrings

Stack Shield por otro lado, trataba de copiar las direcciones de retorno de la pila a una zona que no pudiera sobreescribirse por un buffer-overflow, el segmento de datos, y después comparaba el valor “seguro” contra el valor actual; si eran diferentes el programa terminaba. En uno de los famosos artículos de la revista Phrack, se muestra que tanto StackGuard como Stack Shield pueden circunvalarse.

Tras StackGuard y Stack Shield vino ProPolice desarrollado por IBM, que en vez de comprobar los canaries de las instrucciones de retorno monitorizaba los cambios de la pila. ProPolice reordena las variables, argumentos, direcciones de retorno y frame pointers para proveer un modelo de pila “seguro”.

Este modelo resultó en el flag de compilación -fstack-protector que protege de buffer-overflows a funciones que llaman a alloca y funciones con buffers de más de 8 bytes (4 en algunas distribuciones Linux), y posteriormente en -fstack-protector-all que protege todas las funciones.

Los compiladores modernos utilizan una de estas opciones por defecto, y el ahora clásico “*** stack smashing detected ***: ./a.out terminated Segmentation fault”  muestra que el SSP de ProPolice está funcionando.

¿Es esto suficiente? Lo descubriremos en los siguientes posts.

The post Hardening de binarios (I) – La pila appeared first on S3lab.

]]>
Años binarios capicúa, esos grandes olvidados http://s3lab.deusto.es/binarios-capicua/ Tue, 16 Dec 2014 10:55:55 +0000 http://s3lab.deusto.es/?p=2971 Me parece que se me había pasado comentaros pero… 2015 es un año binario capicúa. Si os  preguntáis a que me refiero exactamente, muy sencillo, si pasamos el año de decimal a binario nos encontramos que dicho número es capicúa

The post Años binarios capicúa, esos grandes olvidados appeared first on S3lab.

]]>
Binary TimeMe parece que se me había pasado comentaros pero…

2015 es un año binario capicúa. Si os  preguntáis a que me refiero exactamente, muy sencillo, si pasamos el año de decimal a binario nos encontramos que dicho número es capicúa (11111011111). Aunque seguramente no resulte un gran hito en vuestra vida, resulta un hecho bastante interesante, que tras percatarme de ello decidí analizar un poco más.

La última vez que se dio este caso fue en 1967 y no volverá a producirse hasta 2047. Si nos centramos en calcular cuantas veces podemos celebrar el nuevo año con unos y ceros, veremos que ocurre una media de 15 veces cada 1.000 años, o lo que es lo mismo, sucede en el 1,5% de los años. Si comparamos este hecho con la posibilidad de ver el cometa Halley desde la tierra, los resultados obtenidos son bastante similares, ya que este hecho tiene lugar una media de 13 veces cada 1.000 años.

Si queréis comprobar algún rango de años concreto, simplemente tendréis que utilizar el siguiente script en Python (7 líneas escritas en menos de 1 minuto). Nos creará un archivo con los años binarios capicúa de ese rango (aparecerá tanto el valor en binario como en decimal). Cada comprobación se irá almacenando en ese mismo archivo, de forma que si queremos examinar varios rangos no perderemos las comprobaciones previas.

import csv
csv_out = open('BinaryPalindromeYears.csv','ab')
out_writer = csv.writer(csv_out)
for i in range(2016,2116):
	if(bin(i)[2:]==bin(i)[2:][::-1]):
		out_writer.writerow([i,bin(i)[2:]])
csv_out.close()

En los próximos 100 años tan solo pasará 2 veces más. Asique ya sabéis, si queréis celebrar el año con un buen,

“¡01000110011001010110110001101001011110100010000000110010001100000011000100110101!”

Aprovechad que no todos los años son binarios capicúa.

El que avisa no es traidor.

The post Años binarios capicúa, esos grandes olvidados appeared first on S3lab.

]]>