背景在之前一篇关于 [Vim 和 Emacs 中由 AI 发现的漏洞](https://blog.calif.io/p/mad-bugs-vim-vs-emacs-vs-claude) 的文章里探讨了看似无害的操作流程如何导致代码执行。此次进一步探究执行 cat readme.txt 是否安全结果表明若使用 iTerm2并不安全。同时要感谢 OpenAI 在这个项目上的合作。iTerm2 的 SSH 集成功能iTerm2 具备 SSH 集成功能能更深入了解远程会话。它通过在远程端部署名为 conductor 的小型辅助脚本实现该功能而非简单“盲目”在远程 shell 中输入命令。大致流程为1. iTerm2 通常通过 it2ssh 启动 SSH 集成2. 通过现有 SSH 会话发送远程引导脚本 conductor3. 远程脚本成为 iTerm2 的协议对等方4. iTerm2 和远程 conductor 通过交换终端转义序列协调各种操作如发现登录 shell、检查 Python 环境、切换目录、上传文件、运行命令等。关键在于没有单独的网络服务conductor 只是在远程 shell 会话中运行的脚本协议通过普通的终端输入输出I/O进行传输。PTY 知识回顾过去终端是连接到计算机的键盘和屏幕等实际硬件设备程序从该设备读取输入并将输出写回。像 iTerm2 这样的终端模拟器是现代的软件版硬件终端负责绘制屏幕、接收键盘输入并解释终端控制序列。而 shell 和其他命令行程序期望与类似真实终端设备的东西交互这就是操作系统提供伪终端PTY的原因PTY 是旧硬件终端的软件替代品位于终端模拟器和前台进程之间。在正常的 SSH 会话中iTerm2 将字节写入 PTY前台进程是 sshssh 将这些字节转发到远程机器远程 conductor 从其标准输入读取这些字节。所以当 iTerm2 想“向远程 conductor 发送命令”时实际上是在本地将字节写入 PTY。conductor 协议SSH 集成协议使用终端转义序列作为传输方式有两个关键部分DCS 2000p 用于挂载 SSH conductorOSC 135 用于 pre - framer conductor 消息。在源代码层面DCS 2000p 会使 iTerm2 实例化一个 conductor 解析器解析器接收 OSC 135 消息如 begin 、命令输出行、end r、unhook 等。因此合法的远程 conductor 可以完全通过终端输出与 iTerm2 进行通信。核心漏洞该漏洞源于信任机制的失效iTerm2 会接受并非来自受信任的真实 conductor 会话的终端输出中的 SSH conductor 协议即不可信的终端输出可以模仿远程 conductor。这意味着恶意文件、服务器响应、横幅或 MOTD 可以输出伪造的 DCS 2000p 挂载信息和伪造的 OSC 135 回复然后 iTerm2 会表现得好像正在进行真实的 SSH 集成交互这就是漏洞利用的基础。漏洞利用的实际原理漏洞利用文件包含一个伪造的 conductor 记录。当受害者运行 cat readme.txt 时iTerm2 会渲染该文件该文件包含一条伪造的 DCS 2000p 行用于宣告一个 conductor 会话以及伪造的 OSC 135 消息用于响应 iTerm2 的请求。一旦挂载信息被接受iTerm2 就会启动正常的 conductor 工作流程在源代码中Conductor.start() 会立即发送 getshell() 请求成功后再发送 pythonversion() 请求。所以漏洞利用无需注入这些请求iTerm2 会自行发起恶意输出只需模仿回复即可。状态机分析伪造的 OSC 135 消息虽简单但精准操作如下1. 为 getshell 启动一个命令体2. 返回看起来像 shell 发现输出的行3. 成功结束该命令4. 为 pythonversion 启动一个命令体5. 以失败结束该命令6. 取消挂载。这些操作足以使 iTerm2 进入正常的回退路径此时 iTerm2 认为已经完成了足够的 SSH 集成工作流程可以进入下一步构建并发送 run(...) 命令。sshargs 的作用伪造的 DCS 2000p 挂载信息包含多个字段其中包括攻击者可控的 sshargs。这个值很重要因为 iTerm2 稍后会在构建 conductor 的 run ... 请求时将其用作命令材料。漏洞利用者选择 sshargs使得 iTerm2 进行 Base64 编码后run 最后 128 字节的块变为 ace/caliFIo这个字符串同时满足是 conductor 编码路径的有效输出和一个有效的相对路径名这两个条件。使漏洞利用成为可能的 PTY 混淆问题在合法的 SSH 集成会话中iTerm2 将 Base64 编码的 conductor 命令写入 PTYssh 会将其转发到远程 conductor。而在漏洞利用的情况下iTerm2 仍然将这些命令写入 PTY但此时并没有真正的 SSH conductor本地 shell 会将其作为普通输入接收。记录会话时呈现的情况为getshell 以 Base64 形式出现pythonversion 以 Base64 形式出现然后出现一个长的 Base64 编码的 run ... 有效负载最后一个块是 ace/caliFIo。前面的块作为无意义的命令会执行失败如果该路径在本地存在且可执行那么最后一个块就会成功执行。复现步骤可以使用 genpoc.py 复现原始的基于文件的概念验证PoCpython3 genpoc.pyunzip poc.zipcat readme.txt。这将创建 ace/caliFIo一个可执行的辅助脚本和 readme.txt一个包含恶意 DCS 2000p 和 OSC 135 序列的文件。前者会误导 iTerm2 与一个伪造的 conductor 进行通信当最后一个块到达时后者会让 shell 执行实际的命令。为使漏洞利用生效需要在包含 ace/caliFIo 的目录中运行 cat readme.txt这样攻击者构造的最后一个块才能解析为一个真实的可执行路径。漏洞披露时间线- 3 月 30 日向 iTerm2 报告了该漏洞。- 3 月 31 日该漏洞在提交 a9e745993c2e2cbb30b884a16617cd5495899f86 中得到修复。- 在撰写本文时该修复尚未应用到稳定版本中。当补丁提交后尝试仅使用该补丁从头开始重建漏洞利用该过程中使用的提示信息位于 [prompts.md](https://github.com/califio/publications/tree/main/MADBugs/iTerm2/prompts.md)生成的漏洞利用脚本是 genpoc2.py其工作方式与 genpoc.py 非常相似。