Вступление

Стив Маркс недавно обнаружил новую слабость смарт-контрактов. Согласно заголовку этой статьи, ошибка может привести к конфликту хэшей функций с несколькими аргументами переменной длины. Давайте рассмотрим пример, чтобы увидеть уязвимость в действии.

Как мы видим в контракте, если функция addUsers вызывается администратором, массивы admins и regularUsers добавляются к сопоставлениям isAdmin и isRegularUser. Если функция не вызывается администратором, она может быть передана с помощью подписи администратора.

Проблема

Уязвимость можно найти в строке 15 с использованием abi.encodePacked(). Проблема заключается в том, как abi.encodePacked() управляет своими параметрами. Следующие два оператора возвращают одно и то же значение, даже если параметры уникальны.

Учитывая, что разные параметры могут возвращать одно и то же значение, злоумышленник может воспользоваться этим, изменив положение элементов в предыдущем вызове функции, чтобы эффективно обойти авторизацию. Например, если злоумышленник увидел addUser([addr1, addr2], [addr3, <attacker’s address>, addr4], sig), он может позвонить addUser([addr1, addr2, addr3, <attacker’s address>], [addr4], sig). Поскольку возвращаемые значения одинаковы, подпись все равно будет совпадать, что делает злоумышленника администратором. Хотя контракт должен иметь надлежащую защиту от повторного воспроизведения, злоумышленник все же может обойти это впереди.

Исправление

Есть несколько различных способов устранения этой уязвимости. Первый вариант - запретить использование массивов в качестве параметров вместо передачи одного значения. Другой вариант - разрешить только массивы фиксированной длины, поэтому позиции не могут быть изменены. Наконец, мы можем избежать этой уязвимости, просто выбрав использование abi.encode() вместо abi.encodePacked().

использованная литература