Acceso con contraseña de 257 caracteres: un asterisco compromete millones de servidores

Acceso con contraseña de 257 caracteres: un asterisco compromete millones de servidores

CiberseguridadLinuxOpenSSHAlpineAnálisis de Vulnerabilidades

Fuentes:sshhole.com informe de vulnerabilidad + notas de lanzamiento de OpenSSH 10.6p2 · HN · Lobsters

El 5 de noviembre de 2026 se hizo pública en el ecosistema Linux una vulnerabilidad que rompe por completo el sentido común criptográfico. En millones de contenedores basados en Alpine, cuentas de administrador configuradas expresamente para rechazar el acceso por contraseña fueron comprometidas. A un atacante le bastaba con ingresar una cadena aleatoria de 257 caracteres en el campo de contraseña para obtener acceso directo al sistema.

La intuición dicta que contraseñas más largas ofrecen mayor protección y que entradas desmesuradas deberían ser bloqueadas de inmediato. En este caso ocurrió justo lo opuesto: una barrera estricta de control de acceso fue franqueada con total facilidad mediante una serie de caracteres tecleados al azar.

Una entrada desmedida derriba las defensas: acceso con 257 bytes

Las condiciones para reproducir el fallo son tan precisas como comunes en producción. El servidor de destino debe ejecutar OpenSSH enlazado contra la biblioteca C musl y sin módulos PAM activados. Cuando un atacante envía una contraseña de entre 257 y 1024 bytes, la autenticación se aprueba de forma inmediata.

Un tamaño de 257 bytes excede ampliamente cualquier contraseña razonable. Sin embargo, ese dato anómalo traspasó la lógica de comparación interna y provocó que el sistema considerara válida una cuenta que jamás debió autenticarse. En ese preciso instante, el diseño defensivo falló.

Las cuentas vulnerables presentan un patrón muy concreto: en /etc/shadow, el campo de hash de contraseña contiene únicamente el carácter *. Según el estándar UNIX, un asterisco indica que la cuenta no admite inicio de sesión mediante contraseña. Las imágenes base de proveedores en la nube y las cuentas de despliegue basadas en claves SSH utilizan precisamente esta configuración.

El objetivo más accesible se encontraba en la nube: en las imágenes oficiales de Alpine para AWS y Azure, el usuario por defecto alpine cuenta con esta configuración y dispone además de privilegios doas sin contraseña. Comprometer dicha cuenta equivale a obtener privilegios de root al instante.

Basta con que en la máquina exista otra cuenta con un hash de contraseña válido para que el ataque funcione de forma determinista. OpenSSH toma prestada la sal (salt) de esa cuenta para mitigar ataques de canal lateral basados en temporización. Múltiples salvaguardas de seguridad se combinaron entre sí para, paradójicamente, otorgar acceso libre al intruso.

Tres decisiones razonables que colisionaron 46 años después

Al revisar la evolución histórica de UNIX, se descubre que esta puerta trasera se originó a partir de tres decisiones de diseño independientes tomadas a lo largo de casi medio siglo. Cada una de ellas fue plenamente lógica y justificada en su contexto original; su convergencia final, no obstante, resultó desastrosa.

La primera decisión tuvo lugar en 1980. Bill Joy introdujo un asterisco * en el archivo de contraseñas de 3BSD para la cuenta de servicio daemon. Los algoritmos criptográficos de la época no podían generar un asterisco solitario como resultado, lo que garantizaba que ninguna contraseña ingresada pudiera coincidir jamás con ese valor.

Archivo de contraseñas original en 3BSD de 1980 Figura: Captura del archivo passwd original de 3BSD en 1980, donde el campo de contraseña de la cuenta daemon contiene un asterisco. Fuente: sshhole.com

Esta sencilla convención de bloquear cuentas mediante un asterisco se mantuvo intacta durante 46 años como norma universal de la industria.

La segunda decisión llegó en 1997. El estándar internacional UNIX (SUS) estableció que la función de cifrado crypt() debía retornar un puntero nulo (NULL) en caso de fallo en el cálculo. Sin embargo, numerosos programas escritos en C omitían la comprobación de punteros nulos, provocando fallos de segmentación (segmentation faults) y caídas de servicios ante valores NULL.

En agosto de 2012, los desarrolladores de la biblioteca ligera musl tomaron cartas en el asunto. Para erradicar los bloqueos por puntero nulo, el commit b3c4cc12 modificó la función para que devolviera un único carácter * cuando se produjera un error de cómputo, eliminando de paso los comentarios en el código que asumían la imposibilidad de fallos.

Definición en musl del asterisco como valor de retorno de error Figura: Comentarios en los encabezados de musl donde se especifica el retorno directo de un asterisco ante fallos de cálculo. Fuente: sshhole.com

Para los desarrolladores de musl, el asterisco representaba un fallo de cálculo. Para los administradores de sistemas, el asterisco representaba una cuenta con acceso deshabilitado. Dos entornos distintos asignaron significados opuestos exactamente al mismo carácter.

El límite contra DoS colisiona con la protección contra canales laterales

La tercera decisión unió definitivamente ambos asteriscos. El 29 de agosto de 2012, apenas veinte días después del cambio anterior, musl incorporó soporte para el algoritmo SHA-512.

El cálculo de SHA-512 es muy costoso en recursos y su tiempo de procesamiento aumenta con la longitud de la entrada. Para prevenir ataques de denegación de servicio (DoS) por agotamiento de CPU con contraseñas gigantescas, musl fijó un límite estricto de 256 bytes. Si la entrada superaba esa longitud, el código abortaba el cálculo y retornaba un único asterisco *.

