Solidity. Смарт контракты и аудит – Telegram
Solidity. Смарт контракты и аудит
2.62K subscribers
246 photos
7 videos
18 files
547 links
Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов
Download Telegram
Безопасность. Внешние вызовы. Часть 4

Учитывайте ошибки внешних вызовов

// плохо

someAddress.send(55);

someAddress.call.value(55)("");
// опасно, так как использует весь газ и не проверяет на ошибки

someAddress.call.value(100)(bytes4(sha3("deposit()")));
// если deposit() получит ошибку, то call() вернет false, но транзакция все равно отправит деньги

// хорошо

(bool success, ) = someAddress.call.value(55)("");
if(!success) {
    // handle failure code
}

Всегда проверяйте успешность низкоуровневых вызовов!

#безопасность #externalcall #external
👍1
Безопасность. Внешние вызовы. Часть 5

Используйте "запросы" вместо "автоматики"

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

Этот подход также помогает оптимизировать расход газа в контракте.

Не используйте delegatecall

delegatecall вообще опасная штука. Разбор кода со взломом контракта через этот метод есть на канале. Если вы на 100% не уверены, что и как будет выполнять функция с ним, то старайтесь не использовать его совсем.

Помните, что delegatecall выполняет сторонние функции внутри вашего контракта.

#безопасность #externalcall #external
👍1
Безопасность. Инварианты

Попытаюсь объяснить простым языком: существуют переменные, которые должны быть неизменными (инварианты), типа как totalSupply в ERC20. Т.е. когда бы мы к ней не обратились, она будет иметь такое же значение.

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

Вот тут и кроется уязвимость. Дело в том, что хакер может послать эфир на счет этого контракта, и тот примет его в любом случае, даже если будет fallback функция с revert.

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

Подробнее тут.

#безопасность #invariant
👍1
Безопасность. Ограничения и проверки

Помните, что смарт контракты должны создаваться по принципу zero-trust или ноль доверия. Поэтому каждое действие, которое вы хотите выполнять от имени администратора, должно содержать проверку на это.

Так же и с другими функциями: давайте доступ к ним только тем людям (адресам), которые по логике должны его иметь, как например, голосование по вашему контракту должно быть доступно только его разработчикам или сотрудникам компании.

Более того в работе с переводами обязательно должны существовать свои ограничения.

Например, деньги можно переводить в определенный срок (в течение пары дней до \ после голосования), или только определенную сумму в промежутке от и до, и т.д.

В общем, проверки и условия наше все!

#безопасность
👍1
Безопасность. Атаки reentrancy и DoS

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

Есть прекрасное видео, где лектор подробно рассказывает и показывает про самую распространенную атаку reentrancy, а также Dos или Denial of Service.

Новый видео урок.

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

Приятного дня и легкого обучения.

#reentrancy #dos #безопасность
👍1
Безопасность. Атаки honeypot, delegatecall и oracle manipulation

Я сейчас вспомнил, что на канале ранее мы уже затрагивали тему двух видов атак. Там все рассказано более чем подробно, поэтому предлагаю пересмотреть их еще раз:

Honeypot - https://news.1rj.ru/str/solidityset/204

Атаки через delegatecall (видео, начиная с 12:30) - https://news.1rj.ru/str/solidityset/116

Также тут еще хотел бы рассказать про другую атаку - Oracle Manipulation (Манипуляция Оракулами).

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

Защита очень простая - не городить "свои костыли и оракулы", не пользоваться всего лишь одним-двумя оракулами для получения данных, или в лучшем случае использовать профессиональные сервисы, типа Chainlink.

#honeypot #delegatecall #oracle #manipulation #безопасность
👍1
Безопасность. Атака frontrunning (опережение)

В Ethereum все транзакции сначала добавляются в пул, который виден всем участникам сети, а далее майнеры добавляют их в блок в произвольном порядке. Поэтому результат выполнения транзакции не должен зависеть от ее положения в блоке.

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

Частично решит проблему добавление в контракт ограничения на цену газа, но майнеры все равно смогут манипулировать порядком транзакций. Более правильным, но сложным решением будет схема Commit — Reveal, которую мы также рассматривали в одном из прошлых уроков.

#frontrunning #безопасность
👍1
Безопасность. Атака timestamp dependence / time manipulation

В Solidity переменная "now" соответствует глобальной переменной "block.timestamp", которую задает майнер, поэтому ориентироваться на ее в качестве временного показателя нельзя.

Возьмем к примеру контракт:

contract Auction {
    uint jackpot = 100 ether;
    uint public lastBid = 1 ether;

    constructor() public payable {}

    function setBid() public payable {
        require(msg.value >= lastBid);
        if (now%20 == 0){
            msg.sender.transfer(jackpot);
        }
    }
}

Контракт представляет собой гибрид аукциона и лотереи: участники отправляют ставки и выигрывает тот, время ставки которого удовлетворяет определенному условию. Для гарантированного выигрыша майнер может установить подходящее значение "block.timestamp" и смайнить блок со своей выигрышной транзакцией.

#timestamp #time #безопасность
👍1
Безопасность. Атака Arithmetic

Уязвимости целочисленного переполнения, как и в других языках, возникают из-за ограниченного размера памяти, выделенного на переменную. Максимальное значение для переменной типа uint (uint256) равно 2256−1, минимальное — 0. Выйти за эти границы не получится: значение либо обнулится (при переполнении вверх), либо станет максимальным (при переполнении вниз).

Очень хорошо про этот процесс было рассказано в этом видео.

Для примера можно привести такую функцию:

function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
    uint cnt = _receivers.length;
    uint256 amount = uint256(cnt) * _value;
    require(cnt > 0 && cnt <= 20);
    require(_value > 0 && balances[msg.sender] >= amount);

    balances[msg.sender] = balances[msg.sender].sub(amount);
    for (uint i = 0; i < cnt; i++) {
        balances[_receivers[i]] = balances[_receivers[i]].add(_value);
        Transfer(msg.sender, _receivers[i], _value);
    }
    return true;
}

Функция batchTransfer() перечисляет заданное в _value количество ether на адреса из массива _receivers. Обрати внимание на строку вычисления amount, переполнение в которой никак не проверяется. Если задать значение _value равным 2256 / _receivers.length, то в результате переполнения amount примет значение 0. Обе проверки далее пройдут успешно, в том числе и проверка того, что баланс отправителя больше amount. В итоге балансы получателей будут пополнены на величину _value. Если получателей было два, то каждый из них получит по

2^256/2=2^255=0x8000000000000000000000000000000000000000000000000000000000000000 токенов.

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

#arithmetic #time #безопасность
👍1
Безопасность. Атака Short Address

Для вызова функций контрактов используется ABI (Application Binary Interface) — бинарный интерфейс приложения, согласно которому вызов функции представляется в виде последовательности байтов. Первые четыре байта — это начало хеша keccak256 от подписи функции (ее название и типы входных данных), далее идут значения входных параметров.

function transfer(address to, uint amount) public returns (bool success);

Адрес в Ethereum состоит из 20 байт. Для осуществления атаки злоумышленнику нужно сгенерировать адрес, который заканчивается на нулевой байт, например abcdabcdabcdabcdabcdabcdabcdabcdabcdab00. В обычном случае вызов функции на перевод 1 ether будет выглядеть так (вертикальной чертой разделены составляющие последовательности):

a9059cbb|000000000000000000000000abcdabcdabcdabcdabcdabcdabcdabcd
abcdab00|000000000000000000000000000000000000000000000000000
0000000000001

Но если указать адрес abcdabcdabcdabcdabcdabcdabcdabcdabcdab без последнего байта, то недостающий байт адреса будет взят из следующего аргумента (amount), а в конец EVM допишет нулевой байт:

a9059cbb|000000000000000000000000abcdabcdabcdabcdabcdabcdabcdabcd
abcdab|00000000000000000000000000000000000000000000000000000
0000000000100

Получается, вместо 1 ether жертва отправит 0x100=256 ether. Защититься от такой атаки поможет только тщательная проверка параметров перед загрузкой их в блокчейн.

#shortaddress #безопасность
👍1
Безопасность. Атака force feeding

Одна из атак, которая далась мне сложно для понимания, пока я не встретил этот код контракта.

Представим, что у нас есть игра, где каждый участник может вносить по 1 Эфиру. Тот, кто внесет Эфир 7 по счету - забирает джекпот. Уязвимость здесь кроется в "address(this).balance" - проверке условия основанной на балансе контракта.

contract EtherGame {
    uint public targetAmount = 7 ether;
    address public winner;
    function deposit() public payable {
        require(msg.value == 1 ether, "You can only send 1 Ether");
        uint balance = address(this).balance;
        require(balance <= targetAmount, "Game is over");
        if (balance == targetAmount) {
            winner = msg.sender;
        }
    }

    function claimReward() public {
        require(msg.sender == winner, "Not winner");
        (bool sent, ) =
msg.sender.call{value: address(this).balance}("");
        require(sent, "Failed to send Ether");
    }
}

contract Attack {
    EtherGame etherGame;
    constructor(EtherGame _etherGame) {
        etherGame = EtherGame(_etherGame);
    }
    function attack() public payable {
        address payable addr = payable(address(etherGame));
        selfdestruct(addr);
    }
}

Предположим, что есть два участника, которые уже внесли по 1 Эфиру. И на балансе контракта получается 2 Эфира. Мошенник может через свой контракт отправить 5 Эфиров, чем в итоге вызовет функцию selfdestruct() в контракте игры, и застопорит контракт.

Здесь нужно понимать работу функции selfdestruct() и то, что нельзя полагаться на address(this).balance в каких-либо функциях своего контракта. Просто избегайте этого.

#forcefeeding #безопасность
👍1
Безопасность. Атака griefing

Еще одна атака, которая трудна для понимания с первого раза, и что еще хуже, практически не заметна для новичков.

В ру сегменте я не смог найти достойной статьи про данную атаку, поэтому сделал перевод основной части отсюда.

Griefing Attack или griefing gas attack, как мы поняли из второго названия этой атаки, тесно связана с использованием газа в транзакции в момент вызова функции в другом контракте. Из-за того, что не был установлен и подтвержден лимит газа, мошенник может подключиться к функции и использовать имеющийся газ в своих целях.

Эта атака не столько приносит "радости" мошеннику, сколько может принести убытков атакуемому контракту.

Рассмотрим пример.

contract Relayer {
  function relay (Target target, bytes memory _data) public returns (bool) {
    (bool, success,) = address(target).call(abi.encodeWithSignature("execute(bytes)", _data));
  return success;
  }
}

contract Target {
  bool piblic result = false;
  function execute(bytes memory _data) public {
    uint j = 0;
    for (uint i; i < 100; i++) {
      j++;
    }
    result = true;
  }
  function setresult (bool v) public {
    result = v;
  }
}

Если мы развернем оба контракта и вызовем в первом relay(), то все пройдет успешно. Но если мы попробуем узнать значение переменной result во втором контракте, то оно останется неизменным.

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

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

Как я понял из статьи, на данный момент нет 100% защиты от этой атаки, но ее шансы можно значительно сократить следующим образом.

Во-первых, проверять в первом контракте, что транзакция успешно прошла, например добавить после строки (bool success,) условие "if\else".

Во-вторых, проверять лимит газа. Например так.

В первом контракте ввести две дополнительные переменные:

uint estimateGasValue = 1000000;
uint gasNeededBetweenCalls = 5000;

а затем модифицировать функцию relay():

uint gasAvailable = gasLeft() - gasNeededBetweenCalls;
require (gasAvailable - gasAvailable \ 64 >= estimateGasValue, 'not enough gas provided');
(bool success,) = address(target).call(abi.encodeWithSignature("execute(bytes)", _data, estimateGasValue));

Решения с оценкой газа могут стать не эффективными со временем, когда цена на газ вырастет.

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

#griefing #безопасность
👍1
Smart Contract Security Verification Standard

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

Также есть еще реестр уязвимостей в смарт контрактах с примерами. Кому интересно, можете покопаться на досуге тут.

#безопасность #swc #weakness #standard #security #scsvs
👍1
Безопасность и аудит

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

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


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

1. Посмотрите на популярные уязвимости и пройдитесь по своему коду еще раз.

2. Напишите в контракте комментарии к коду, если вдруг захотите отдать другими людям на проверку.

3. Напишите свои тесты в hardhat (или в той среде, где вы работаете) с solidity coverage на 100%.

4. Запустите быстрые тесты со сторонними программами slither, linters, static analysis и др.).

5. Запустите более продвинутые тесты (echidna, manticore, symbolic execution, MythX).

6. Передайте на аудит, если есть хоть "грамм" сомнений.


Даже все эти шаги не смогут гарантировать 100% безопасность вашего смарт контракта!

#безопасность #тесты
👍1
Подготовка к тестам

Вчера мне потребовалось время, чтобы разобраться с настройкой Python, так как никогда ранее не работал с ним, и появились вопросы по использованию библиотек в проекте. Но сейчас не об этом.

Зачем нам Python в смарт контрактах?

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

Для работающих с Python

Проверьте, чтобы была установлена версия выше 3.10, а также установлен pip3.

Для новичков

1. Для начала нужно скачать сам Python. При этом следите, чтобы версия была ^3.0.

