2023/01/18

La asimetría entre una campaña de EH y un control de seguridad.

En Nerdearla 2022 tuve el privilegio de dar dos charlas, una mía personal que más que un taller era una charla larga, una versión extendida de lo presentado en Flisol 2022 relativa a open hardware, cores y software y otra, en representación de mi trabajo, ésta si una charla de verdad, nacida de una combinación de necesidades y oportunidades, de la aplicación de ML a un problema de seguridad.


El proyecto expuesto trata de cómo hallar información sensible en diversos almacenamientos, en particular credenciales en texto plano en archivos de texto plano en sistemas de archivos utilizando técnicas de ML. Claramente todas estas ideas pueden extenderse otra información sensible en más tipo de archivos (pdf, documentos con formato, planillas) en diversos sistemas (repositorios, páginas web, comprimidos), pero no de modo sencillo ni automático.

 

Sin embargo, el aspecto que quiero destacar en esta entrada no es tanto el diseño  técnico y la arquitectura del sistema, que vendrían a incluir aspectos como lidiar con diversos encodings, realizar la exploración en determinados horarios para no impactar en la disponibilidad de los sistemas a examinar, actualizar el modelo y las reglas de inclusión y exclusión de búsqueda tanto de archivos como de patrones de palabras clave de modo relativamente dinámico para poder aplicarlos durante la ejecución y no tener que esperar a que finalice, considerá que quizás estás recorriendo millones de archivos a lo largo de semanas. De este tema tengo muchísimo elaborado pero poco testeado y además no he revisado soluciones existentes para comparar.


Lo que me interesa y tema de esta entrada nace de esta frase:

 

"(A) Vinieron unos pentesters y revisaron en cierto lugar y (B) encontraron un archivo con una clave que aunque no era la actual  mostraba el patrón de generación (C) lo cual permitió acceder a un sistema donde se encontraron otras credenciales.(D) Tenemos que hacer un control para prevenir esta situación".


Ok, nos gustaría mucho que no ocurra que hayan credenciales en texto plano en primer lugar, para ello existen técnicas de autenticación para evitar que hayan claves en los scripts y concientización para que no hayan claves fuera de los almacenes seguros tipo keepass, pero esto se trata justamente de detectar cuando alguien no las respeta.


Aunque a primera vista no lo parezca, el salto que hay desde (A) unos pentesters... a (D) hacer un control... es abismal y más si pasamos por (B) y (C), veamos el detalle y el contraste:


  • El éxito de una campaña de pentesting se puede alcancar ante el primer hallazgo importante o cuando se alcanza al tiempo límite de ejecución asignado.
  • Ésta campaña, aunque pueda tener mucha asistencia de automatización, es esencialmente manual e interactiva, no hay foco en optimizar aspectos como que un humano no tenga que revisar más de 5.000 líneas, por decir un número para mí razonable. Esto significa que:
    • si el humano se tiene que pasar una tarde mirando una lista de 100.000 líneas candidatas, lo va a hacer.
  • La búsqueda no es exhaustiva, se pueden buscar archivos con nombres clave tipo "claves.txt", con hallar uno alcanza.
  • La frecuencia puede ser tal que sea una o dos veces por año, quizás cada dos años.


 

Contrastemos con un control:

  • La ejecución del control se completa cuando recorre todo el conjunto de activos a revisar y emite su reporte, el cual puede ser contínuo, no hace falta que sea al final.
  • El éxito se alcanza cuando recorre todo y halla todo lo que podría hallar.
  • Debe ser esencialmente automático, el humano sólo debería intervenir para una decisión final acerca de los positivos y realimentar la lógica.
    • En mi experiencia, completamente personal, no debería examinar más de 10.000 líneas. Y pensá que esto hay que repetirlo periódicamente, es esencial que sean pocas líneas.
  • Debe ser permanente, no bien termina de ejecutarse debe comenzar otra vez.
  • Considerando (B) clave pista y (C) que conduce a otro lado, esto es imposible en un control, se hace indispensable la intervención humana.

Esta intervención puede pasar a formar parte del control, pero hay que tener en cuenta que pueden haber mucho "candidatos", una cosa es mirar rápido y ver que "let password = "3234234" amerita contactar al dueño del sistema y otra es que cuando el dueño te contesta "esa clave no se usa más" confiar y seguir escarbando.

Otra es, si el hit fué "let password = $texto", tendrías que ir a ver dónde y cómo se definió $texto, pudo haber sido

let texto = "3234234"

que es un nivel de indirección que nuestro análisis difícilmente pueda interpretar, o peor aún:

let password = exec("proceso.exe", "id_sistema")

donde proceso.exe puede ni siquiera estar presente en el sistema que estamos examinando. No pongo las manos en el fuego pero consideraría esta una técnica válida, esa línea la encontraste en un repositorio y proceso.exe sólo existe en el sistema productivo donde se ejecutará el código.

Existen herramientas de análisis estático de código que son capaces de seguirle el rastro a una cadena de asignación de valores dentro del flujo de un programa, sólo sería cuestión de activarla cuando se detecta que es código fuente, pero bueno, es una complejidad adicional.

