Вспоминаем истоки.
Олды помнят, что когда-то в этом канале рассказывали об уязвимостях на TON, в том числе
и о своих находках.
Не так давно у swap coffee появился свой DEX, он вышел сразу с аудитом от TrailOfBits (аудит почему-то был удалён из репы, найти его можно
в истории коммитов). И среди всего аудита (весьма неплохого, судя по всему) давайте разберём одну багу, которая крайне характерна именно для TON — под номером 6 (
четыре шесть) в отчёте.
Основой билдинга вокруг DEX является так называемый возврат исполнения — когда после успешно проведённой операции на DEX происходит исполнение какой то логики на следующем контракте. Например, в
@bidask мультихопы реализованы по сути как 2 свапа — сначала один пул проводит свап, потом передает токены другому пулу и "просит" провести второй свап.
На блокчейне TON, ввиду его асинхронности, это реализовано через forward_payload-ы — то есть какие-то данные, которые можно передавать получателю результатов операции (например, после успешного свапа), чтобы он на основе этих данных делал что-то ещё.
С жетонами никакой проблемы нет, а вот TON, как валюта для оплаты комиссий, всегда вызывал проблему — как отделять логический TON, с которым проводится операция, от TON, который был прислан для комиссий? Ston fi не заморачивались — просто
обернули TON в жетон, и всё. Но это не очень эффективно, поэтому другие DEX начали что то выдумывать.
Самым логичным решением было просто хранить TON на каком-то контракте DEX. Например, в
@bidask он хранится на пуле. После свапа пул просто отправляет весь TON (и комиссионный, и свапнутый) получателю.
Так же сделали и swap coffee, но ошиблись: вместе с TON они слали просто forward_payload, ничего с ним не делая. Это кажется элегантным решением, свапающий сразу может вставить нужный ему опкод, вызвать нужную операцию на своем контракте после свапа, и не париться. Однако именно это и является проблемой — атакующий может указать в качестве получателя результатов свапа внутренний контракт декса, и от имени пула/vault-а (сообщение с TON же идет оттуда) указать ему что-то сделать (например, вывести ликву на кошелёк атакующего, или провести еще один свап, или депозитнуть еще ликвидности).
В этом и заключается баг, именно поэтому подобные сообщения нужно префиксовать чем-либо — например, мы в
@bidask озаботились этим ещё при написании кода,
и используем свой опкод, который вставляем перед forward_payload. Таким образом, сообщение не подпадает ни под одну схему интерфейса внутри DEX, и уязвимость не может быть проэксплуатирована.
Хорошо, что эту уязвимость обнаружили при аудите — это очень круто. Нам известно, что у как минимум 2-х других проектов на TON этот баг при аудите не был найден.
Думайте.
@TheOpenDevBlog
Обсуждение 24
Обсуждение не доступно в веб-версии. Чтобы написать комментарий, перейдите в приложение Telegram.
Обсудить в Telegram