8 грудня 2023 OpenZeppelin випустив важне попередження про безпеку. Виявляється, при спільному використанні стандарту ERC-2771 та функцій типу Multicall існує ризик підміни адреси! Я глибоко вивчив цю уразливість і хочу поділитися своїми знахідками.
Зловмисник обміняв 5 WETH на приблизно 3,455,399,346 TIME
Потім сконструював хитрі параметри calldata і викликав [Forwarder].execute
Ця функція запустила multicall в контракті TIME, а залишковий calldata використовувався для burn() - знищення токенів у пулі!
Як це працює?
В цій атаці зійшлися зірки: ERC-2771, Multicall і ретельно складені дані. Контракт TOKEN успадковує ERC2771Context, і тут починається найцікавіше!
ERC-2771 надає віртуальний msg.sender, дозволяючи делегувати транзакції третій стороні. При цьому справжня адреса додається в calldata. Коли [Forwarder] викликає контракт, _msgSender() перевіряє ці дані та обрізає останні 20 байтів як "справжній" msg.sender.
Multicall ж перетворює один виклик на кілька, економлячи газ. Він приймає масив викликів і виконує їх через deleGatecall().
І ось тут пастка! Атакуючий зміщує calldata так, що перші 4 байти нових даних відповідають функції burn(), а параметр - величезна сума токенів. У рядку 0x20 додається адреса TIME-ETH пулу ліквідності, який стає "очікуваним" msg.sender!
Корінь проблеми
В ERC-2771 [Forwarder] ніколи не планувався для роботи з multicall! Атакуючий додав параметри _msgSender() до зовнішнього виклику multicall. Всередині функції multicall деякі функції теж додавали ці параметри, що дозволило імітувати виклик від ЛЮБОГО адреси!
Заходи безпеки
Нова версія OpenZeppelin Multicall тепер зберігає довжину контексту ERC-2771 і враховує її при кожному дочірньому виклику.
ThirdWeb пішов далі і заборонив будь-яким контрактам викликати multicall, запобігаючи використанню [Forwarder].
Ця уразливість - яскравий приклад того, як комбінація безпечних окремо компонентів може створити катастрофічну брешу! Усі розробники повинні пам'ятати: завжди перевіряйте взаємодію між різними стандартами.
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
Аналіз принципу вразливості підміни довільної адреси в ERC2771 Multicall від SharkTeam
8 грудня 2023 OpenZeppelin випустив важне попередження про безпеку. Виявляється, при спільному використанні стандарту ERC-2771 та функцій типу Multicall існує ризик підміни адреси! Я глибоко вивчив цю уразливість і хочу поділитися своїми знахідками.
Аналіз атаки
Розглянемо одну з атак:
Схема атаки геніально проста:
Як це працює?
В цій атаці зійшлися зірки: ERC-2771, Multicall і ретельно складені дані. Контракт TOKEN успадковує ERC2771Context, і тут починається найцікавіше!
ERC-2771 надає віртуальний msg.sender, дозволяючи делегувати транзакції третій стороні. При цьому справжня адреса додається в calldata. Коли [Forwarder] викликає контракт, _msgSender() перевіряє ці дані та обрізає останні 20 байтів як "справжній" msg.sender.
Multicall ж перетворює один виклик на кілька, економлячи газ. Він приймає масив викликів і виконує їх через deleGatecall().
І ось тут пастка! Атакуючий зміщує calldata так, що перші 4 байти нових даних відповідають функції burn(), а параметр - величезна сума токенів. У рядку 0x20 додається адреса TIME-ETH пулу ліквідності, який стає "очікуваним" msg.sender!
Корінь проблеми
В ERC-2771 [Forwarder] ніколи не планувався для роботи з multicall! Атакуючий додав параметри _msgSender() до зовнішнього виклику multicall. Всередині функції multicall деякі функції теж додавали ці параметри, що дозволило імітувати виклик від ЛЮБОГО адреси!
Заходи безпеки
Нова версія OpenZeppelin Multicall тепер зберігає довжину контексту ERC-2771 і враховує її при кожному дочірньому виклику.
ThirdWeb пішов далі і заборонив будь-яким контрактам викликати multicall, запобігаючи використанню [Forwarder].
Ця уразливість - яскравий приклад того, як комбінація безпечних окремо компонентів може створити катастрофічну брешу! Усі розробники повинні пам'ятати: завжди перевіряйте взаємодію між різними стандартами.