Скачать можно с официального сайта тут (https://www.python.org/downloads/).

2. Затем проверьте, чтобы он у вас правильно установился и имел в своем распоряжении pip3, выполнив команды:

$ python --version
$ pip3 -- version

Там должен появиться номер установленной версии.

3. Далее рекомендуется установить компилятор для Solidity, на случай работы с разными его версиями. Это можно сделать командой:

$ pip3 install solc-select

И вот тут могут пойти проблемы.

У меня постоянно возникала ошибка "running setup.py install for pysha3 did not run successfully". Я попробовал разные советы, которые находил в гугле, но помог только один.

Нужно скачать и установить Visual Studio Build Tools 2022 (пакеты С++).

После этого еще раз попробовать выполнить команду в консоли:

$ pip3 install solc-select

Если и тут не выходит, то попробуйте так:

$ pip3 install solc-select --user

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

#python #pip3
👍1
Подготовка рабочей среды для тестов

Нам потребуются несколько программ для тестов, которые следует установить через консоль. О самих программах в последующих постах подробнее.

Slither - pip3 install slither-analyzer

Mythril - pip3 install mythril

Manticore - pip install manticore

Есть и другие программы, типа Echidna или MythX, но для начала рассмотрим только указанные три.

Проверить правильность их установки можно командой

pip list

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

Для этого создаем файл requirements.txt, куда записываем необходимые программы, которые планируем использовать в своем проекте, по типу:

solc-select== 1.0.1
slither-analyzer==0.9.0

и сохраняем файл. Можно в директории проекта.

Затем выполняем команду для создания виртуального окружения:

python -m venv venv

Потом активируем:

source venv/noscripts/activate

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

И в конце выполняем подключение программ в проект:

pip install -r requirements.txt

Теперь проверить, что все у вас подключилось правильно, можно, выполнив, например, такую команду:

slither --help

Если появятся длинный список команда и опций, то все ок. Если нет - постарайтесь пройти все шаги заново.

#python #pip3 #venv
👍1
Тестирование контрактов в Slither

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

Особенности программы:

- Обнаруживает уязвимый код Solidity с низким уровнем ложных срабатываний.

- Определяет, где конкретно в коде есть такая уязвимость.

- Встроенные "принты" создают отличные отчеты по важным частям кода контракта.

- Анализ кода Solidity выше 0.4 версии

- Средняя скорость выполнения теста всего несколько секунд.

Как работает?

После установки всех библиотек в Python и подключения рабочей среды в проект, вы можете запустить его с помощью команды:

"slither ."

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

Прочитав ошибку, вам станет понятно, на какой строке или в какой функции есть уязвимость.
  
#slither
👍1
Тестирование с Mythril и Manticore

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

Тут надо уточнить, что мне пришлось дополнительно устанавливать Docker для работы, так как bash терминал постоянно выдавал ошибку при запуске Manticore. Как я понял, там идет внутренний конфликт с windows, поэтому пришлось действовать так.

Также Mithril не поддерживает питон 3.10 (макс 3.9), поэтому для него также используется Docker.

Я не хотел бы здесь открывать новые темы изучения Docker и Python: новичкам будет сложно, а продвинутые смогут и сами установить пакеты.

На всякий случай, оставляю здесь ссылки на обе программы:

Manticore - https://github.com/trailofbits/manticore
Mythril - https://github.com/ConsenSys/mythril

Аудит смарт контрактов дело достаточно кропотливое и долгое. В целом, это отдельная профессия со своими навыками, инструментами и практиками.

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

#mythril #manticore
👍1
Всем привет!

Для начала, хотел бы поприветствовать всех новеньких на канале. Тут я пишу про обучение блокчейн разработке, разбираю контракты, проекты и сервисы.

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

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

Как обычно, первым постом на новой неделе делюсь планами обучения.

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

Также на неделе мы разберем несколько интересным моментов в Solidity и попробуем создать полноценные проекты.

Вы также можете предлагать какие-либо темы для разбора на канале (по биржам мы пройдемся чуточку позже).

Легкого дня и приятного обучения.
👍5
Идеи проектов для тренировки. Часть 1

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

1. Создать приложение для голосования, где все происходит в блокчейне. Позволить каждому пользователю начать / запустить голосование с периодом регистрации и временем окончания. Любой пользователь может предложить кандидата в течение периода регистрации. Голосовать можно только одни раз. Также разработайте фронтенд, где голосующие могут увидеть результаты, или сколько времени осталось до конца голосования.

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

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

4. Создайте один NFT с возможностью передачи его один раз в 24 часа. Если пользователь не успевает его передать в течение этого времени, то NFT остается у него навсегда.

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

#практика #идеи
👍1
Идеи проектов для тренировки. Часть 2

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

The Ethernaut - популярный ресурс, который был одним из первых. Выбираете любое задание, читаете описание и пробуете выполнить требующуюся от вас задачу.

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

Кстати, в этом видео уже разбирались некоторые задачи из ethernaut.

Damn Vulnerable DeFi - еще один крутой проект для поиска уязвимостей. Я встречал в нескольких видео рекомендации о нем. Работает так же: выбираете задание, читаете условие и выполняете его.

Rect - интересный проект о блокчейн взломах и безопасности. Многие Телеграм паблики берут самые актуальные новости именно оттуда. К тому же есть русский язык.

Блог Trail if Bits - англоязычный блог от создателей таких крутых сервисов для аудита смарт контрактов, как Slither, Manticore, Mythril и других. Пишут о новых уязвимостях.

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

#практика #идеи #безопасность