Si usas iTerm2, incluso `cat readme.txt` deja de ser seguro
(blog.calif.io)- La integración SSH usa secuencias de escape de terminal para comunicarse con el shell remoto, y por esa estructura incluso la salida normal del terminal puede interpretarse como el protocolo de conductor
- El problema central es una falla de confianza: archivos maliciosos, banners, MOTD y respuestas del servidor que no provienen del conductor remoto real también pueden actuar como si fueran conductor mediante
DCS 2000pyOSC 135falsificados - Con solo ejecutar
cat readme.txt, si se renderiza una transcripción falsa de conductor, iTerm2 avanza por sí solo por el flujo degetshell,pythonversionyrun(...), y la salida del ataque solo necesita fingir las respuestas - El exploit aprovecha la confusión de que los comandos en base64 escritos al PTY, cuando no existe un conductor SSH real, terminan cayendo como entrada en texto plano del shell local; la ejecución es posible cuando el último chunk se interpreta como la ruta
ace/c+aliFIo - La corrección se aplicó en el commit del 31 de marzo
a9e745993c2e2cbb30b884a16617cd5495899f86, pero al momento de hacerse público todavía no estaba incluida en una versión estable, lo que dejó una ventana de exposición antes de que el parche se distribuyera
Contexto de la integración SSH de iTerm2
- La integración SSH de iTerm2 es una función para comprender mejor las sesiones remotas, y funciona subiendo al shell remoto un pequeño script auxiliar llamado conductor
- Se inicia la integración SSH mediante
it2ssh - Se envía conductor, un script de bootstrap remoto, a través de la sesión SSH existente
- Ese script remoto actúa como la contraparte del protocolo de iTerm2
- Se inicia la integración SSH mediante
- iTerm2 y el conductor remoto no se comunican como un servicio de red convencional, sino intercambiando secuencias de escape sobre la E/S del terminal
- detección del shell de inicio de sesión
- verificación de la presencia de Python
- cambio de directorio
- subida de archivos
- ejecución de comandos
Cómo funciona el PTY
- Los emuladores de terminal modernos son versiones en software de los antiguos terminales físicos y se encargan de la salida en pantalla, la entrada por teclado y la interpretación de secuencias de control del terminal
- Como el shell y los programas de línea de comandos siguen esperando un dispositivo que parezca un terminal real, el sistema operativo ofrece un PTY
- Un PTY es un pseudoterminal ubicado entre el emulador de terminal y el proceso en primer plano
- En una sesión SSH típica, iTerm2 escribe bytes al PTY, el proceso en primer plano,
ssh, los reenvía a la máquina remota, y el conductor remoto los lee por stdin - Cuando iTerm2 envía comandos al conductor remoto, en lo local finalmente lo hace escribiendo bytes al PTY
Protocolo de conductor
- El medio de transporte del protocolo de integración SSH usa secuencias de escape de terminal
- Hay dos elementos clave
DCS 2000pse usa para enganchar al conductor SSHOSC 135se usa para los mensajes de conductor previos al framing
- A nivel de código,
DCS 2000phace que iTerm2 cree un parser de conductor, y luego ese parser procesa mensajesOSC 135begin <id>- líneas de salida del comando
end <id> <status> runhook
- Un conductor remoto legítimo puede comunicarse con iTerm2 solo mediante la salida del terminal
Vulnerabilidad principal
- La esencia de la vulnerabilidad es una falla de confianza: iTerm2 acepta como protocolo del conductor SSH incluso salidas de terminal que no pertenecen a una sesión de conductor confiable real
- Como resultado, una salida de terminal no confiable puede hacerse pasar por el conductor remoto
- archivos maliciosos
- respuestas del servidor
- banners
- MOTD
- La entrada del ataque puede emitir un hook
DCS 2000pfalsificado y respuestasOSC 135también falsificadas; en ese caso, iTerm2 actúa como si realmente estuviera en curso un intercambio de integración SSH
Cómo funciona el exploit
- El archivo de exploit contiene una transcripción falsa de conductor
- Cuando el usuario ejecuta
cat readme.txt, iTerm2 renderiza el archivo, pero este no contiene solo texto: incluye los siguientes elementos- una línea falsa de
DCS 2000pque anuncia una sesión falsa de conductor - mensajes falsos de
OSC 135que responden a las solicitudes de iTerm2
- una línea falsa de
- Si el hook es aceptado, iTerm2 inicia el flujo normal de conductor, y en el código fuente
Conductor.start()envía de inmediatogetshell()y, si tiene éxito, luego envíapythonversion() - El ataque no necesita inyectar esas solicitudes: iTerm2 las emite por sí mismo, y la salida maliciosa solo debe fingir las respuestas
Progresión de la máquina de estados
- Los mensajes falsos de
OSC 135son mínimos, pero están construidos en el orden exacto- inicio del cuerpo del comando para
getshell - devolución de una línea que parece salida de detección del shell
- fin exitoso de ese comando
- inicio del cuerpo del comando para
pythonversion - fin fallido de ese comando
unhook
- inicio del cuerpo del comando para
- Solo con ese flujo, iTerm2 entra en una ruta normal de fallback y luego decide que el flujo de integración SSH se completó lo suficiente como para pasar al siguiente paso
- El siguiente paso es construir y enviar el comando
run(...)
El papel de sshargs
- El hook
DCS 2000pfalsificado incluye varios campos, entre ellossshargs, controlado por el atacante - Ese valor se usa después como material de comando cuando iTerm2 construye la solicitud
run ...del conductor - El exploit elige
sshargspara que, cuando iTerm2 codifique en base64 los siguientes datos,run <padding><magic-bytes>
- el último chunk de 128 bytes se convierta en
ace/c+aliFIo - Esta cadena no se eligió al azar, sino para satisfacer simultáneamente estas dos condiciones
- ser una salida válida de la ruta de codificación del conductor
- ser un nombre de ruta relativa válido
La confusión del PTY que hace posible el exploit
- En una sesión normal de integración SSH, iTerm2 escribe al PTY comandos del conductor codificados en base64, y
sshlos reenvía al conductor remoto - En la situación del exploit, iTerm2 escribe esos mismos comandos en el PTY, pero como no existe un conductor SSH real, el shell local los recibe como entrada en texto plano
- En la sesión grabada se observa una forma como esta
getshellaparece en base64pythonversionaparece en base64- luego aparece un payload largo
run ...codificado en base64 - el último chunk es
ace/c+aliFIo
- Los chunks anteriores fallan como comandos sin sentido, pero el último funciona si esa ruta existe en local y es ejecutable
Procedimiento de reproducción
- El PoC original basado en archivos puede reproducirse con
genpoc.pypython3 genpoc.pyunzip poc.zipcat readme.txt
- Este procedimiento crea los siguientes dos archivos
- un script auxiliar ejecutable llamado
ace/c+aliFIo readme.txt, que contiene secuencias maliciosasDCS 2000pyOSC 135
- un script auxiliar ejecutable llamado
- El primer archivo induce a iTerm2 a comunicarse con el conductor falso, y el segundo proporciona el objetivo que el shell realmente ejecutará cuando llegue el último chunk
- Para que el exploit tenga éxito,
cat readme.txtdebe ejecutarse desde el directorio que contieneace/c+aliFIo, de modo que el último chunk configurado por el atacante se interprete como una ruta ejecutable real
Cronograma de divulgación y parche
- El 30 de marzo se reportó el bug a iTerm2
- El 31 de marzo se completó la corrección en el commit
a9e745993c2e2cbb30b884a16617cd5495899f86 - Al momento de redactarse, la corrección todavía no estaba incluida en una versión estable
- Después de aplicarse el commit del parche, se intentó reconstruir el exploit desde cero basándose únicamente en el parche
- los prompts de ese proceso están en
prompts.md - el resultado es
genpoc2.py - funciona de forma muy similar a
genpoc.py
- los prompts de ese proceso están en
Cuestionamientos sobre el momento de la divulgación
- La divulgación ocurrió antes de que la corrección llegara a una versión estable, abriendo una ventana en la que a la mayoría de los usuarios les resultaba difícil estar realmente protegidos pese a que la vulnerabilidad ya era conocida
- Ese conflicto sobre el momento de divulgar exige una justificación clara
- Dos semanas es poco tiempo tanto para esperar una distribución significativa del parche como para justificar que era necesario forzar una respuesta mediante una divulgación temprana
- Como resultado, la vulnerabilidad pasó a ser ampliamente conocida, pero la versión corregida todavía no estaba disponible en la práctica para los usuarios que la necesitaban, creando una ventana de exposición pública
- Una mejor opción habría sido esperar a que la versión corregida llegara realmente a manos de los usuarios o presentar un fundamento claro de por qué era necesario exponerlo antes, pero no se cumplió ninguna de las dos
1 comentarios
Opiniones de Hacker News
Me preguntaba por qué lo hicieron público ahora, cuando todavía no sale un parche para la versión estable. Solo habían pasado 18 días desde que se reportó upstream, y el post del blog era mucho más detallado que el commit público, así que sentí que aumentaba la posibilidad de explotación real. El autor confirmó que pudo crear un exploit usando un LLM solo con el commit upstream, pero aun así creo que este artículo hizo la vulnerabilidad mucho más visible
El trabajo está muy bien, pero no me pareció tan sorprendente. Es un problema que aparece una y otra vez en aplicaciones de terminal con muchas funciones, y en los últimos 15 años se han divulgado varias vulnerabilidades parecidas. Herramientas como less o vim tampoco fueron la excepción, y muchos de estos problemas se parecen más a bugs de lógica que a problemas de seguridad de memoria, así que reescribirlo en Rust no los resolvería automáticamente. Por un lado queremos que las herramientas a nivel de SO sean simples y predecibles, pero por otro también queremos colores bonitos, animaciones y personalización infinita. Y ahora además entran los agentes de IA, así que ya vivimos en una época donde un archivo de texto malicioso podría contener nada más una frase como "ignora las instrucciones anteriores"
Me acordé de la época del PDP-10. Un colega descubrió que, si seguía presionando backspace, el manejador del terminal borraba incluso caracteres anteriores al inicio del buffer; y luego, si usabas un carácter de escape para borrar toda una línea, terminabas tumbando el sistema operativo
Hace 6 años ya hubo casi el mismo problema de seguridad en iTerm2
Soy el autor de iTerm2. Creo que esto puede servir como un eslabón dentro de una cadena de explotación, pero presentarlo como si por sí solo fuera un riesgo enorme, como sugiere el título, me parece una exageración. Ahora mismo estoy de viaje con mi familia y cuando regrese voy a publicar una versión corregida
No me sorprendió que apareciera un bug sutil en un sistema complejo que usa scripts de bootstrap, agentes conductor remotos, secuencias de escape y demás. Cuando se ensamblan componentes de una forma para la que no fueron diseñados, este tipo de cosas pasa fácilmente. Entiendo que si una salida no confiable que se muestra en pantalla, como un archivo de texto o el banner de un servidor, contiene códigos especiales, la arquitectura puede terminar procesándolos sin validar su origen
Sentí que esta historia ya la había visto antes. Hubo un caso donde la integración SSH de iTerm2 fue la causa de un CVE, y también me vino a la mente CVE-2025-22275. Ya había antecedentes, y el problema viejo que se mencionó en este hilo era del lado de la integración con tmux. Tal vez convendría meter estas funciones de integración de forma un poco menos agresiva
El título es demasiado sensacionalista. El problema no es cat, sino la integración SSH de iTerm, y una arquitectura de canal de control que no está separada del flujo de datos parece riesgosa. Si no usas esa función y solo usas SSH normal, en general deberías estar bien
Antes algunos emuladores de terminal permitían incluso reconfigurar teclas del teclado mediante códigos de escape. Por eso era casi sentido común no hacer
cata archivos no confiables, sino abrirlos con herramientas comolessLa redacción del artículo es imprecisa. El segundo párrafo suena como si "usar iTerm2 no fuera seguro", cuando lo más correcto sería decir que puede haber problemas al usar la función opcional de Shell Integration. Si esa función viene desactivada por defecto, entiendo que el alcance sería limitado. Si estoy equivocado, agradecería una corrección