10 ноября я рассказал, как работают HTML-виджеты Telegram. Разобрал, как бот отправляет виджет, где выполняется JavaScript и как данные от бота меняют уже отправленное сообщение. А на игре с башней проверил, что вообще влезает в 4 КБ. Про безопасность я тогда написал, что виджет живёт в песочнице без сети и ввода с клавиатуры.

На следующий день V12 выложила демонстрацию уязвимости. Моя башня на этом фоне выглядела довольно воспитанной.

Что показала V12

Демонстрация V12: виджет запускает калькулятор на Android
Демонстрация V12: виджет запускает калькулятор на Android
Уязвимости нет, а она сидит на столе
Уязвимости нет, а она сидит на столе

Что ответил Павел Дуров

Запуск виджетов Павел Дуров анонсировал так: «Any Telegram message can now become an app». После калькулятора он написал второй пост, и его я теперь буду показывать всем, кто спрашивает, как отвечать на баг-репорты.

Ответ Павла Дурова о виджетах Telegram
Ответ Павла Дурова о виджетах Telegram

Перевод поста

По поводу предполагаемого удалённого выполнения кода в новых виджетах Telegram для Android и Windows.

Проблемы не существует.

Никого нельзя было взломать одним лишь получением сообщения.

Сначала нужно было самому запустить сторонний сервис.

Даже этот сценарий уже полностью закрыт на стороне сервера.

Думаете иначе? Попробуйте взломать мой аккаунт: t.me/monk 🍿

Во второй строчке «проблемы не существует», в пятой «даже это полностью исправлено на сервере». Уязвимость Шрёдингера: её нет, но её починили.

Павел Дуров уточняет, что для атаки пользователь должен был сначала запустить бота. Это ограничивает сценарий, но не отменяет уязвимость. Уговорить человека нажать «Старт» можно, например, под предлогом верификации для входа в чат. После этого бот мог прислать виджет с вредоносным кодом.

Это возможный сценарий, а не свидетельство такой атаки. Но необходимость запустить бота сама по себе довольно слабое утешение: от сообщения в мессенджере человек всё равно не ожидает запуска постороннего кода на своём устройстве.

Неделя по дням

В журнале исправлений первая запись о RCE появилась 6 ноября, за три дня до того, как виджеты открыли всем ботам.

Дата

Что произошло

5 ноября

Telegram Desktop 7.4.0, в описании релиза одна строка: «HTML widgets in bots»

6 ноября

Движок виджетов v0.6.1: семь исправлений, одно из них Telegram сам называет «the reported RCE»

9 ноября

Виджеты открыли всем ботам в Bot API 10.4. В тот же день вышел аудит движка QuickJS-ng на 27 находок

10 ноября

Движок v0.6.4: ещё пять ошибок памяти и вторая ошибка с выполнением кода, найденная на Android 13.2.1

10 ноября

Выходит моя статья про башню

11 ноября

Ролик V12 с калькулятором. Telegram Desktop 7.4.2

13 ноября, ночь по Москве

Telegram Desktop 7.4.3

Ошибка первая: регулярка, которую выполнили после удаления

JavaScript внутри виджетов запускает QuickJS, движок на C. Если он ошибается при работе с памятью, скрипт может выйти за пределы песочницы.

Когда replace удалял совпадения, QuickJS мог заново скомпилировать ту же регулярку прямо посреди операции. Старый байткод уже освободили, а движок продолжал читать его по прежнему адресу. Такая ошибка называется use-after-free.

Через неё можно было запустить свой код с правами процесса, в котором работал QuickJS. Использовала ли V12 именно этот баг, неизвестно.

Ошибка вторая: функция закончилась, а её память ещё используют

9 ноября Андреас Рёсдал, один из разработчиков, вносивших правки в QuickJS-ng, опубликовал аудит движка. Проверять исходники ему помогала нейросеть Claude Fable 5.1. В отчёте было 27 находок, но автор оговорился: их проверили по коду, воспроизвести атаки он не пытался.

