Это вторая часть серии «Играем в OpenZeppelin Ethernaut CTF», в которой я объясню, как решить каждую задачу.
Ethernaut — это варгейм на основе Web3/Solidity, созданный OpenZeppelin.
Каждый уровень представляет собой смарт-контракт, который необходимо «взломать». Игра выступает в качестве инструмента для тех, кто заинтересован в изучении ethereum, и как способ каталогизации исторических взломов уровней. Уровни могут быть бесконечными, и игра не требует соблюдения определенного порядка.
Задача №2: Fallout
Чтобы завершить этот уровень, заявите о владении контрактом, приведенным ниже.
Вещи, которые могут помочь
- Solidity Remix IDE
Автор(ы) уровня: Алехандро Сантандер
Изучите контракты
Первое, что мы заметили, это используемая версия компилятора Solidity < 0.8.x
. Это означает, что контракт будет подвержен ошибкам переполнения и недополнения математики.
Этот контракт импортирует и использует библиотеку OpenZeppelin SafeMath, поэтому проблемы переполнения/недополнения должны быть безопасны.
Проблема довольно уникальна, и если вы новичок в теме безопасности Solidity, вам, вероятно, будет трудно понять, как решить эту проблему, но только по одной причине: эта проблема существовала только до Solidity 0.4.22
.
До Solidity 0.4.22
единственным способом определить конструктор для контракта было определение функции с тем же именем, что и сам контракт.
Вы можете представить, что могло пойти не так… вы думаете, что определили функцию-конструктор, которая должна иметь имя контракта, но делаете опечатку при написании… функция никогда не вызывается автоматически, потому что она больше не распознается как конструктор, и поэтому контракт не инициализируется во время создания.
После этой версии Solidity они ввели новое ключевое слово constructor
, чтобы избежать подобной ошибки.
Если вы посмотрите на код, имя контракта Fallout
, но функция конструктора называется Fal1out
. Вы видите опечатку? Они использовали 1 вместо l.
Из-за этой опечатки, когда контракт развернут, функция конструктора никогда не выполняется во время создания, и переменная owner
никогда не обновляется. Это происходит потому, что Fal1out
теперь воспринимается как «обычная» функция.
Код решения
Решение этой задачи довольно простое. Нам просто нужно вызвать функцию Fal1out
, которая никогда не вызывалась.
function exploitLevel() internal override {
vm.startPrank(player);
// Before Solidity 0.4.22 the only way to define a constructor for a contract was to define a function with the same name of the contract itself
// After that version they introduced a new `constructor` keyword to avoid this kind of mistake
// In this case the developer made the mistake to misstype the name of the constructor
// Contract name -> Fallout
// Constructor name -> Fal1out
// The result of this is that the contract was never initialized, the owner was the address(0)
// and we were able to call the `Fal1out` function that at this point is not a constructor (callable only once)
// but a "normal" function. This also mean that anyone can call multiple time this function switching the owner of the contract.
level.Fal1out();
vm.stopPrank();
}
Вы можете прочитать полное решение задачи, открыв Fallout.t.sol
Дальнейшее чтение
- SWC-118 — Неправильное имя конструктора
Отказ от ответственности
Весь код Solidity, практики и паттерны в этом репозитории являются ЧЕРТОВСКИ ВУЛЬГЕРНЫМИ и предназначены только для образовательных целей.
Я не даю никаких гарантий и не несу ответственности за любые потери, понесенные в результате использования этой кодовой базы.
НЕ ИСПОЛЬЗУЙТЕ В ПРОИЗВОДСТВЕ.