Компания V12, которая делает ИИ-агентов для поиска уязвимостей, 11 ноября показала видео: сообщение с виджетом в Telegram для Android запускает на телефоне калькулятор. Калькулятор — традиционная демонстрация того, что атакующий исполняет на устройстве свой код, а не только код, разрешённый песочницей. Уязвимость исправлена в Telegram для Android 13.2.2 (7303); касается это тех, у кого Android-клиент с виджетами старше этой версии. Твит V12 цитирует пост Павла Дурова «Any Telegram message can now become an app», заменив в нём последнее слово на RCE.
Что делать
Обновить Telegram для Android до 13.2.2 или новее. Номер своей версии виден внизу экрана «Настройки». Код виджета исполняется, когда пузырь с ним показан в чате, поэтому до обновления разумно не открывать чаты и каналы, где незнакомые боты и люди присылают виджеты. Нужно ли для атаки что-то нажимать, V12 не уточнили.
Затронуты ли iOS и десктопные клиенты, ни V12, ни коммиты Telegram не говорят.
Что такое виджет и где была ошибка
Виджет — это HTML-документ со стилями и JavaScript, который бот присылает в сообщении, а клиент рисует прямо в пузыре чата. Браузера под ним нет: разметку рисует собственный рендерер Telegram, а скрипт исполняет QuickJS — небольшой интерпретатор JavaScript, написанный на C. Подробно устройство разобрано в материале о виджетах.
Песочница виджета ограничивает, что скрипт может сделать через программный интерфейс: сеть, ссылки, запросы к боту. Но сам интерпретатор работает с памятью напрямую, и ошибка в нём оказывается ниже этой песочницы. По описанию уязвимости, найденной V12, это use-after-return в QuickJS — обращение к памяти функции после того, как функция уже вернула управление.
В открытом коде Telegram ровно такая ошибка исправлена коммитом в форке QuickJS от 10 ноября; в документации Android-клиента он помечен как отчёт против версии 13.2.1. Механизм по описанию коммита такой. В JavaScript недавно появилась конструкция await using — объявление переменной, ресурс которой освобождается автоматически при выходе из блока, с ожиданием асинхронной операции. Ожидание разрешено только в асинхронных функциях, но в одном из мест разборщик QuickJS этого не проверял. В результате инструкция ожидания попадала в обычную функцию, и при выходе из неё интерпретатор шёл по пути, рассчитанному на генераторы, пропуская шаг, на котором замыкания отцепляются от переменных функции. Замыкания, созданные внутри, продолжали ссылаться на область стека, которая после возврата уже отдана под другие данные. Такая ссылка на переиспользованную память — типичная отправная точка, чтобы читать и переписывать чужие данные процесса.
Исправление двойное: разборщик теперь отвергает await using вне асинхронных функций, а интерпретатор отказывается приостанавливать обычную функцию любой инструкцией ожидания или генератора, чтобы следующая ошибка разборщика не открыла тот же путь.
Связь коммита с отчётом V12 следует из совпадения описания: имени исследователей в коммите нет, разбора от V12 пока тоже. Под твитом V12 вместо подробностей стоит строка из 64 шестнадцатеричных знаков — это длина хеша SHA-256. Так обычно фиксируют содержимое отчёта или эксплойта, не раскрывая его, чтобы позже доказать первенство; что именно захешировано, V12 не пояснили.
Как исправляли
Исправлений в движке виджетов за последнюю неделю несколько, они идут через общий репозиторий widget-sandbox, из которого собирают движок клиенты:
| Дата | Что вышло |
|---|---|
| 6 ноября | v0.6.1: семь исправлений памяти из основной ветки QuickJS, среди них ошибка в RegExp, помеченная как присланный отчёт о RCE |
| 7 ноября | Telegram для Android 13.2.0 и 13.2.1 в исходниках |
| 9 ноября | v0.6.2 и v0.6.3: разборщик QuickJS больше не выходит за границы своих таблиц при нехватке памяти |
| 10 ноября, 13:16 UTC | исправление await using в форке QuickJS |
| 10 ноября, 13:37 UTC | Павел Дуров объявляет виджеты, Bot API 10.4 |
| 10 ноября | v0.6.4: ещё пять исправлений памяти, все достижимы из обычного JavaScript виджета |
| 11 ноября, 11:00 UTC | видео V12 |
| 12 ноября | Telegram для Android 13.2.2 в исходниках |
Исправление await using датировано на 21 минуту раньше поста Дурова, которым виджеты открыли для всех ботов: отчёт пришёл до объявления. В 13.2.2 движок закреплён на коммите с этим исправлением; пять исправлений v0.6.4 вышли в тот же день позже и в 13.2.2, судя по закреплённым версиям, не попали.
Кто прислал отчёт об ошибке в RegExp, исправленной 6 ноября, в коммитах не сказано.
Отдельный процесс для виджетов
Главное изменение 13.2.2 — не одна строка в разборщике, а новая граница. Коммит версии — 96 файлов и около 6 800 изменённых строк, и большая часть из них переносит код виджетов в отдельный изолированный процесс :widgets. По документации в коде клиента:
- В этом процессе исполняются JavaScript виджета, валидатор и рендерер. У процесса нет разрешений Android, нет сети и нет доступа к файлам приложения, то есть к аккаунтам, сообщениям и ключам.
- Основной процесс Telegram библиотеку движка больше не загружает вовсе.
- Всё, что процесс виджетов возвращает, клиент считает недоверенным: ссылки, копирование текста, запросы к боту и вызовы кошелька он перепроверяет сам — например, одна ссылка на одно настоящее нажатие пользователя.
- Поверх стоит фильтр системных вызовов seccomp. Пока он работает в режиме журнала: запрещённые вызовы записываются, но выполняются. Запуск программ и создание процессов отклоняются уже сейчас.
Процесс один на все виджеты, а не по процессу на бота: такой вариант пробовали и отказались из-за памяти, около 25 МБ на процесс. Изоляция отделяет код виджетов от данных приложения, но не виджеты друг от друга. Если похожая ошибка в QuickJS найдётся снова, исполнение кода окажется в процессе, где нет ни аккаунта, ни переписки.
Кто такие V12
V12 — автономная система поиска уязвимостей в коде: ИИ-агенты анализируют репозиторий и присылают находки с доказательством и исправлением. Основатель — Джасрадж Беди, сооснователь аудиторской компании Zellic, до этого занимался взломом Android в Google. В списке находок V12 — уязвимости в Redis, PostgreSQL, MariaDB, QEMU и анклаве поиска контактов Signal; в сентябре компания уже упоминала Telegram среди приложений, где встроенный браузер на iOS рисовал скачиваемые файлы как страницу.
Это второй за две недели заявленный RCE в Telegram для Android: в конце октября стартап NebuSec описывал ошибку в коде звонков.




