OpenSSH publica parche de emergencia para una vulnerabilidad crítica que permite saltar la autenticación SSH con contraseñas largas en Alpine Linux

Los atacantes pueden iniciar sesión en cuentas que no tienen contraseña, como las configuradas solo con clave SSH, en algunos servidores Alpine Linux que ejecutan el paquete estándar openssh-server. Para ello necesitan acceso de red al servidor, el nombre de una cuenta y una contraseña de entre 257 y 1.024 bytes.

OpenSSH, que califica el fallo como crítico, lanzó hoy la versión 10.6p2 para bloquearlo. Alpine ha publicado paquetes corregidos para todas sus versiones desde la 3.16.

El ataque funciona cuando el servidor OpenSSH (sshd) verifica contraseñas sin la interfaz Pluggable Authentication Module (PAM), los inicios de sesión con contraseña están habilitados y al menos otra cuenta en la máquina tiene contraseña. El paquete openssh-server de Alpine está compilado sin PAM y los inicios de sesión con contraseña están activados por defecto.

El fallo proviene de cómo sshd interactúa con musl, la biblioteca C sobre la que se construye Alpine. Los sistemas que no son Linux, los sistemas Linux basados en glibc y los que verifican contraseñas a través de PAM no se ven afectados, según Damien Miller del proyecto OpenSSH.

Miller recomendó a quienes ejecuten un sistema afectado: "establezcan PasswordAuthentication=no o deshabiliten SSH para estos sistemas INMEDIATAMENTE".

No se han reportado ataques que exploten el fallo.

Quién está expuesto

El aviso de seguridad de Alpine enumera cuatro condiciones. Un servidor está expuesto cuando las cuatro son verdaderas:

  • Ejecuta el paquete openssh-server, que está compilado sin PAM, o ejecuta openssh-server-pam con UsePAM no.
  • PasswordAuthentication está en yes, que es el valor predeterminado de OpenSSH.
  • Una cuenta tiene * como campo de contraseña, lo que significa que no se ha establecido contraseña.
  • Al menos otra cuenta local tiene un hash de contraseña que comienza con $5$ o $6$.

El atacante también necesita el nombre de una cuenta sin contraseña. Una sola cuenta con contraseña es suficiente para exponer a todas las cuentas sin ella. El ataque tiene éxito en cada intento con una sola conexión, según el aviso.

En Alpine, las cuentas sin contraseña incluyen:

  • Usuarios de solo clave creados con adduser sin contraseña, o con usermod -p '*'.
  • Usuarios que provienen de un servicio de directorio a través de musl-nscd, ya que no tienen entrada en shadow.
  • root, que se distribuye como root:* en la imagen base desde aproximadamente Alpine 3.16.
  • El usuario alpine en las imágenes oficiales de nube construidas con tiny-cloud.

Root está protegido por la configuración predeterminada PermitRootLogin prohibit-password y solo se puede acceder directamente si se establece PermitRootLogin yes. Esa protección no ayuda si una cuenta expuesta puede convertirse en root, por ejemplo mediante doas.

Las imágenes tiny-cloud desde la 3.18.11 hasta la 3.24.3 otorgan al usuario alpine doas sin contraseña. Son seguras en el primer arranque pero quedan expuestas una vez que existe cualquier hash $6$ en la máquina, por ejemplo después de que un administrador establezca una contraseña de consola. Un atacante puede entonces iniciar sesión como alpine y usar doas para convertirse en root.

Los contenedores que no ejecutan sshd, los sistemas con PasswordAuthentication no y las imágenes de nube configuradas a través de cloud-init, que escribe esa configuración, no se ven afectados. Las cuentas bloqueadas con ! en /etc/shadow tampoco se ven afectadas, ni las máquinas donde ninguna cuenta tiene un hash de contraseña con estilo $.

El fallo no se limita a Alpine. Özgün Kültekin de Wakefield, quien lo reportó, menciona OpenWrt, Buildroot y Yocto en su informe técnico como otros sistemas basados en musl que deben verificarse.

OpenWrt maneja SSH con Dropbear por defecto, como muestra su documentación de Dropbear, y Kültekin afirma que Dropbear no se ve afectado. En OpenWrt, el fallo solo puede importar donde un administrador haya instalado el servidor OpenSSH.

