Исследователь смог превратить «cat readme.txt» в выполнение произвольного кода в iTerm2

от автора

Исследователь показал, как он преобразовал команду «cat readme.txt» для выполнения произвольного кода в эмуляторе iTerm2. Он показал, как iTerm2 работает с легитимной функцией, как он использует псевдотерминал (PTY) и что происходит, когда вывод терминала может имитировать одну из сторон протокола этой функции.

Команда cat readme.txt в операционных системах Linux, macOS и других Unix-подобных используется для вывода содержимого текстового файла readme.txt на экран или в терминал.

iTerm2 — это популярный бесплатный эмулятор терминала с открытым исходным кодом для macOS, работающий на macOS 12.4 или новее. Он считается продвинутой заменой стандартному Terminal.app, предлагая разработчикам и системным администраторам улучшенный интерфейс, высокую производительность, разделение экрана, поиск и широкие возможности кастомизации (темы, прозрачность, горячие клавиши).

Исследователь отметил, что он сотрудничал с OpenAI в этом проекте.

По его словам, iTerm2 имеет функцию интеграции с SSH, которая позволяет лучше понимать удалённые сессии. Для этого он не просто «вслепую вводит команды» в удалённую оболочку, а запускает небольшой вспомогательный скрипт на удалённой стороне, называемый «дирижёром».

Примерная модель выглядит следующим образом:

  1. iTerm2 запускает интеграцию SSH, обычно через it2ssh;

  2. iTerm2 отправляет удалённый скрипт начальной загрузки, «кондуктор», через существующую сессию SSH;

  3. скрипт становится одноранговым узлом протокола для iTerm2;

  4. iTerm2 и удалённый скрипт обмениваются управляющими последовательностями терминала для координации таких действий, как обнаружение оболочки входа в систему, проверка наличия Python, смена каталогов, загрузка файлов и выполнение команд.

Исследователь отмечает, что отдельной сетевой службы нет. Эмулятор терминала, такой как iTerm2, работает как программная версия, отображает экран, принимает ввод с клавиатуры и интерпретирует управляющие последовательности терминала. При этом оболочка и другие программы командной строки по-прежнему ожидают взаимодействия с подобием настоящего терминального устройства. Именно поэтому ОС предоставляет PTY, или псевдотерминал. PTY — это программный аналог старого аппаратного терминала, и он находится между эмулятором терминала и процессом переднего плана.

В обычной сессии SSH:

  • iTerm2 записывает байты в PTY;

  • процесс переднего плана — ssh;

  • ssh пересылает эти байты на удаленную машину;

  • удалённый контроллер считывает их из стандартного ввода.

Таким образом, когда iTerm2 хочет отправить команду удалённому скрипту, он фактически локально записывает байты в PTY.

Протокол интеграции SSH использует управляющие последовательности терминала в качестве транспортного протокола.

Здесь важны два момента:

  • DCS 2000p используется для перехвата SSH-проводника;

  • OSC 135 используется для сообщений проводника до кадра.

На уровне исходного кода DCS 2000p заставляет iTerm2 создать экземпляр парсера проводника. Затем парсер принимает сообщения OSC 135, такие как:

  • begin <id>

  • command output lines

  • end <id> <status> r

  • unhook

Таким образом, легитимный удалённый проводник может взаимодействовать с iTerm2 исключительно через вывод терминала.

Ошибка заключается в нарушении доверия, когда iTerm2 принимает протокол SSH-проводника из вывода терминала, который на самом деле не исходит от доверенной, реальной сессии. Другими словами, ненадёжный вывод терминала может имитировать удалённого проводника.

Это означает, что вредоносный файл, ответ сервера, баннер или 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:

  • начинают выполнение команды getshell;

  • возвращают строки, похожие на вывод shell-discovery;

  • успешно завершают эту команду;

  • начинают выполнение команды pythonversion;

  • завершают эту команду с ошибкой;

  • отключают перехватчик.

Этого достаточно, чтобы заставить iTerm2 перейти к обычному резервному пути. На этом этапе терминал считает, что завершил достаточную часть процесса интеграции SSH, чтобы перейти к следующему шагу: созданию и отправке команды run(…).

Поддельный перехватчик DCS 2000p содержит несколько полей, включая управляемый злоумышленником sshargs. Это значение важно, потому что iTerm2 позже использует его в качестве материала команды при формировании запроса run(…) от conductor.

Эксплойт выбирает sshargs таким образом, что при кодировании iTerm2 в base64:

run <padding><magic-bytes>

последний 128-байтовый фрагмент становится:

ace/c+aliFIo

Строка одновременно является действительным выводом из пути кодирования кондуктора и действительным относительным путём.

В легитимной сессии интеграции SSH iTerm2 записывает команды кондуктора в кодировке base64 в PTY, а ssh пересылает их удалённому скрипту. В случае эксплуатации уязвимости iTerm2 по-прежнему записывает эти команды в PTY, но реального SSH-дирижёра нет. Локальная оболочка получает их как обычный ввод.

Вот почему сессия при записи выглядит так:

  • getshell отображается как base64;

  • pythonversion отображается как base64;

  • появляется закодированная в base64 run(…) полезная нагрузка;

  • последний фрагмент — ace/c+aliFIo.

Более ранние фрагменты завершаются с ошибкой как бессмысленные команды. Последний фрагмент работает, если этот путь существует локально и является исполняемым.

Чтобы воспроизвести оригинальный PoC на основе файлов, можно применить genpoc.py:

python3 genpoc.py

unzip poc.zip

cat readme.txt

Это создаст:

  • ace/c+aliFIo, исполняемый вспомогательный скрипт;

  • readme.txt, файл, содержащий вредоносные последовательности DCS 2000p и OSC 135.

Первый обманывает iTerm2, заставляя его взаимодействовать с поддельным дирижёром. Второй предоставляет оболочке реальный объект для выполнения после получения финального фрагмента кода.

Для работы эксплойта нужно запустить cat readme.txt из каталога, содержащего ace/c+aliFIo, чтобы финальный фрагмент кода, созданный злоумышленником, указывал на реальный путь к исполняемому файлу.

В конце марта исследователь сообщил об ошибке в iTerm2, и её исправили на следующий день ​​в коммите a9e745993c2e2cbb30b884a16617cd5495899f86. Однако пока исправление ещё не вошло в стабильные релизы.

В сентябре был представлен первый бета‑выпуск утилиты Term.Everything, который позволяет отображать любые графические приложения внутри окна с эмулятором терминала. Также решение позволяет запускать графические приложения в терминале при доступе к удалённой системе по SSH. На терминалах, поддерживающих расширение для вывода растровой графики, таких как kitty, Ghostty, Konsole, wezterm и iTerm2, вывод почти не отличим от открытия в обычном окне.

ссылка на оригинал статьи https://habr.com/ru/articles/1027016/