Resumen

  • CGI podía llevar una cabecera remota a una variable de entorno; Bash vulnerable podía reconocer allí una función y seguir interpretando el texto posterior como órdenes.
  • La exposición no equivalía a tener Bash instalado: hacía falta una ruta completa desde datos controlados por el atacante hasta una nueva ejecución de Bash.
  • El primer arreglo fue incompleto, y cerrar el caso requería paquetes corregidos, menos herencia ambiental y pruebas sobre procesos y sesiones realmente renovados.

Una cabecera HTTP llega con datos sobre una solicitud. No llega con permiso para ejecutar. Shellshock mostró que esa distinción podía desaparecer sin que ningún componente la borrara por sí solo.

RFC 3875 describe el mecanismo de CGI: los campos de cabecera pueden convertirse en metavariables con el prefijo HTTP_; en Unix, esas metavariables pasan al script como variables de entorno con el mismo nombre. Era un puente deliberado entre el protocolo y el proceso.

Bash aportaba otro puente. Para exportar funciones entre instancias, codificaba una definición dentro del entorno. Las versiones vulnerables detectaban una forma que comenzaba como función y la analizaban al arrancar. El análisis podía continuar más allá del cierre de la función. Lo que para CGI seguía siendo el valor de una cabecera, para Bash podía terminar siendo una orden.

La cadena era corta pero condicional: cabecera remota, variable CGI, entorno heredado, inicio de Bash, importación y ejecución. Por eso el censo útil no era “servidores con Bash”. Había que localizar servicios que aceptaran valores externos y acabaran invocando el shell. CERT/CC y Red Hat documentaron ejemplos en CGI, configuraciones SSH de comandos restringidos y determinados clientes DHCP.

CVE-2014-6271 se hizo público el 24 de septiembre de 2014. Al día siguiente CERT/CC publicó su nota y registró explotación activa. El primer parche no resolvió toda la familia de comportamientos: Red Hat lo advirtió el 26 de septiembre y CVE-2014-7169 cubrió una vía restante. Más problemas relacionados recibieron identificadores separados. Durante esos días, decir “está parcheado” sin nombrar el paquete exacto y el resultado de una prueba era una afirmación incompleta.

La solución más significativa cambió el contrato de importación. Las funciones exportadas pasaron a un espacio de nombres reconocible, como BASH_FUNC_nombre(). No era una mera firma contra una cadena conocida; separaba mejor el dato ordinario de la declaración ejecutable. Esa separación podía romper usos marginales, pero devolvía claridad a la frontera.

Quedaba el estado vivo. Red Hat explicó que ciertos servicios debían reiniciarse y que algunos usuarios necesitaban volver a iniciar sesión; screen y tmux podían conservar definiciones antiguas. El inventario de paquetes describía el disco. La prueba de cierre tenía que observar el ejecutable y el árbol de procesos que atendían la petición.

La operación correcta empezaba por dibujar la invocación. ¿Qué punto público construye el entorno? ¿Qué ayudante llama a Bash? ¿Con qué identidad? ¿Qué proceso padre persiste desde antes de la actualización? Mientras llegaba el paquete, un equipo local podía retirar un CGI innecesario, limpiar el entorno o sustituir un envoltorio de shell por ejecución directa.

Shellshock no condena CGI ni las variables de entorno. Su lección es más exigente: una organización debe conocer el momento exacto en que un dato adquiere verbos. Si ese cambio depende solo de una forma sintáctica, la autoridad ya está demasiado escondida.

Fuentes