Cómo solucionarlo

En Alpine, la solución es actualizar el paquete y luego reiniciar, porque la actualización del paquete no reinicia el sshd en ejecución:

  • Actualizar los paquetes: apk upgrade -U -a
  • Reiniciar el servidor: rc-service sshd restart

Las versiones puntuales 3.21.10, 3.22.8, 3.23.8 y 3.24.4 ya incluyen el paquete corregido. Las ramas 3.16 a 3.21 están fuera de soporte pero también recibieron paquetes corregidos.

Las instancias en la nube iniciadas desde imágenes tiny-cloud anteriores a esas versiones puntuales aún necesitan la actualización, o la configuración a continuación.

Si compilas OpenSSH tú mismo, la versión 10.6p2 incluye el cambio, como describen sus notas de la versión.

Si no puedes actualizar aún, desactivar los inicios de sesión con contraseña también detiene el ataque. Primero asegúrate de que tu inicio de sesión con clave SSH funciona y mantén tu sesión actual abierta hasta que un nuevo inicio de sesión tenga éxito. Luego establece PasswordAuthentication no, verifica la configuración con sshd -t y reinicia sshd.

El aviso proporciona comandos que añaden la configuración en un archivo drop-in en /etc/ssh/sshd_config.d, que la configuración predeterminada de Alpine lee desde la versión 3.19 en adelante. También cambian cada línea PasswordAuthentication en /etc/ssh/sshd_config de yes a no, incluidas las líneas dentro de un bloque Match. Después, sshd -T | grep -i passwordauthentication debería imprimir passwordauthentication no.

El aviso sugiere buscar en /var/log/messages líneas de sshd que digan Accepted password para una cuenta que no tiene contraseña, como alpine, root o un usuario de solo clave. En máquinas expuestas, también revisa el uso de doas, los usuarios creados recientemente, los archivos y las claves autorizadas.

"Si no puedes descartar un inicio de sesión, trata la máquina como comprometida", dice el aviso.

Por qué funcionan las contraseñas largas

Sin PAM, sshd verifica la contraseña por sí mismo. Hashea el intento con crypt(), la función de la biblioteca C que convierte una contraseña en su forma almacenada, y compara el resultado con el campo almacenado.

Una cuenta sin contraseña solo tiene * en ese campo. Eso es demasiado corto para contener una sal, el prefijo aleatorio de un hash, por lo que sshd toma prestada la sal de otra cuenta que tiene un hash real.

Para los tipos de hash $5$ y $6$, crypt() de musl rechaza contraseñas de más de 256 bytes y devuelve * para señalar el error. Ese * coincide con el * almacenado, por lo que sshd acepta el inicio de sesión. El límite superior del rango es el propio límite de sshd de 1.024 bytes por contraseña.

Este comportamiento proviene de un cambio en musl del 9 de agosto de 2012, que hizo que una llamada fallida a crypt() devolviera "un hash no comparable en lugar de NULL" porque muchos programas no verificaban el fallo. El límite de 256 bytes se estableció el 29 de agosto de 2012 para proteger a los servidores de ataques de denegación de servicio.

El préstamo de sal proviene de un cambio en OpenSSH del 15 de julio de 2016 que abordó CVE-2016-6210, un fallo que permitía a los atacantes saber qué nombres de usuario existían. Kültekin dice que el problema ha existido desde entonces.

El cambio de código en 10.6p2 hace que sshd rechace una coincidencia cuando el campo almacenado tiene menos de cuatro caracteres. OpenSSH lo llama una solución alternativa y dice que la causa raíz está fuera de sshd. Los paquetes estables de Alpine llevan un parche para el mismo problema.

Por qué la solución llegó al día siguiente

El equipo de Miller se enteró del fallo a principios de esta semana y lanzó la solución lo más rápido que pudo. En el anuncio de la versión, dijo que el equipo ahora considera que los embargos largos son peligrosos y principalmente útiles para los atacantes, porque recientemente ha visto agentes de IA encontrar los mismos errores nuevamente, a veces en cuestión de horas.

Hasta hoy no se había asignado ningún identificador CVE al fallo.

Cybersecurity
Cybersecurity
Cybersecurity
Cybersecurity

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *