Добро пожаловать в руководство для начинающих по аудиту смарт-контрактов! Один из лучших способов начать аудит смарт-контрактов — это взглянуть на несколько распространенных типов уязвимостей в смарт-контрактах.
Было бы полезно, если бы у вас уже было базовое понимание языка программирования Ethereum Solidity. Так же мы рассмотрим некоторые коды, написанные нубами-программистами Solidity.
Повторная атака
Реальный сценарий:
Представьте, что у вас есть 50 шоколадок. У вас есть непослушная младшая сестра, которой вы позволили забрать у вас только 2 шоколадки за раз. Вы также не хотите давать ей больше 10 шоколадок в день, опасаясь, что у нее разовьется кариес. Для этого каждый вечер вы считаете, сколько шоколадок осталось у вас. Как вы думаете, это сработает? Или вас взломала бы ваша младшая сестра?
К сожалению, это не сработает! Ваша сестра выясняет, что вы не знаете, сколько у вас шоколадок, пока не наступит вечер. Итак, уже на следующий день ваша младшая сестра приходит к вам 6 раз до вечера и каждый раз берет по 2 шоколадки! Это то, что мы называем атакой с повторным входом.
Здесь вы обновляете количество конфет, которые у вас есть вечером, вместо того, чтобы обновлять количество каждый раз, когда ваша сестра берет у вас 2 шоколада. Это также то, что происходит со смарт-контрактом. Смарт-контракт предполагает определенный баланс, в то время как злоумышленник фактически занят выводом некоторой суммы криптовалюты из контракта несколько раз.
Пример реального кода:
Этот код принадлежит смарт-контракту под названием банковские услуги. Любой может снять эфир с небанковского контракта, если баланс отправителя сообщения (т.е. withdraw
function ) больше или равно запрашиваемой сумме вывода.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Обратите внимание, что есть ключевое слово call, используемое для отправки необходимого количества эфира на сервер. msg.sender
. Злоумышленник может использовать это, создав контракт с именем Thief, в котором он вызывает функцию изъятия в fallback()
функция. А fallback()
Функция в Solidity — это специальная функция, которая выполняется, когда эфир отправляется в смарт-контракт.
Это означает, что злоумышленник может рекурсивно вызывать функцию снятия. Таким образом, перед обновлением смарт-контракта балансы msg.sender
в последней строке кода злоумышленник уже несколько раз выводил эфир. Этого можно было бы избежать, если бы балансы обновлялись до использования ключевого слова call, т.е. проверки-эффекты-взаимодействия шаблону.
Влияние:
Ассоциация первая в истории атака повторного входа произошло в 2016 году в DAO (децентрализованной автономной организации), что привело к взломам примерно на 50 миллионов долларов. Чтобы отменить этот взлом, сообщество Ethereum разделило блокчейн Ethereum, что привело к появлению ETC (Ethereum Classic) и ETH (Ethereum).
Арифметическое переполнение и потеря значимости
Реальный сценарий:
Давайте поиграем в мысленную игру. Он состоит из вращения колеса, и победитель определяется на основе наибольшего числа, которое он может получить при вращении колеса. Колесо промаркировано от 256 до -256.
Правила игры таковы, что указатель у всех игроков стоит на 0 в начале каждого вращения. И игроку разрешено вращаться только в сторону отрицательных чисел. Как вы выиграете эту игру?
Хорошей стратегией для победы в этой игре было бы крутить колесо с такой силой, чтобы колесо вращалось до -256, а затем поворачивалось до 256 за один раз. Это возможно, потому что 256 идет сразу после -256 на колесе. Это то, что мы называем арифметическим недостаточным потоком. А арифметическое переполнение как раз наоборот.
Пример реального кода:
An недолив или перелив происходит, когда арифметическая операция достигает своего минимума или максимума.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
Ассоциация _amount
Параметр функции изъятия представляет собой целое число без знака. Значение сопоставления балансов (которое похоже на словарь в Python или пару ключ-значение в C++ или Java) также является целым числом без знака.
mapping(address => uint256) public balances
Требуемый отчет проверяет, являются ли балансы msg.sender
положительный или нет. Но это утверждение всегда будет верным, даже если сумма больше, чем балансы msg.sender
. Это потому, что оба balances
и _amount
переменные имеют тип целое число без знака, и их арифметический результат (после потери значимости) также будет целым числом без знака!
И, как вы помните, целое число без знака всегда положительно. Это означает, что злоумышленник может вывести неограниченное количество эфира из смарт-контракта! Вы можете найти подробный пример и код реализации этой уязвимости здесь.
Еще одна важная вещь, на которую следует обратить внимание, заключается в том, что арифметическая операция, скажем, между двумя целыми числами без знака также является целым числом без знака. Это может быть опасно, если это упускается из виду в смарт-контрактах, поскольку это может привести к нежелательным нарушениям безопасности!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Как вы могли заметить в приведенном выше примере, оператор if совершенно бессмысленен, поскольку upvote - downvote
всегда будет положительным. И пост будет удален, даже если downvotes
больше upvotes
. Во избежание таких атак рекомендуется использовать компилятор Solidity версии выше, чем 0.8.0.
Влияние:
Монета под названием Монета PoWH был запущен в 2017 году. Хотя это была игра Ponzi, она сама была взломана из-за ошибки арифметического переполнения, которая привела к потере около 866 ETH или 950,000 XNUMX долларов США на тот момент. Об этом можно подробно прочитать здесь.
Должен прочитать: Уроки атаки на Tinyman, крупнейшего DEX на Algorand
Атака на отказ в обслуживании
Реальный сценарий:
Представьте, что вы находитесь в Биткойн-техническом университете. Вроде бы все хорошо, за исключением того, что есть общий обеденный стол для всех. И, к сожалению, мало кто из другого класса всегда успевает занять обеденный стол раньше кого-либо из твоего класса.
В практическом сценарии они отказывают всем в основных услугах, что приводит к потере драгоценного времени. Это то, что мы называем «атакой отказа в обслуживании».
Пример реального кода:
В игре называется Король Эфира, любой может стать королем. Но правило, чтобы стать королем, заключается в том, что человек должен внести больше эфира, чем текущий король. Это можно сделать, позвонив в claimThrone()
Функция контракта Короля Эфира, в котором человек отправляет эфир непосредственно предыдущему королю и становится новым королем.
function claimThrone() external payable { require(msg.value > balance, "Need to pay more to become the king"); (bool sent, ) = king.call{value: balance}(""); require(sent, "Failed to send Ether"); balance = msg.value; king = msg.sender; }
Как вы могли догадаться, этот код уязвим для DoS-атаки, но как? Для этого вам нужно понять, что в Ethereum есть два типа адресов: первый — это адрес внешнего собственный аккаунт или просто адрес кошелька, а второй — адрес договора. Теперь эфир можно отправлять с любого из этих типов адресов.
Если это, эфир будет отправлен по адресу контракта, то контракт станет королем. Но давайте предположим, что этот новый контракт не имеет fallback()
функция, которая необходима, если контракт хочет принять эфир. Затем, если появится новый человек и попытается позвонить claimThrone()
функция, она всегда будет терпеть неудачу!
Обратите внимание, что это также происходит отчасти потому, что claimThrone()
Функция явно проверяет, была ли передача эфира успешной или нет во втором требуемом операторе. Вы можете найти полный код и провести по нему DoS-атаку. здесь.
Также возможно, что код будет уязвим для DoS-атаки, если код имеет цикл по массиву больших размеров. Это происходит потому, что газовый лимит в таких случаях может быть превышен. Вы можете прочитать об этом здесь.
Влияние:
Игра под названием ПравительствоМентальный, который, по-видимому, был схемой Понци, застрял на 1100 эфирах, потому что для обработки выплаты требовалось большое количество газа.
Небезопасная случайность
Реальный сценарий:
Жил-был человек по имени Хески, которого всегда сопровождала его обезьяна Пески. Хески проводил лотереи и получал хорошую прибыль. Однажды Алиса заметила, что Хески пристально смотрит на свою обезьяну Пески. Затем она увидела, как он что-то пишет на листе бумаги и запечатала его в конверт. Заинтересовавшись, она решила продолжить расследование.
Позже тем же вечером Алиса увидела, что победитель лотереи был определен путем публичного вскрытия запечатанного конверта. Наблюдая за ним в течение нескольких дней, Алиса выяснила, что Хески определил выигрышный номер лотереи, глядя на жесты Пески (например, если обезьяна почесала голову, Хески записал 10)! Теперь у Алисы была формула выигрыша в каждой лотерее, и ей нужно было просто купить лотерейный билет с правильным номером!
Хески полагал, что его «случайный» способ определить победителя лотереи невозможно вычислить, но он действительно ошибался.
Пример реального кода:
В этом примере случайное число генерируется на основе хэша комбинации номера блока и временной метки его блока. затем этот хэш присваивается переменной ответа. Теперь любой, кто угадает это (на первый взгляд) случайное число, получит 1 эфир. Думаете, это невозможно взломать?
function guess(uint _guess) public { uint answer = uint( keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) ); if (_guess == answer) { (bool sent, ) = msg.sender.call{value: 1 ether}(""); require(sent, "Failed to send Ether"); } }
Неа! Злоумышленник все еще может угадать это случайное число, просто скопировав код, чтобы сгенерировать значение, присвоенное переменной ответа, и передать ту же переменную ответа в guess()
функция!
guessTheRandomNumber.guess(answer);
Вы можете найти полный код здесь. Чтобы избежать этой атаки, рекомендуется использовать проверяемую случайную функцию, такую как Цепная связь VRF.
Влияние:
Около 400 ETH было потеряно из-за атаки на Умная лотерея Миллиарды договор. Удивительно, но даже сама лотерея контрактов была схемой Понци (ой!).
Манипуляция временем
Реальный сценарий:
Сатоши любит есть печенье. Он любит все виды печенья, которые печет его мама. Но его мать очень строгая и считает, что есть слишком много печенья вредно для него. Поэтому его мать установила правило, что он получит печенье только в 8 часов вечера.
В тот же день в 7:45 Сатоши бежит к маме и просит печенья. Его мать спрашивает: «Который час?»
«Сейчас 8 часов!» – отвечает он.
"Хорошо. Тогда возьми печенье из моего шкафа.
Таким образом, Сатоши смог успешно манипулировать временем на 15 минут, чтобы получить свои печеньки! Какой голодный до печенья парень!
Пример реального кода:
Временной меткой блока можно манипулировать примерно 15 секунд шахтером. Таким образом, майнер может установить благоприятную временную метку и включить свою транзакцию в тот же блок, который он майнит. Функция play()
принадлежит игровому контракту под названием G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Этот контракт вознаграждает 1500 эфира игроку, который первым вызовет функцию игры. Но, как видите, функция play может быть вызвана только в том случае, если метка now или block.timestamp транзакции, которая содержит вызов функции play()
функция, больше, чем эпоха 1640392200.
Майнер может легко манипулировать этой отметкой времени и включить свою транзакцию вызова play()
функция в том же блоке, что он сам является первым игроком. Таким образом гарантируется, что майнер выиграет игру!
Влияние:
Отметка block.timestamp использовалась для генерации случайных чисел в Правительственные и, таким образом, был уязвим для атак манипулирования временем.
Обратитесь в QuillAudits
QuillAudits - это безопасная платформа для аудита смарт-контрактов, разработанная QuillHash
Технологии.
Это платформа аудита, которая тщательно анализирует и проверяет смарт-контракты для проверки уязвимостей безопасности посредством эффективного ручного анализа с помощью инструментов статического и динамического анализа, газоанализаторов, а также ассимуляторов. Кроме того, процесс аудита также включает обширное модульное тестирование, а также структурный анализ.
Мы проводим как аудит смарт-контрактов, так и тесты на проникновение, чтобы найти потенциал
уязвимости безопасности, которые могут нанести ущерб целостности платформы.
Если вам нужна помощь в аудите смарт-контрактов, обращайтесь к нашим специалистам. здесь!
Чтобы быть в курсе нашей работы, присоединяйтесь к нашему сообществу: -
Twitter | LinkedIn | Facebook | Telegram
сообщение Руководство для начинающих по аудиту смарт-контрактов: часть 1 Появившийся сначала на Блог Quillhash.
Источник: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- О нас
- Учетная запись
- адрес
- Все
- уже
- Несмотря на то, что
- анализ
- аудит
- автономный
- начало
- ЛУЧШЕЕ
- Bitcoin
- блокчейн
- Ошибка
- купить
- призывают
- случаев
- Проверки
- классический
- код
- Монета
- сочетание
- Общий
- сообщество
- содержит
- контракт
- контрактов
- печенье
- может
- Создающий
- крипто-
- Текущий
- DAO
- день
- децентрализованная
- Отказ в обслуживании
- подробность
- Dex
- вниз
- легко
- есть
- ETH
- Ether
- Эфириума
- Ethereum blockchain
- Ethereum Классический
- пример
- Эксплуатировать
- конец
- First
- Бесплатно
- функция
- игра
- Игры
- ГАЗ
- порождать
- GitHub
- будет
- хорошо
- инструкция
- мотыга
- взломы
- хэш
- здесь
- Как
- HTTPS
- исследовать
- IT
- Java
- присоединиться
- Прыгать
- Король
- язык
- большой
- линия
- Длинное
- искать
- лотерея
- человек
- миллиона
- мать
- номера
- организация
- бумага & картон
- шаблон
- ОПЛАТИТЬ
- Люди
- кусок
- Платформа
- Играть
- игрок
- Понци
- Ponzi Scheme
- мощностью
- процесс
- Программисты
- Программирование
- что такое варган?
- Reddit.
- обратный
- обзоре
- Награды
- условиями,
- Satoshi
- безопасность
- набор
- умный
- умный контракт
- Смарт-контракты
- So
- основательность
- удалось
- Вращение
- раскол
- и политические лидеры
- заявление
- Стратегия
- успешный
- Успешно
- технологии
- тестов
- Через
- время
- инструменты
- сделка
- банковские услуги
- Университет
- Updates
- ценностное
- Уязвимости
- уязвимость
- Уязвимый
- Кошелек
- Что
- Колесо
- КТО
- выиграть
- Работа
- письмо