Código de musl que impone el límite de 256 bytes Figura: musl libc fijando un tope de 256 bytes en crypt_sha512.c para evitar el consumo excesivo de recursos en el servidor. Fuente: sshhole.com

Ese tope de 256 bytes neutralizó con éxito los ataques de denegación de servicio y operó sin incidentes en producción durante años.

Más adelante, en julio de 2016, OpenSSH corrigió una vulnerabilidad de canal lateral por análisis de tiempos (CVE-2016-6210). Dado que las respuestas ante usuarios inexistentes solían ser más rápidas, los atacantes podían deducir nombres de usuario válidos midiendo la latencia. Para igualar los tiempos de respuesta, OpenSSH introdujo un cálculo simulado.

Al procesar una solicitud de autenticación para una cuenta sin hash registrado, el servicio toma la sal de una cuenta válida existente y ejecuta un ciclo de cifrado falso con el único fin de consumir tiempo. Las cuentas deshabilitadas con un asterisco también pasaron a transitar por este flujo de cálculo simulado.

La trampa quedó lista. Un atacante envía una contraseña de 257 bytes a la cuenta root. OpenSSH toma una sal prestada y llama a crypt(). musl detecta que la longitud supera los 256 bytes, aborta la operación y devuelve *. OpenSSH compara ese * devuelto contra el valor en /etc/shadow, comprueba que son idénticos y concede el acceso sin más preguntas.

La era de los contenedores propulsó un diseño minoritario a millones de servidores

En sus orígenes, musl solía utilizarse en enrutadores domésticos y dispositivos embebidos con una superficie de exposición reducida. La adopción masiva de contenedores trasladó este diseño particular al epicentro de la infraestructura cloud moderna.

Con un tamaño de apenas 5 MB, Alpine Linux se convirtió en la base preferida para construir contenedores a escala global. En 2019, al corregir una vulnerabilidad de contraseña vacía en el usuario root de sus imágenes oficiales, los mantenedores bloquearon el campo con un signo de exclamación !. Sin embargo, esto impedía la autenticación mediante clave SSH en entornos sin PAM, provocando problemas de conexión en los principales proveedores de nube.

Por ello, en Alpine 3.16 (lanzada en 2022) se decidió revertir el campo de contraseña de root al asterisco *. El inicio de sesión por clave volvió a operar con normalidad, pero dejó a todas las versiones e imágenes posteriores expuestas a las condiciones del bypass.

La comunidad técnica analizó rápidamente el alcance de la brecha. El desarrollador jbyers señaló que, si bien la probabilidad de que un único contenedor cumpla todas las condiciones de forma simultánea puede no parecer abrumadora, al multiplicar esa cifra por el descomunal volumen de contenedores activos en el mundo, la cantidad de sistemas afectados resulta enorme. Millones de entornos en producción tropezaron inadvertidamente con este escollo.

El cumplimiento de los estándares también generó controversia. El desarrollador NewJazz cuestionó si musl se había desviado de las especificaciones POSIX. Otros replicaron citando el texto de la norma, recordando que POSIX define un único código de error y carece de pautas claras para la gestión de situaciones excepcionales.

En el foro Lobsters, el usuario mort criticó el tono narrativo de algunos reportes de seguridad, señalando que las divulgaciones técnicas deben ir al grano y priorizar el alcance real y las instrucciones de mitigación.

No basta con actualizar paquetes: es imperativo reiniciar servicios

El 5 de noviembre de 2026, el proyecto OpenSSH lanzó la versión 10.6p2. La actualización añade reglas de filtrado para rechazar valores de retorno de un solo carácter, evitando que la capa de aplicación asuma a ciegas las convenciones de la biblioteca del sistema.

Actualizar el paquete, sin embargo, es solo la mitad del trabajo. El ciclo de vida de los procesos en Linux suele representar un punto ciego habitual entre administradores.

Aunque el gestor de paquetes actualice los binarios en el disco, los procesos residentes en la memoria continúan ejecutando el código previo. Mientras no se reinicie el servicio, la vulnerabilidad persiste activa. Los administradores deben reiniciar inmediatamente el servicio sshd o reconstruir y reiniciar los contenedores afectados.

Al evaluar este incidente en su conjunto, destaca que ninguna línea de código fue escrita con fines maliciosos. En 1980 se introdujo un asterisco para inhabilitar accesos; en 1997 se establecieron retornos para evitar caídas imprevistas; en 2012 se limitó el tamaño de entrada frente a ataques DoS; y en 2016 se incorporaron cálculos simulados para neutralizar análisis temporales. Cada decisión representaba la mejor práctica de su época.

Sin embargo, al confluir todas estas lógicas defensivas a lo largo de cuatro décadas, una pequeña discrepancia semántica abrió un canal silencioso de escalada de privilegios. En sistemas complejos, capas defensivas superpuestas que asumen premisas distintas son a menudo mucho más difíciles de detectar y neutralizar que un error aislado de programación.

Enlaces de referencia:

  • Divulgación original de la vulnerabilidad y herramienta de verificación en sshhole.com
  • Commit fbe926af en Alpine aports: cambio del campo de contraseña de root de exclamación a asterisco
  • Anuncio oficial de OpenSSH 10.6p2 y parche del código fuente
  • Debate técnico en Hacker News sobre los valores de retorno de musl crypt
  • Discusión en Lobsters sobre los perímetros de seguridad en contenedores y medidas de resolución