2 puntos por GN⁺ 2024-04-10 | 1 comentarios | Compartir por WhatsApp
  • En 2008, un trabajo para corregir el cuello de botella del inicio de sesión SSH de GitHub terminó revelando una colisión anómala en la que distintos usuarios tenían la misma huella de clave SSH
  • Para evitar el problema de búsqueda lineal en el creciente archivo authorized_keys, GitHub modificó OpenSSH para consultar las huellas de clave en MySQL
  • Tras desplegar el parche, apareció un problema en el que se podía acceder por SSH a los repositorios de otros usuarios, pero las colisiones repetidas de huellas de clave eran difíciles de explicar como un simple bug del parche
  • Con la publicación de DSA-1571-1 el 13 de mayo de 2008, se confirmó que Debian OpenSSL había estado generando claves privadas predecibles durante unos 18 meses, reduciendo el número de claves posibles a poco más de 32,000 por usuario
  • Los grandes incidentes de seguridad a menudo comienzan con pequeñas señales de que “algo está raro”, y la diferencia real la marca contar con el tiempo y la capacidad para seguir esa pista hasta el final

El incidente que comenzó con el cuello de botella del inicio de sesión SSH de GitHub

  • En marzo de 2008, el autor, que trabajaba en Engine Yard, terminó ayudando con un problema de rendimiento del inicio de sesión SSH de GitHub, que era cliente de la empresa de hosting centrada en Rails
  • GitHub ofrecía acceso a repositorios Git mediante autenticación con clave pública después de conectarse por SSH a git@github.com
  • En ese momento, la gestión de claves dependía del método habitual: el archivo ~/.ssh/authorized_keys
    • Cuando SSH recibe una solicitud de autenticación con clave pública, abre el archivo authorized_keys y realiza una búsqueda lineal para encontrar una entrada que coincida con la clave enviada
    • En cuentas normales eso no era gran problema porque solo había unas pocas claves, pero en GitHub, que crecía con rapidez, todas las claves SSH se acumulaban en un solo archivo grande y el tiempo de inicio de sesión se volvió visiblemente más lento

El parche a OpenSSH y la consulta de claves en MySQL

  • Tras revisar varias soluciones, el equipo de GitHub y el autor eligieron modificar OpenSSH para buscar las claves en una base de datos MySQL usando la huella de la clave
  • Esta no fue una decisión que pudiera tomarse a la ligera
    • Modificar OpenSSH podía ser crítico desde el punto de vista de seguridad si algo salía mal
    • Como las otras alternativas eran peores, se consideró la opción “menos mala”
  • Buena parte del trabajo de implementación se dedicó a comprobar que el cambio no debilitara la seguridad
  • Después del despliegue a inicios de abril de 2008, los inicios de sesión por SSH se volvieron más rápidos y parecía que ya no habría que preocuparse por ese problema por un tiempo

El síntoma aparentemente imposible de huellas de clave duplicadas

  • A inicios de mayo de 2008, el equipo de GitHub envió un mensaje indicando que algunos usuarios podían acceder por SSH a los repositorios de otros usuarios
  • Como el problema estaba directamente relacionado con la autenticación por clave SSH y el parche a OpenSSH se había desplegado justo antes, el código escrito por el autor fue el primer sospechoso
  • Tras depurar el problema, se confirmó que dos usuarios distintos tenían la misma huella de clave
    • Salvo que los usuarios hubieran compartido sus claves, era algo prácticamente imposible
    • Los usuarios afectados no se conocían entre sí y dijeron que nunca habían publicado sus claves
  • Más adelante se encontró la misma huella de clave en otra pareja de usuarios, y esa huella era distinta de la del caso anterior
    • La situación ya era difícil de explicar como una coincidencia aislada o como un simple bug de la aplicación web
  • Una vez que quedó suficientemente claro que el parche de OpenSSH no era la causa, la participación directa del autor disminuyó
    • El autor no era empleado de GitHub y también tenía que atender a otros clientes de Engine Yard
    • El equipo de GitHub siguió verificando con los usuarios y encontró un punto en común: habían generado sus claves SSH en sistemas Debian o Ubuntu

La causa quedó clara con la divulgación de la vulnerabilidad de Debian OpenSSL

  • El 13 de mayo de 2008, con la publicación de DSA-1571-1, la situación se aclaró
  • El paquete OpenSSL de Debian llevaba unos 18 meses generando claves privadas predecibles
  • La causa fue que, durante una limpieza del código de generación aleatoria de OpenSSL, un mantenedor de Debian redujo sin querer de forma drástica el espacio de claves posibles
    • La cantidad de claves que podía generar un usuario específico pasó de ser “enormemente grande” a poco más de 32,000
    • Como muchos usuarios se registraban en GitHub y algunos probablemente generaban una clave nueva siguiendo las prácticas recomendadas, podían producirse colisiones
  • Esa divulgación aportó la prueba definitiva de que el parche de OpenSSH del autor no era el causante

Trabajo posterior relacionado con las weak keys de Debian

La diferencia que marca tener tiempo para seguir el “algo está raro”

  • El autor no pudo averiguar exactamente cuándo ni cómo Luciano Bello descubrió la vulnerabilidad que terminó siendo CVE-2008-0166
  • Como la versión estable de Debian que incluía el código vulnerable se había publicado un año antes de la divulgación, es posible que hubiera tiempo para notar que “algo estaba raro” al ver las colisiones de claves y luego investigar a fondo
  • El caso reciente de la puerta trasera de XZ también se conecta con una observación de “algo está raro” seguida de una investigación intensiva
  • La parte importante es tener de verdad la capacidad y el tiempo para realizar esa investigación concentrada
    • En ese momento, el autor no podía hacer personalmente una investigación profunda
    • El equipo de GitHub también estaba ocupado desarrollando funciones y respondiendo a incidentes en un servicio que crecía con rapidez
    • El propio autor estaba atendiendo tickets de soporte en Engine Yard
  • Se hace una gran diferencia cuando, en el momento adecuado, alguien con la habilidad, el tiempo y la energía puede seguir la pista hasta el final

1 comentarios

 
GN⁺ 2024-04-10
Opiniones de Hacker News
  • Sobre el pasaje que dice “no pude encontrar exactamente cuándo ni cómo Luciano Bello descubrió la vulnerabilidad que más tarde se convertiría en CVE-2008-0166”, en los logs de IRC de la época quedó esto:
    17:23 < luciano> has really an accident. I was needing many primes numbers... 0:-)
    17:23 < Sesse> and you got the same numbers every time?
    17:25 < luciano> Sesse, not every time :P

    • Viendo solo este log, parece que Luciano estaba generando claves en masa y le pareció raro que hubiera más colisiones de lo esperado
  • La frase “la industria tuvo suerte de que hubiera una persona con las habilidades, el tiempo y la energía adecuados justo en el momento adecuado” es un punto donde se sienten reales las estadísticas de muchos ojos y “la luz del sol es el mejor desinfectante”
    Por más improbable que parezca que alguien pase de casualidad y encuentre un bug, como es posible, en realidad sucede
    En código propietario/cerrado, esa probabilidad es cercana a 0

    • Creo que el caso xz fue una gran victoria del software de código abierto
      Alguien notó algo raro y pudo comprobar la situación real junto con el código fuente para ver que había ocurrido algo sospechoso
      Se contactó a expertos en seguridad de las principales distribuciones para que lo revisaran más a fondo, y ellos también confirmaron el problema de seguridad y pudieron responder de inmediato
      Después de hacerse público, personas con experiencia en varias áreas de software y seguridad pudieron investigar qué se hizo, cómo se hizo y cuáles eran los riesgos
      También se rastrearon y confirmaron commits sospechosos que el mismo desarrollador había dejado en otro software, y el análisis de su impacto sigue en curso
      Cada distribución se volvió más sensible a los detalles de cómo se produjo la afectación alrededor de sus archivos de compilación, y empezó a buscar formas de detectar y prevenir casos similares en el futuro
      Comparado con el código cerrado, es muy probable que reportes como “el software está un poco lento” casi no hubieran recibido atención hasta que hubiera explotación real
      Incluso si la empresa al final lo descubriera, probablemente solo publicaría una explicación muy cautelosa con la mínima información, lo que perjudica mucho la capacidad de toda la industria para evitar que se repita
    • También en el código cerrado siempre se encuentran bugs. Muchos se pueden encontrar incluso sin tener el código
      Pero es muy probable que no se pueda solucionar el problema o que no se haga nada
      La mayoría de la gente, aunque encuentre un bug, no sabe qué hacer. A mí me pasó hace mucho tiempo, y recién después me di cuenta de que cosas que había visto eran bugs
      Los detalles son borrosos porque fue hace casi 30 años, pero recuerdo que, jugando con Microsoft NetMeeting en Windows, podía provocar un crash por un error de buffer overrun
      En ese momento era principiante en computación y no entendía que un buffer overflow en una aplicación de red era algo muy malo. Parece que mucha gente con años en la industria tampoco lo entendía
      En aquella época reportar problemas de seguridad también era mucho más difícil, e incluso podía ser peligroso en algunos casos
      Al final se necesitan varias cosas: encontrarse con el problema, entender computación lo suficiente como para reconocer que el problema es grave, un medio para reportar el bug en un lugar donde la gente lo revise, y una cultura de seguridad que sepa cuándo y cómo tratar los reportes
    • También en el código propietario/cerrado la gente encuentra bugs de software todo el tiempo
    • No hay discusión en que el código abierto es mejor que el código cerrado
      Pero lo que me pregunté al leer esa misma frase es cuántos bugs de seguridad graves como Heartbleed, CVE-2008-0166 y el caso xz están ocurriendo sin ser descubiertos ni divulgados
  • Un dato importante que recién hace poco supe sobre esta vulnerabilidad es que este cambio no fue algo hecho a las apuradas
    El mantenedor publicó en la lista de correo de OpenSSL el problema que había visto, pidió feedback y propuso una corrección, e incluso recibió algunas respuestas, incluidas del upstream
    El resultado fue una vulnerabilidad terrible, pero parece más bien un caso de mala suerte tremenda en el que todos pasaron por alto el problema

    • En ese momento se sentía que Debian recibió bastantes críticas por este bug, pero como se dijo arriba, sí hubo un intento de colaboración
      Además, el código upstream de OpenSSL estaba invocando comportamiento indefinido. Por eso, si el compilador hubiera hecho exactamente la misma transformación que hizo el mantenedor de Debian, podría haber sido válido
      En ese entonces esto sonaba como una discusión académica. Uno pensaba: “ni modo que el compilador se comporte de forma tan maliciosa”
      Después se entendió mejor que el comportamiento indefinido debe evitarse por completo
      Y 8 años más tarde, con el descubrimiento de Heartbleed, todos se dieron cuenta de golpe de lo mal mantenido que estaba OpenSSL
      En su defensa, era casi trabajo voluntario, y por suerte después la situación mejoró gracias al financiamiento
    • Más que mala suerte, me pregunto si no fue falta de cobertura de pruebas automatizadas
      Si se trata de código de un generador de números aleatorios importante para la seguridad, parece realmente necesario tener una prueba que genere una enorme cantidad de números aleatorios y verifique que todos sean únicos
  • Al leer cosas así, me pregunto cuál será la probabilidad de que algo como esto ya haya ocurrido, o vaya a ocurrir, también en la función de generación de seed de alguna de las hardware wallets de Bitcoin populares.
    Y también me pregunto cuáles serían las consecuencias.

    • https://www.unciphered.com/blog/randstorm-you-cant-patch-a-h...
      Durante los últimos 22 meses, Unciphered ha estado trabajando con BitcoinJS, ampliamente usado para generar wallets de criptomonedas basadas en navegador, y con una vulnerabilidad que afectó a productos y proyectos creados con ese software.
      Con el paso de los años, esta vulnerabilidad hizo que se generara una cantidad considerable de wallets de criptomonedas vulnerables.
    • Si fuera un problema de ese tipo, creo que se descubriría bastante rápido.
      En el caso de la vulnerabilidad de SSH, hay que comprobar activamente si el servidor al que uno intenta acceder tiene una de las huellas malas, pero en el caso de las wallets, porque permitiría acceder automáticamente a fondos de otras personas en la red.
    • https://news.ycombinator.com/item?id=6195493
    • El hackeo de Wintermute por 160 millones de dólares ocurrió por una generación de claves insegura en una biblioteca pública.
      Aunque en ese caso es poco probable que se haya introducido intencionalmente.
    • Si pensamos que cada clave puede generarse de forma determinista a partir de una seed key, y que la seed key no es infinita, al final es cuestión de tiempo.
      Con la tecnología actual harían falta millones de años de cómputo, pero para un actor estatal capaz de gastar una cantidad casi infinita de dinero y ejecutar ese cómputo en unas semanas, quizá no esté fuera de alcance.
      Puede llegar un momento en que cualquiera que conozca una dirección pueda acceder a todas las wallets.
      Si puedes ser objetivo de alguien con cabeza y dinero, Bitcoin no es muy seguro para guardar valor.
  • Me dio risa la frase “Ezra Zygmuntowitz me conectó con GitHub y me dio tiempo para profundizar en el problema con el equipo de GitHub”.
    Tal vez porque no soy hablante nativo, también puede leerse como que había un gran problema con el propio equipo de GitHub, así que pensé que las siguientes frases iban a profundizar en eso.
    La parte de “me pregunto cuánto habría pasado hasta que se descubriera si Luciano no lo hubiera encontrado” probablemente apunta a que solo GitHub o un proveedor grande de nube se habría topado con esto por casualidad.
    No hay muchos lugares que tengan guardadas miles o decenas de miles de claves de usuarios.

    • En sintaxis, a esto se le llama problema de adjunción de sintagmas preposicionales.
      Es el problema de si hay que leer la oración como (profundizar en el problema) (con el equipo de GitHub) o como profundizar en (un problema relacionado con el equipo de GitHub).
      Se sabe que manejar esto correctamente es bastante difícil.
    • Puede leerse de ambas formas, pero si hubiera habido una coma después de “problem”, la ambigüedad habría desaparecido.
  • Según entiendo, el generador de números aleatorios de OpenSSL se sembraba con memoria de stack sin inicializar y el PID, y Debian hizo que se sembrara solo con el PID.
    Pero aun sin el parche de Debian, ¿no era ya bastante peligroso?

    • Este malentendido parece estar bastante extendido. Pero en realidad no fue así.
      En el código de OpenSSL había dos puntos donde se copiaban bloques de bytes, y uno de ellos podía copiar basura sin inicializar. Eso sí estaba mal.
      Alguien escribió un parche para corregirlo y, después, sin ayuda de ningún LLM, solo con pura incompetencia humana, alguien dijo: “hay otra copia parecida cerca, así que también habría que eliminarla”.
      Debian incluyó un parche con ambos cambios.
      Como resultado, OpenSSL ahora ya no copiaba ningún byte.
      Está bien que no copiara datos sin inicializar, pero tampoco copiaba entropía verdaderamente aleatoria al pool. Vaya.
    • Eso es incorrecto. OpenSSL también sembraba el generador de números aleatorios con datos leídos de /dev/urandom.
  • En la parte que dice “Tras evaluar varias soluciones posibles, concluimos que la opción menos mala era parchear OpenSSH para que buscara claves en una base de datos MySQL indexada por huellas de clave”, ¿por qué MySQL y no sqlite?
    La situación era acelerar el acceso a ~/.ssh/authorized_keys, y este tipo de caso parece justamente uno para el que MySQL fue diseñado para brillar.
    Creo que habría sido menos trabajo parchear OpenSSH para que revisara ~/.ssh/authorized_keys.db que parchearlo para usar MySQL.

    • Seguramente había muchas máquinas involucradas, y normalmente es más fácil mantener una sola base de datos que mantener varias.
      También es muy probable que MySQL ya estuviera en operación. Entonces no habría habido costo inicial para guardar ahí los datos.
      Al fin y al cabo, la base de datos de usuarios ya debía existir en algún lado.
  • Más allá de haber encontrado unas pocas claves débiles, es interesante que los inicios de sesión SSH lentos fueran una pista que valía la pena investigar por varias razones.

  • Otro episodio interesante es el caso en que se usó el máximo común divisor para detectar claves RSA con un factor p o q común: https://factorable.net/weakkeys12.extended.pdf

  • Me pregunto si GitHub todavía ejecuta un openssh parcheado.

    • Si quieres, no es difícil revisar algo bastante cercano al código fuente de GitHub.
      Basta comprar una copia de GitHub Enterprise, deshacer la ofuscación de archivos y explorar. Desofuscarlo es un reto divertido y no es demasiado difícil.
      Lamentablemente no es open source, así que no se puede compartir el código, hablar de él ni enlazarlo en GitHub.
      Aun así, si GitHub Enterprise todavía usa un parche así, es muy probable que el GitHub en producción también lo haga.
    • Al menos no habrán vuelto al método de poner todas las claves otra vez en ~/.ssh/authorized_keys.
    • GitHub usa algo llamado babeld.
      Si te conectas por telnet al puerto 22 de github.com, se imprime de inmediato la cadena de versión.
    • En 2015 usaban libssh.
      Corrección: al principio dije golang, pero al verificarlo vi que quien usaba golang era Bitbucket.
    • Desde OpenSSH 6.2, lanzado en 2013, se agregó AuthorizedKeysCommand, así que no hace falta un parche.