Ethernaut Challenge #4 Решение — Телефон

Это четвертая часть серии «Играем в OpenZeppelin Ethernaut CTF», в которой я объясню, как решить каждую задачу.

Ethernaut — это варгейм на основе Web3/Solidity, созданный OpenZeppelin.
Каждый уровень представляет собой смарт-контракт, который необходимо «взломать». Игра выступает в качестве инструмента для тех, кто заинтересован в изучении ethereum, и как способ каталогизации исторических взломов уровней. Уровни могут быть бесконечными, и игра не требует соблюдения определенного порядка.

Задача № 4: Телефон

Чтобы завершить этот уровень, заявите о праве собственности на контракт, приведенный ниже.

Автор уровня: Кайл Райли

Для этого задания наша конечная цель — получить право собственности на контракт.

Изучите контракты

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

Переменная состояния owner инициализируется в constructor. Единственная функция, которая будет обновлять owner — это changeOwner :

function changeOwner(address _owner) public

Это публичная функция, которая принимает только один параметр address _owner.
Если значение tx.origin отличается от msg.sender, она обновит owner с помощью входного параметра функции _owner.

Чтобы решить эту задачу, нам нужно понять, что такое msg.sender и tx.origin.

Если мы посмотрим на страницу документации Block and Transaction Properties из официального документа Solidity, то найдем следующее определение:

tx.origin и msg.sender — это «специальные переменные», которые всегда существуют в глобальном пространстве имен и в основном используются для предоставления информации о блокчейне или являются полезными функциями общего назначения.

Но мы должны обратить внимание на следующее:

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

Что это значит?

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

Сценарий A: Алиса (EOA) вызывает напрямую Telephone.changeOwner(Bob).

Сценарий B: Алиса (EOA) вызывает смарт-контракт Forwarder.forwardChangeOwnerRequest(Bob), который вызовет Telephone.changeOwner(Bob).

Внутри Forwarder.forwardChangeOwnerRequest

Внутри Telephone.changeOwner(Bob).

Это происходит потому, что в то время как tx.origin всегда будет возвращать адрес, создавший транзакцию, msg.sender будет возвращать адрес, совершивший последний внешний вызов.

Код решения

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

contract Exploiter {
    function exploit(Telephone level) public {
        level.changeOwner(msg.sender);
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

И в коде нашего решения просто разверните его и вызовите его

function exploitLevel() internal override {
    vm.startPrank(player, player);

    Exploiter exploiter = new Exploiter();

    vm.stopPrank();
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы обратили внимание на нашу предыдущую статью в блоге, вы уже видели чит-код startPrank. У startPrank есть еще одна перегруженная версия

// Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called
function startPrank(address) external;

// Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input
function startPrank(address, address) external;
Войти в полноэкранный режим Выйти из полноэкранного режима

В данном случае мы используем второй вариант, потому что нам нужно переопределить начальный tx.orgin, который в противном случае будет address(this): адрес самого тестового контракта!

Вы можете прочитать полное решение задачи, открыв Telephone.t.sol

Дальнейшее чтение

  • Свойства блоков и транзакций
  • SWC-115: Авторизация через tx.origin
  • Соображения безопасности о tx.origin из документации Solidity
  • Consensys Ethereum Smart Contract Best Practices: tx.origin
  • Виталик Бутерин: НЕ предполагайте, что tx.origin будет оставаться полезным или значимым

Отказ от ответственности

Весь код Solidity, практики и паттерны в этом репозитории являются ЧЕРТОВСКИ ВУЛЬГЕРНЫМИ и предназначены только для образовательных целей.

Я не даю никаких гарантий и не несу ответственности за любые убытки, понесенные в результате использования этой базы данных.

НЕ ИСПОЛЬЗУЙТЕ В ПРОИЗВОДСТВЕ.

Оцените статью
devanswers.ru
Добавить комментарий