En síntesis, la idea está en concordancia con el concepto de la asimetría que hay entre atacante y el defensor, el EH respeta la visión del atacante y el Control la del defensor:

  • El atacante tiene toda la ventaja del tiempo, es lo único que hace.
  • El atacante tiene toda la ventaja de concentrarse en un único conocimiento, el de tal ataque en particular, mientras el defensor debe abarcar de modo obviamente superficial todo el conocimiento de todo lo que defiende.
  • Al atacante le alcanza con un éxito y en última instancia no importa mucho cómo lo consigue.

Entonces la idea es, no sencillo en general modelar un control a partir del resultado de un reporte de EH y en particular en el caso de la frase, probablemente imposible.











2022/10/25

Secure Boot con ESP32c3

Primero hay que leer atentamente la documentación y cuantos más clicks hagas en los links que tiene más vas a comprender todo, elegí para la v4.4. Puse ESP32c3 en el título pero probablemente aplica a Secure Boot V2, que incluye al menos ESP32s2.


El primer programa que se ejecuta es el que está en la ROM, también llamado FSB (First Stage Bootloader), que entre otras cosas se fija si el eFuse de secure boot está activado, ponele que sí. Luego busca el SSB (Second Stage Bootloader) y si tiene hasta 3 firmas agregadas. Utiliza las hasta 3 public keys que pueden haber en los eFuses y si alguna firma está ok, ejecuta el SSB.

 

Arranque normal
Arranque normal


Arranque seguro
Arranque seguro

 

Este hace lo mismo para cada imagen que haya en el resto de la memoria hasta encontrar una válida. Luego, de la aplicación, copia a memoria los datos y programa correspondientes y mapea a la memoria los datos y programas que vayan a quedar en la EEPROM. Por último ejecuta la aplicación.

Para poder llegar a esta situación, tenemos que hacer algunas cositas:

 

Generar las claves

 

En la carpeta de tu elección, pero luego el pem va en cada proyecto.

$ openssl genrsa -out secure_boot_signing_key.pem 3072

No te olvides de agregar un *.pem a tu .gitignore, si llegás a versionar esto, pensá que podrías revocar el certificado en el chip pero sólo tenés lugar para tres.

 

Toolchain


Bajar todo el entorno de esp-idf según las instrucciones del paso 4. Si ya lo tenías de antes, es conveniente que lo actualices.

$ cd ~/esp/esp-idf

$ git pull --recurse-modules

$ ./install.sh esp32,esp32c3,esp32s2

 

Tu proyecto


Para este ejemplo usé CIBS/esp32c3-secure-boot, que es lo mismo que esp32c3-pinout. De un modo u otro, activar el entorno

$ . export.sh

Ir a tu proyecto, si lo tenías ya construido, hacelo papilla con

$ rm -rf build

Para empezar de cero:

$ idf.py set-target esp32c3
$ idf.py menuconfig

# Security features
[*] Enable hardware Secure Boot in bootloader (READ DOCS FIRST)
   Select secure boot version (Enable Secure Boot version 2)  --->
   (X) Enable Secure Boot version 2
[*] Sign binaries during build (NEW)
   (secure_boot_signing_key.pem) Secure boot private signing key (NEW)

# Partition Table  --->
(0xa000) Offset of partition table

 

Ese 0xa000 en lugar del 0x8000 original podría ser opcional pero en mis pruebas dijo:


Bootloader binary size 0x8c30 bytes is too large for partition table offset 0x8000. Bootloader binary can be maximum 0x8000 (32768) bytes unless the partition table offset is increased in the Partition Table section of the project configuration menu.

La tentación es poner 0x8d00, pero tras varias iteraciones, mejor 0xa000, más que por ahí dice que debe ser múltipo de 0x1000.


$ idf.py build

En algún punto va a tirar dos mensajes, uno que gentilmente explica como agregarle firmas al bootloader:

To sign the bootloader with additional private keys.
    /home/iot/.espressif/python_env/idf4.4_py3.10_env/bin/python /home/iot/esp/esp-idf/components/esptool_py/esptool/espsecure.py sign_data -k secure_boot_signing_key2.pem -v 2 --append_signatures -o signed_bootloader.bin build/bootloader/bootloader.bin 

Y otro de cómo grabarlo, hay que hacerlo a mano, sólo cuando hay nuevas keys.


/home/iot/.espressif/python_env/idf4.4_py3.10_env/bin/python  /home/iot/esp/esp-idf/components/esptool_py/esptool/esptool.py --chip esp32c3 --port=(PORT) --baud=(BAUD) --before=default_reset --after=no_reset --no-stub write_flash --flash_mode dio --flash_freq 80m --flash_size 2MB 0x0 /home/iot/ceiot_base/CIBS/esp32c3-secure-boot/build/bootloader/bootloader.bin


¿Qué ponemos en PORT y BAUD?

PORT = /dev/ttyUSB0

BAUD = 115200


Ambos salen de haber visto alguna vez la salida de idf.py monitor:

--- idf_monitor on /dev/ttyUSB0 115200 ---


Luego

$ idf.py flash

$ idf.py monitor

 

Resultados


La primera vez, tal como dice la documentación, sirve para activar, hace falta un reset

Último arranque inseguro

Desde la próxima vez que arranque:


Primer arranque seguro

Notá tanto la diferencia del FSB (en negro) como la del SSB (en verde).

Este proceso en dibujitos:


Setup bootloader
Setup bootloader



Setup App
Setup App



A mi no me salió de una tán fácil, no encontraba la tabla de particiones, no había nada en ésta, horas...


Una de las tantas fallas...
Una de las tantas fallas...