1 puntos por GN⁺ 2024-04-02 | 1 comentarios | Compartir por WhatsApp
  • xzbot es un repositorio para explorar el backdoor de xz (CVE-2024-3094), que incluye un honeypot, un parche de clave pública ED448, el formato del payload del backdoor y una demo de ejecución remota de código
  • El honeypot aplica un parche simple a OpenSSH para registrar en los logs de sshd los intentos de conexión entrantes con un valor N de clave pública que coincide con el formato del backdoor
  • El parche ED448 reemplaza la clave pública hardcodeada que el backdoor usa para verificar firmas y descifrar payloads por una clave generada por el usuario, lo que permite activar el backdoor
  • El payload del backdoor se coloca en el valor N de la clave de firma de CA del certificado SSH; crea el tipo de solicitud con a * b + c, y el Type 2 ejecuta un comando terminado en null mediante system()
  • La CLI de demo muestra el flujo para conectarse a un servidor SSH vulnerable y ejecutar un comando; una explotación exitosa no genera logs de nivel INFO o superior

Alcance y componentes de xzbot

  • xzbot es un proyecto para explorar CVE-2024-3094, el backdoor de xz
  • Incluye cuatro elementos
    • honeypot: servidor vulnerable falso para detectar intentos de exploit
    • ed448 patch: parchea liblzma.so para usar una clave pública ED448 propia
    • backdoor format: documentación del formato del payload del backdoor
    • backdoor demo: CLI que activa RCE bajo el supuesto de que se conoce la clave privada ED448

Honeypot: detección de intentos con un parche de OpenSSH

  • openssh.patch es un parche simple que se aplica a OpenSSH para registrar intentos de conexión entrantes con un valor N de clave pública que coincide con el formato del backdoor
  • El flujo consiste en clonar openssh-portable, aplicar el parche y ejecutar autoreconf, configure y make
  • Los intentos de conexión aparecen en los logs de sshd como xzbot: magic 1 [preauth] y como una secuencia de bytes del payload

Parche de clave pública ED448

  • El backdoor usa una clave pública ED448 hardcodeada para verificar firmas y descifrar payloads
  • Si se reemplaza esa clave pública por una clave que el usuario posee, se puede activar el backdoor
  • El repositorio presenta tanto la clave pública ED448 del atacante como un valor de clave pública alternativo generado con seed=0
  • El paso inicial es preparar el objeto compartido liblzma.so.5.6.1 que contiene el backdoor
    • Se menciona como fuente de ejemplo el snapshot de Debian de xz-utils 5.6.1-1
    • Tras instalar pwntools, al ejecutar patch.py liblzma.so.5.6.1 se genera liblzma.so.5.6.1.patch
    • Luego se ejecuta sshd usando el objeto compartido modificado liblzma.so.5.6.1.patch
  • En assets hay ejemplos

Formato del payload del backdoor

  • El backdoor puede activarse al conectarse con un certificado SSH colocando el payload dentro del valor N de la clave de firma de CA
  • Este payload debe estar cifrado y firmado con la clave ED448 del atacante
  • La estructura externa está compuesta por los siguientes campos
    • a: 32 bits
    • b: 32 bits
    • c: 64 bits
    • ciphertext: 240 bytes
  • El tipo de solicitud se deriva como a * b + c
    • Si el valor es mayor que 3, el backdoor omite el procesamiento
    • Type 1: uso desconocido, espera 0 bytes
    • Type 2: ejecuta un payload terminado en null mediante system()
    • Type 3: uso desconocido, espera 48 bytes de datos de firma
  • ciphertext se cifra con chacha20, usando los primeros 32 bytes de la clave pública ED448 como clave simétrica
    • Por eso, los intentos de exploit pueden descifrarse con la clave de 32 bytes indicada
  • Dentro del ciphertext descifrado hay una firma de 114 bytes, campos de 1 bit x e y, longitud, cadena de comando, etc.
    • Si se configura x o y, se toma una ruta de código ligeramente distinta
  • La firma es una firma ED448 según RFC-8032
    • La entrada incluye un valor magic de 32 bits, un campo de 5 bytes previo al comando, opcionalmente los bytes length del comando y los primeros 32 bytes del hash SHA-256 de la hostkey del servidor