Одна из ошибок возникала из-за await using внутри обычной функции:

  1. Движок принимал код, который должен был отклонить.

  2. Функция завершалась, а созданные внутри неё замыкания продолжали обращаться к её бывшему участку памяти.

  3. Этот участок уже мог использоваться для других данных.

Это use-after-return, ещё одна ошибка работы с памятью. 10 ноября Telegram выпустил её исправление.

Баги искали с помощью нейросетей

Нейросетями пользовался не только Рёсдал. 11 ноября разработчик Коннор Ши сообщил о другой ошибке памяти: её нашла Mythos 5.2, а он подтвердил результат. Так что речь уже о конкретных багах, которые разработчики находили с помощью AI.

Думаю, без нынешних нейронок некоторые из этих багов могли бы просидеть в движке ещё лет пять, а то и десять. Кто бы сел проверять, что будет, если регулярка пересоберёт сама себя в тот момент, когда движок её выполняет?

До Desktop исправление дошло не сразу

Исправить движок мало: его новую версию ещё нужно включить в приложения Telegram. Поэтому я проверил, какой код попал в обновления для компьютера.

Telegram Desktop 7.4.2 вышел 11 ноября, уже после исправления ошибки с await using. Но именно этого патча в нём не оказалось: приложение получило пять других исправлений памяти. Нужный патч появился в версии 7.4.3, вышедшей в ночь на 13 ноября по Москве.

У обеих версий одинаковое описание: «Исправления ошибок и другие мелкие улучшения». По нему не понять, что обновление закрыло ещё одну дыру в движке. Пришлось сравнивать версии QuickJS в исходниках приложения.

Мелкие правки на поверхности, дыры в движке под водой
Мелкие правки на поверхности, дыры в движке под водой

На Android виджеты отделили от самого Telegram

В Android 13.2.2 (сборка 7303) ошибку с await using тоже исправили. Заодно движок виджетов перенесли в отдельный изолированный процесс без доступа к файлам Telegram и сети. Раньше он работал внутри самого приложения. Теперь, даже выбравшись из QuickJS, вредоносный код не получает автоматически права Telegram.

Добавили и ограничения на обращения к операционной системе. Запускать новые программы из процесса виджета уже запрещено. Часть остальных ограничений пока только проверяют: записывают обращения в журнал, чтобы понять, какие из них можно заблокировать, не сломав виджеты.

Оказалось, что Telegram можно было ещё и уронить сложной отрисовкой. В тестах тысячи вложенных графических эффектов переполняли стек или съедали гигабайты памяти. Теперь количество таких эффектов ограничено, чтобы один виджет не обрушил приложение.

Для iPhone и отдельного клиента Telegram for macOS номера сборок с патчами я не нашёл.

А виджеты-то сейчас работают?

13 ноября Telegram Info сообщил, что виджеты в чатах перестали работать, и предположил, что их отключили из-за уязвимостей. Павел Дуров пишет, что сценарий закрыли на сервере, но как именно, не объясняет. Отключили виджеты целиком или частично и когда вернут, пока непонятно.

Если вы повторяете мой туториал и бот молчит, причиной может быть ограничение на стороне Telegram.

Что делать

Обновиться: Android 13.2.2 и выше, Desktop 7.4.3 и выше, на остальных платформах просто последняя версия. Незнакомым ботам с кнопкой «Запустить» на этой неделе можно не отвечать.

Свои виджеты переделывать не надо. Дыра была в движке клиента, а ваш HTML остаётся обычным HTML. Разве что не вкладывайте div глубже 1024 уровней, но вы, надеюсь, и не собирались.

Виджеты мне по-прежнему нравятся, 4 КБ интерактива прямо в сообщении остаются отличной игрушкой. В первой статье я бы теперь уточнил, что на Android виджеты работают в отдельном процессе, а фильтр системных вызовов пока в режиме аудита.