Как вырваться из тисков реентерабельных атак на смарт-контракты? PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Как уберечь смарт-контракты от атак с повторным входом?

Время Читать: 6 минут

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

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

Несмотря на то, что это знакомая и широко разрекламированная проблема, появление ошибки повторного входа в смарт-контракты всегда неизбежно. 

Как часто хакеры использовали уязвимость Reentrancy в последние годы? Как это работает? Как удержать смарт-контракты от потери средств из-за ошибок повторного входа? Найдите ответы на эти вопросы в этом блоге.

Итак, вскоре давайте освежим в памяти крупнейшие атаки с повторным входом в память. 

Некоторые из самых печально известных хаков повторного входа в реальном времени 

Атаки с повторным входом, которые вызвали самые разрушительные последствия для проектов, в конечном итоге привели к одному из этих двух или даже к обоим. 

  • Полностью слить эфир со смарт-контрактов
  • Хакеры проникают в код смарт-контракта

Теперь мы можем наблюдать несколько случаев Reentrancy-атак и их последствия. 

2016 июня: DAO атака – 3.54 млн или 150 млн долларов эфира

2020 апреля: Взлом Uniswap/Lendf.Me — 25 миллионов долларов

Май 2021: Взлом BurgerSwap — 7.2 миллиона долларов

Август 2021: Взлом CREAM FINANCE — 18.8 млн долларов

Мар 2022: Ола Финанс – 3.6 млн долларов

Июль 2022: Протокол OMNI — 1.43 млн долларов.

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

Обзор повторной атаки

Как и в названии «Повторное вхождение», которое подразумевает «Повторное вхождение снова и снова». Атака с повторным входом включает два контракта: контракт жертвы и контракт атакующего. 

Контракт злоумышленника использует уязвимость повторного входа в контракте жертвы. Для этого используется функция вывода. 

Контракт злоумышленника вызывает функцию вывода, чтобы вывести средства из контракта жертвы, выполняя повторные вызовы до обновления баланса в контракте жертвы. Контракт жертвы проверит баланс, отправит средства и обновит баланс. 

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

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

Иллюстративный вид Reentrancy Attack

Давайте разберемся с концепцией атаки с повторным входом на упрощенной иллюстрации ниже. 

Вот два контракта: уязвимый контракт и контракт хакера.

Хакерский контракт вызывает отказ от уязвимого контракта. При получении вызова уязвимый контракт проверяет наличие средств в хакерском контракте, а затем переводит средства хакеру. 

Хакер получает средства и реализует резервную функцию, которая снова обращается к уязвимому контракту еще до того, как баланс в уязвимом контракте будет обновлен. Таким образом, повторяя ту же операцию, хакер полностью выводит средства из уязвимого контракта. 

Как уберечь смарт-контракты от атак с повторным входом?

Особенности резервной функции, используемой злоумышленником 

  • Они вызываются извне. Т.е. их нельзя вызвать из контракта они прописаны
  • Безымянная функция
  • Резервная функция не включает в себя произвольную логику.
  • Откат срабатывает, когда ETH отправляется на вложенный в него смарт-контракт, а функция receive() не объявлена.

Анализ атаки повторного входа с технической точки зрения 

Давайте возьмем пример контракта и поймем, как происходит повторная атака.

Злонамеренный контракт

contract Attack {
    DepositFunds public depositFunds;

    constructor(address _depositFundsAddress) {
        depositFunds = DepositFunds(_depositFundsAddress);
    }

    // Fallback is called when DepositFunds sends Ether to this contract.
    fallback() external payable {
        if (address(depositFunds).balance >= 1 ether) {
            depositFunds.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        depositFunds.deposit{value: 1 ether}();
        depositFunds.withdraw();
    }


}

Это контракт злоумышленника, в котором злоумышленник вносит 2ETH. Злоумышленник вызывает функцию снятия в уязвимом контракте. После получения средств от уязвимого контракта срабатывает резервная функция. 

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

Уязвимый контракт

contract DepositFunds {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }


}

Уязвимый контракт имеет 30ETH. Здесь функция remove() отправляет запрошенную сумму злоумышленнику. Поскольку баланс не обновляется, токены повторно передаются злоумышленнику. 

Типы реентерабельных атак

  • Реентерабельность одной функции 
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

msg.sender.call.value(amount)() передает средства, после чего резервная функция контракта злоумышленника снова вызывает метод remove() перед обновлением balances[msg.sender] = 0.

  • Межфункциональный реентерабельность
function transfer(address to, uint amount) external {
   if (balances[msg.sender] >= amount) {
       balances[to] += amount;
       balances[msg.sender] -= amount;
   }
}
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

Кросс-функциональный реентерабельность гораздо сложнее идентифицировать. Разница здесь в том, что резервная функция вызывает передачу, в отличие от повторного входа с одной функцией, где она вызывает изъятие.

Предотвращение атак с повторным входом

Паттерн проверки-эффекты-взаимодействия: Шаблон проверки-эффекты-взаимодействия помогает структурировать функции. 

Программа должна быть закодирована таким образом, чтобы сначала проверять условия. После прохождения проверок должно быть устранено влияние на состояние контрактов, после чего можно вызывать внешние функции. 

function withdraw() external {
   uint256 amount = balances[msg.sender];
   balances[msg.sender] = 0;
   require(msg.sender.call.value(amount)());
}

Переписанный здесь код следует шаблону проверки-эффекты-взаимодействия. Здесь баланс обнуляется перед совершением внешнего звонка. 

Использование модификатора

Модификатор noReentrant, применяемый к функции, гарантирует отсутствие повторных вызовов. 

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

В конце

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

Безопасность средств обеспечивается прямо перед тем, как стать жертвой каких-либо потерь. 

Часто задаваемые вопросы

Что такое реентерабельная атака?

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

Что такое реентерант?

Акт повторного входа означает прерывание выполнения кода и запуск процесса заново, что также известно как повторный вход.

Что такое защита от повторного входа?

Защита от повторного входа использует модификатор, который предотвращает повторный вызов функции. Прочитайте блог выше, чтобы найти пример защиты от повторного входа.

Какие существуют атаки на смарт-контракты?

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

69 Просмотры

Отметка времени:

Больше от Квиллхэш