CLI de demo del exploit

  • La CLI se instala con Go
    • go install github.com/amlweems/xzbot@latest
  • xzbot -h muestra tres opciones principales
    • -addr: dirección del servidor SSH, valor predeterminado 127.0.0.1:2222
    • -seed: seed ED448 que debe coincidir con la clave del backdoor de xz, valor predeterminado 0
    • -cmd: comando que se ejecutará con system(), valor predeterminado id > /tmp/.xz
  • El ejemplo se conecta al servidor SSH vulnerable en 127.0.0.1:2222 y ejecuta el comando id > /tmp/.xz
  • Si se configura un watchpoint en el punto de llamada a system() en el servidor vulnerable, se puede ver cómo el proceso sshd ejecuta id > /tmp/.xz
  • Se presenta un ejemplo en el que, después de la ejecución, /tmp/.xz contiene la salida uid=0(root) gid=0(root) groups=0(root)

Árbol de procesos y características de los logs

  • El árbol de procesos de una conexión SSH normal continúa hacia la sesión de usuario de sshd y el shell
  • En el ejemplo de ejecución del backdoor, después de xzbot -cmd 'sleep 60' aparecen sshd: root [priv], sshd: root [net], sh -c sleep 60 y sleep 60
  • Una explotación exitosa no genera entradas de log de nivel INFO o superior

Material de referencia

1 comentarios

 
GN⁺ 2024-04-02
Opiniones de Hacker News
  • Es bastante interesante que no lo hayan convertido en ejecución remota de código explotable por cualquiera, sino que requiera la clave privada del atacante.
    Irónicamente, parece una vulnerabilidad muy consciente de la seguridad.

    • La intención original probablemente era mantener larga la vida útil del backdoor.
      Si hubieran abierto un agujero enorme para que cualquiera pudiera entrar, lo habrían descubierto y cerrado rápido; y si no hubiera habido degradación de rendimiento, posiblemente habría sobrevivido en silencio durante mucho tiempo con el argumento de que no era ampliamente explotable.
    • Visto como un ataque patrocinado por un Estado, tiene bastante sentido plantar una vulnerabilidad segura en sistemas que también podrían usar sus propios ciudadanos.
      Toda la contribución a xz parece haber sido, al final, trabajo para insertar este backdoor; por ejemplo, incluso crearon un framework de pruebas donde se podía ocultar el payload malicioso.
      Antes de trabajar en xz, también contribuyeron a libarchive de BSD, donde apareció una vulnerabilidad.
    • Realmente parece un exploit patrocinado por un Estado.
      El diseño y la ejecución fueron extremadamente sofisticados, y que el problema de rendimiento haya sido lo que llevó a descubrirlo se siente casi como pura suerte.
    • A esto se le llama NOBUS: https://en.wikipedia.org/wiki/NOBUS
    • Según entiendo, la firma del payload incluye la clave de host SSH del objetivo; me pregunto si eso es correcto.
      Si es así, no se puede rociar indiscriminadamente sobre servidores, y enviarlo a un host en particular ya implica un costo de cómputo considerable.
  • Este incidente no me salió de la cabeza en todo el fin de semana.
    El mecanismo es fascinante y una gran colección de ofuscación, y la parte de ingeniería social es una historia vergonzosamente familiar para los mantenedores de open source.
    Lo más interesante es que hayan elegido datos de prueba malos como vector de ataque: si preparas un buen archivo, lo manipulas estructuralmente y luego lo usas como datos defectuosos para fuzz testing, el resto de los pasos se vuelve muchísimo más fácil.
    Para más adelante, diría que este tipo de manipulación debería aparecer en grafos de patrones binarios.
    El resto de las técnicas, una vez definido el payload, se parecían en general a ofuscación bastante común, pero la jugada brillante fue que, con el mismo patrón, podían agregar “parches” o incluso backdoors nuevos a otros archivos de prueba sin que nadie se diera cuenta.
    Que GitHub haya ocultado y eliminado el repositorio no ayudó en absoluto y dificulta el análisis de este incidente.

    • Empecé a desconfiar de las dependencias en tiempo de compilación de las herramientas open source que usamos.
      Descubrí que esa dependencia en particular prefiere xz de manera llamativa y, si no está instalado, incluso instala xz en la máquina host como si fuera una función de conveniencia.
      No hace eso con otras dependencias, así que resulta algo raro.
      Estas estrategias de largo plazo dan miedo, y hasta que el “mal” se ejecuta de verdad, no se puede saber qué es malicioso y qué simplemente es extraño.
    • Una de las causas principales parece haber sido agregar archivos binarios al repositorio para usarlos como entradas de prueba.
      En especial si son archivos de “basura binaria” para demostrar fallas en pruebas, son un lugar demasiado bueno para ocultar contenido malicioso.
    • Al eliminar el repositorio, al final solo los atacantes quedaron con acceso al código y al know-how.
  • Es muy impresionante que la comunidad, en especial amlweems, haya implementado y documentado tan rápido un código de prueba de concepto.
    Si no hay vulnerabilidades adicionales en las funciones criptográficas o de carga del payload, puede que ni siquiera haya abierto la falla de seguridad a todos los demás atacantes hasta que se rompa la clave.
    El siguiente paso es encontrar una forma de detectar distribuciones vulnerables, lo cual no parece fácil; y tal vez upstream podría incorporar una forma de monitorear si alguien está escaneando activamente servidores SSH con la clave hardcodeada.

    • Eso no es el exploit original, sino una prueba de concepto de una versión con la clave cambiada.
      Una prueba de concepto de la versión original requiere la clave privada no publicada del atacante.
    • Detectar por red una distribución vulnerable sin la clave privada del atacante parece no solo difícil, sino imposible.
      Lo mejor que se puede hacer sería un benchmarking más fino, pero no se puede saber si un host cualquiera de Internet responde lento porque es vulnerable, porque está lejos o porque la computadora en sí es lenta.
      Tampoco se puede acceder a cuánto tardaron intentos de conexión anteriores a ese host, y además hay variaciones de ruteo.
  • Me pregunto si alguien probó esta prueba de concepto con herramientas de detección de comportamiento anómalo de procesos.
    Productos como Carbon Black, AWS GuardDuty y Sysdig entran en esa categoría, y este parece un caso perfecto para esa familia de productos si se quiere probar si alguien lo habría notado relativamente rápido cuando se desplegó de verdad.

    • Creo que depende de qué tan bien el exploit imite o se oculte dentro de un comportamiento normal de compresión.
      GuardDuty no inspecciona procesos como un EDR tipo CrowdStrike o Carbon Black, así que creo que sería difícil que lo detectara; y Sysdig observa contenedores e infraestructura cloud, por lo que parece difícil que detecte el exploit en sí.
      Sin embargo, después de una escalada de privilegios, podría detectar anomalías en las acciones posteriores del actor de amenazas.
      En última instancia, lo más probable para detectar el exploit en sí sería un EDR que monitoree procesos de endpoint, o una evaluación de la cadena de suministro de software que monitoree problemas de seguridad en software libre y open source upstream.
      Curiosamente, esto lleva a un tema de seguridad más amplio.
      A los equipos de desarrollo puede no gustarles instalar EDR en servidores por la degradación de rendimiento y los problemas de experiencia de usuario al aplicar aislamiento, y también pueden no gustarles las políticas que restringen el uso de software libre y open source.
      Este exploit golpea justo en el centro de una “vulnerabilidad” organizacional, y según la posición puede haber argumentos tanto para mantener la exposición como para corregirla.
    • Sysdig publicó un blog el viernes.
      Decía: “Una forma de detección en runtime es monitorear si SSHD carga una biblioteca maliciosa. Estas bibliotecas compartidas suelen incluir la versión en el nombre de archivo”.
      El blog también incluye contenido de reglas de detección reales que no vi en otros proveedores de seguridad.
      https://sysdig.com/blog/cve-2024-3094-detecting-the-sshd-bac...
    • Creo que toda esa familia de productos es, en su mayoría, productos de seguridad vendehumo.
  • Leí mal el enlace de abajo, y dejo el contenido original a modo de registro
    Al ver más abajo en el mismo hilo de correo, se decía que la persona que hizo commit del backdoor parecía haber hecho recientemente contribuciones al kernel, pero el análisis original en sí es realmente excelente, así que vale la pena leer ese tipo de textos
    https://www.openwall.com/lists/oss-security/2024/03/29/10

    • Esa serie de parches la subió Lasse, no Jia Tan
      El propio Lasse también dijo que no era nada urgente y que no entraría en esta ventana de merge; ninguna persona razonable está acusando a Lasse de ser un actor malicioso
    • Hasta que se demuestre lo contrario, Lasse Collin no es Jia Tan
    • La serie de parches referenciada todavía no entró al kernel
    • Puede ser coincidencia, pero JiaT75 se parece bastante al código de transpondedor 7500, que en aviación significa secuestro
  • Este incidente tiene una cantidad absurda de similitudes con el caso de Audacity de hace unos años
    Cookie guy afirmó que lo habían apuñalado y que la policía federal estaba involucrada en el caso, lo que sugiere la posibilidad de que el incidente estuviera conectado con un actor mucho más grande que 4chan
    En ese momento mucha gente creía que solo Muse Group estaba involucrado, pero quizá pudo haber sido un actor estatal ruso
    Antes de eso, afirmó que Audacity tenía mucha telemetría y backdoors, y que los había eliminado en el primer commit después de hacer el fork
    Tal vez Audacity también tenga realmente un backdoor, así que habría que revisar el código fuente

    • Hay que tener cuidado, APT28 es bastante peligroso
      Últimamente está fusionando operaciones con APT29, y yo no despertaría a cozy bear
    • ¿Quién es Cookie guy?
  • Me pregunto cómo hacía esto el exploit real en runtime sin el openssh.patch del honeypot en tiempo de compilación https://github.com/amlweems/xzbot/blob/main/openssh.patch
    La cadena era opensshd -> notificación de systemd -> xz incluido como dependencia transitoria, y quiero saber cómo, después de que liblzma.so.5.6.1 se cargaba en memoria, lograba remontarse hasta openssh_RSA_verify para engancharlo o parchearlo

    • Al cargar liblzma, parchea la GOT del ELF con la dirección del código malicioso
      Si se carga antes que libcrypto, registra un manejador de auditoría de símbolos, que probablemente sea una función específica de glibc, y puede recibir una notificación cuando se resuelven los símbolos de libcrypto para demorar el parcheo de la GOT
    • Es ifunc
  • Me pregunto si se sabe si este exploit solo se activaba cuando entraba una conexión SSH
    La lista de cadenas en GitHub incluye DISPLAY y WAYLAND_DISPLAY
    https://gist.github.com/q3k/af3d93b6a1f399de28fe194add452d01
    Estas no tienen una relación clara con SSH, así que existe la posibilidad de que hiciera algo incluso sin una conexión
    Podría ser importante para quienes ejecutaron el código pero asumen que están a salvo porque no expusieron el servidor SSH a Internet

    • Probablemente sea un kill switch para que el exploit no funcione si hay una terminal abierta o si se está ejecutando en una sesión GUI
      Es decir, un mecanismo para evitar situaciones en las que alguien intente detectarlo, reproducirlo o depurarlo
    • También podría estar relacionado con el forwarding de sesiones X11
      Si no lo desactivas al conectarte a una máquina no confiable, se convierte en un agujero de seguridad común del lado de quien se conecta
  • Me pregunto si “una explotación exitosa no genera entradas de log” significa que, si este exploit no hubiera sido descubierto, el atacante podría haber ejecutado comandos arbitrarios como root en el host comprometido sin ni siquiera un log de sshd para esa “conexión”


    • La ejecución remota de código ocurre en la fase de conexión, antes de que se escriban logs
    • Aun así, habría quedado tráfico SSH sin el login correspondiente
      Me pregunto qué tipo de detección de anomalías habría podido captarlo
  • Me pregunto si este ataque se habría podido dificultar más separando los archivos de prueba en un repositorio aparte para que no pudieran usarse en tiempo de build
    La lógica es que cualquier cosa que pueda intervenir en el build debe ser legible por humanos

    • “Cualquier cosa que pueda intervenir en el build debe ser legible por humanos” es, en general, un buen principio para adoptar
      Hay que tratar este ataque como un accidente aéreo e introducir nuevas reglas que reduzcan la probabilidad de que vuelva a tener éxito
      Aunque no podamos verificar a cada colaborador individualmente, los datos de prueba ruidosos deberían poder separarse fácilmente