ru
Feedback
Solidity. Смарт контракты и аудит

Solidity. Смарт контракты и аудит

Открыть в Telegram

Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов

Больше
2 597
Подписчики
Нет данных24 часа
Нет данных7 дней
+530 день
Архив постов
Изучаем Foundry На канале у Ильи вышел новый урок про Foundry. Это что-то вроде Hardhat, но для написания тестов используется Solidity. Вот этот видео урок. Я бы, возможно, пропустил его в рамках своего обучения, так как привык к hh и не видел смыла, тогда, изучать его. Если бы не текущие собеседования. В рамках одного из них предлагали скачать архив с файлами для проверки контрактов на уязвимости, и что вы думаете? Проект там был создан для foundry. И мне пришлось в скором темпе перекидывать и адаптировать его под hh, чтобы начать работу. Поэтому, чтобы вам в будущем не "прижало", просто покопайтесь в foundry в ближайшее время и поймите, как там настраиваются проекты. А в следующем посте я напишу, какие у меня возникли трудности с ним. #foundry #forge

Zero trust и постоянные проверки Мне сильно импонирует основная идея блокчейна и разработки смарт контрактов, которая основывается на постоянные проверках любых действий и доступов с минимумом доверия к пользователям. И порой, даже хорошо написанный код без каких-либо видимых ошибок, может привести к взлому, только потому что разработчики просто не подумали сделать дополнительную проверку. Остановитесь и взгляните на код на скрине. Функция позволяет пользователя отменить их транзакции в очереди. Сможете найти там баг? Давайте пройдемся по коду. Пользователь вызывает данную функцию, которая проходит по массиву транзакций, которые должны быть отменены, одновременно проверяя, что transfer.from и msg.sender сходятся. Затем ставит статус транзакции, как "отменена", переводит токены пользователю и порождает событие. И все бы ничего, если бы не одно "но". Решение Тут нет проверки на то, была ли данная транзакцию уже отменена раньше. Другими словами злоумышленник может "залить" в массив одну и туже транзакцию несколько раз, она будет прогоняться через цикл и выводить деньги с контракта. Подробнее об этом можно прочитать тут. Этот баг был вовремя обнаружен и хакер получил 10 000 в качестве вознаграждения. Будьте внимательны и проводите больше времени над раздумьем о дополнительных проверках в коде, особенно там, где есть переводы. #security

Чуть больше о собеседованиях Я никуда не пропал, просто сейчас взял время, чтобы подготовиться к собеседованиям. Обучаться можно постоянно, но мне хотелось узнать, что нужно для получения работы и как проходят интервью. Итак, пара слов о поиске работы и собеседованиях. Я ищу работу в зарубежных компаниях: как на сайтах агрегаторах вакансий, так и на linkedIn, так и просто посещая сайты интересующих компаний. Подаюсь в приоритете на аудитора смарт контрактов, во вторую очередь на блокчейн разработчика. В качестве резюме одна страница pdf с описанием скилов и стека разработки. На данный момент у меня было 3 собеседования вживую. Проходили по скайпу и зуму в вечернее время на английском языке. Спрашивали, в основном, про опыт работы и навыки работы с кодом. Никто не просил писать код в эфире. Также пара компаний выслала тестовые задания: где-то нужно было найти уязвимости, где-то взломать контракт, где-то дописать код по логике. Все достаточно просто, если чуть посидеть. На данный момент, предложений пока не получил. Отказов +5. На что стоит обратить внимание для прохождения собеседования? 1. Стандарты ERC и их уязвимости. Меня спрашивали про ERC20, ERC721 и ERC1155. Как происходит transfer, approve и на что стоит обращать внимание, работая с ними. 2. Прокси контракты. Очень важная часть! Нужно знать про transparent, uups, beacon прокси контракты и их upgradable версии. 3. Openzeppeling. Подключение и настройка. 4. В какой ide работаешь? Далее вопросы про hardhat были. 5. Ethers js и его основные функции: как тестировать контракты. 6. Уязвимости и способы их предотвращения. Достаточно знать самые популярные. 7. Для DAO приложений нужно понимать как происходят голосования и в чем фишка таких контрактов. Пока что, это основные моменты, которые удалось вспомнить. Если уверены в своих силах, то в резюме лучше не писать Junior, а сразу Blockchain Developer (Auditor), так будет больше шансов, что резюме заметят. Только в одной компании спросили, готов ли я получать зарплату в криптовалюте, учитывая, что я нахожусь в России и международные переводы не доступны. Мне было ок. Держу вас в курсе. На днях буду еще заниматься тестовыми заданиями. На их основе составляю список для дальнейшего контента для канала. Не теряйте! Приятной недели и легкого обучения!

Уязвимости с прокси контрактами Мы уже встречали несколько задач, где нужно было знать логическую работу прокси контрактов (и transparent, и uups). А сейчас я, на основе этой статьи, перевел список самых популярных уязвимостей. 1. Не инициализированный контракт Логики. Из предыдущих уроков мы знаем, что конструктор может быть только в контрактах прокси, иначе происходят внутренние ошибки и работа контрактов может нарушиться. Поэтому в контракте Логики вместо конструктора используется функция initialize, которая действует по тому же принципу. Контракт должен быть обязательно инициализирован, иначе это может привести к смене владельца и краже всех средств. Если вы используете библиотеку Initializable.sol от openzeppelin, то проверьте булеву переменную _initialized. Если она вернет вам 0 / false, то контракт еще не инициализирован. 2. Ошибки с переменными в хранилище. На канале уже было несколько постов на эту тему. Основным моментом тут является то, то переменные в обоих контрактах должны быть с одинаковыми названиями и в строгом порядке. 3. Function Clashing Vulnerability. Сложно перевести дословно тут, но суть заключается в том, что селекторы в функциях (те, которые 4 первых байта) могут быть одинаковыми в контрактах прокси и логики. Эту часть уязвимости можно проверить специальными инструментами, типа Slither. 4. Metamorphic Contract Rug Vulnerability. Еще одна уязвимость, которую даже не знаю как перевести правильно. Суть ее заключается в процессе создания адреса контракта с create2, который был представлен в хардфорке EIP-1014. Create2 позволяет деплоить контракт с адресом, который может быть просчитан заранее. К слову, простой create так делать не может. Таким образом можно задеплоить контракт с функцией selfdestruct, а затем уничтожить его и задеплоить на тот же адрес новый контракт с новым функционалом. Вообще, если встретите контракты в сети, которые были созданы с create2, то проверьте их код на наличие selfdestruct() или delegatecall. В случае наличия таковых, контракт может быть создан мошенниками. 5. Delegatecall with Selfdestruct Vulnerability. Тут и так все понятно: допустим, если контракт А имеет функцию delegatecall, а контракт В - selfdestruct(), то есть вероятность уничтожить контракт А и заблокировать всю логику. 6. Delegatecall to Arbitrary Address. Встречается, когда delegatecall передает исполнения из прокси контракта и использует его переменные состояния или другой контекст. Обращайте на это внимание. 7. Проверка на наличие контракта. Когда используется delegatecall, то в нем не существует проверки на наличие контракта, в смысле существует ли он вообще. При этом даже если его нет, вернется true значение! Для этого желательно делать проверку на существование внешнего контракта. Как мы видим из списка, в работе с прокси контрактами первым делом стоит обращать внимание на три вещи: initialize, delegatecall и слоты памяти. Это основные моменты, где кроются уязвимости. #proxy #security

Передача параметров в struct На форуме увидел вопрос-ответ на тему передачи параметров для struct из одного контракта в другой. Сам еще не пробовал, но решил сохранить себе и поделиться тут. Итак, у нас есть контракт и struct, например: interface IExternalContract{ struct one { address user; unit amount; } function callOne(one[] calldata data) external; } и в него из другого контракта нужно передать информацию. Сделать можно так: В нужном контракте дублирует struct и передаем его аргументы с помощью abi.encodeWithSignature: contract YourContract {   address public contractAddr;   constructor(address _contractAddr) {     contractAddr = _contractAddr;   }   function callOne(IExternalContract.one[] calldata data) public {     IExternalContract(contractAddr).callOne(data); } } Кто-то уже имел дело с передачей инфы в struct? Как справлялись? #struct

Как создать подписанное сообщение? Я еще не так хорошо знаком с подписанными сообщениями вне сети (на английском off-chain signed message), но пару слов сказать о них стоит. Подобные сообщения используются для подтверждения владельца, платежа, авторизации и т.д. Вся фишка в том, что вы создаете такое сообщение вне сети Эфира и можете позже отправить его. Или переслать другому пользователю для исполнения, типа как мета-транзакция. По сути, в задаче требовалось создать сообщение с текстом содержащим мое имя и подписать его адресом кошелька, с которого была проведена транзакция-решение для контракта из предыдущего поста. Как я это сделал? Для начала создать в Ремиксе небольшой контракт с двумя функциями, которые позволяют зашифровать мое сообщение с именем. function getHash(string memory str) public pure returns (bytes32) {   return keccak256(abi.encodePacked(str)); } function getEthSignedHash(bytes32 _messageHash) public pure returns (bytes32) {   return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)); }   Затем получил хеш своего имени через getHash(), а также конечный хеш в getEthSignedHash(). После этого нужно зайти в браузер, где у вас установлен Метамаск, с которого деплоили контракт и проводили транзакцию, в моем случае Хром. Далее нажимаем f12 или правую кнопку мыши, выбирая Посмотреть код. Откроется консоль Хрома. Переходим на вкладку Console. Прямо во вкладке ставим курсор и прописываем: hash = "вставляем наш хеш из функции getEthSignedHash()"  Это сохранит в переменную наш хеш. Далее прописываем эту строку: ethereum.enable().then(console.log) Откроется Метамаск и нужно будет подтвердить действие. В консоли отобразится ваш адрес кошелька. Сохраните его в переменную account, как сделали это с hash. Затем прописываем эту строку: ethereum.request({method: “personal_sign”, params: [account, hash]}).then(console.log) Снова появится окошко Метамаска с предложением о подписании сообщения. Подписываете его, нажимая sign. В консоли отобразится хеш вашего подписанного сообщения. Это то, что нам нужно. Теперь этот хеш можно переслать другому человеку, подтверждая, что кошелек действительно принадлежит нам. Надеюсь, эта информация была вам полезна. #sign #message #metamask

Задача с собеседования Вчера был на паре зарубежных собеседований на должность аудитора смарт контрактов. Вопросы довольно однообразные: опыт работы, знание Solidity и уязвимостей, общие принципы эксплойта, работа defi и т.д. В большой минус работает то, что у меня пока нет проектов в web3, которые можно показать. Так же как и нет успешных bug bounties. Тем не менее, опыт в задачах Ethernaut и DVD был оценен. На одном из собеседований была предложена задача из двух частей. В первой нужно было "взломать" контракт и добавить свой адрес в массив. Подтверждением служил хеш транзакции на Etherscan. Во второй - создать подписанное сообщение со своим именем и адресом кошелька, с которого был взлом. Предлагаю вам самим решить задачу. В этот раз без подсказок. И, пожалуйста, не выкладывайте свое решение в комментариях. Так меня попросили в компании. Итак, целью задачи является добавление своего адреса в массив winners. contract Challenge{ address[] public winners; bool lock; function exploit_me(address winner) public{ lock = false; msg.sender.call(""); require(lock); winners.push(winner); } function lock_me() public{ lock = true; } } Задача достаточно легкая. Постом чуть позже расскажу, как создать подписанное сообщение простым способом. Такого на канале еще не было. #task

Задача на день Одна из простых задач, которая однажды появлялась в челленджах Imminefy. Тут требуется завладеть контрактом. Уверен, мы уже все натренировались с задачами ранее, поэтому в решении я буду просто давать наводку, без примера кода. Решение Посмотрите на модификатор и его условия вначале. Затем на функцию statcall(). Вспомните, как можно передать функцию в низкоуровневых вызовах. #task

Task.sol0.03 KB

А что вы думаете о будущем web3? Этот топик совсем не по теме канала, но меня немного бомбит со вчерашнего дня. Вчера в компании разработчиков речь зашла о будущем web3. Меня пытались убедить, что я зря трачу столько сил, чтобы выучить Solidity и получить новую профессию, так как с крахом крупнейших бирж, типа FTX, у многих людей пошатнулась вера в блокчейн и криптовалюты. Компании банкротятся, сотрудников увольняют, криптовалюты скам и т.д. Вообще мне было обидно, что в моем кругу есть настолько узкомыслящие люди, ограничивающие web3 и блокчейн только игрой на бирже и криптой, как таковой. Мои доводы, что текущая "крипто зима" никак не отразилась, например, на IPFS, Chainlink, Immunify и других компаниях не были приняты всерьез. Вот мне и захотелось спросить на канале, а верите ли вы сами в будущее web3, в то, что данная профессия будет востребована?

Два расширения для браузера На просторах Телеграм каналов встретил ссылку на два расширения для браузера, которые помогают быстрее находить адреса и транзакции с какого-либо сайта на популярных площадках, типа etherscan. Суть их довольно проста: допустим на сайте вы наткнулись на адрес контракта. Вы кликаете по нему правой кнопкой мыши, выбираете сайт, на котором хотите просмотреть этот контракт и сразу на него переходите. Довольно удобная штука. Как установить? Идете по этой ссылке и скачиваете репозиторий. Затем распаковываете его на свой компьютер. Далее заходите в браузер (в моем случае Chrome), в правом верхнем углу в меню выбираете пункт Дополнительные инструменты -> Расширения,и уже там кликаете на Загрузить распакованное расширение. Откроется окошко с выбором папки. После всех манипуляций, у вас будет два расширения: для проверки адресов, и для проверки транзакций. #extentions #tools #toolbox

Как создать адрес в сети Эфир на js Попалась интересная статья о том, как с помощью ethers создать валидный адрес с приватным ключом, который потом можно импортировать, например, в Метамаск. Давайте для начала разберемся, как вообще создается подобный адрес. 1. В начале необходимо сгенерировать приватный ключ 64 hex (256 бит / 32 байта). 2. Затем с помощью ECDSA и нашего приватного ключа создается публичный ключ (128 hex, 64 байта). 3. В конце, к нашему публичному ключу применяется keccak256, из чего получается строка в 64 символа (32 байта). К последним 40 символов (20 байт) этой строки добавляется префикс "0х" и получается адрес. Для того чтобы сгенерировать адрес на JavaScript нам потребуется установка node и библиотеки ethers. Как обычно перед стартом проекта мы заходим в нужную папку, открываем из нее консоль и прописываем npm init. Далее создаем файл, например address.js. В файле пишем код (можно скопипастить этот): var ethers = require('ethers');  var crypto = require('crypto'); var id = crypto.randomBytes(32).toString('hex'); var privateKey = "0x"+id; console.log("SAVE BUT DO NOT SHARE THIS:", privateKey); var wallet = new ethers.Wallet(privateKey); console.log("Address: " + wallet.address Сохраняем изменения в файле и прописываем в консоли node address. Если появилась информация с приватным ключом и адресом, то все ок. В противном случае, решfем ошибки. Далее этот адрес можно добавить в Метамаск и импортировать счет, нажав на иконку вашего профиля в правом верхнем углу. #address #metamask #ethers

Мини задача И сразу интересный пример из Твиттера. Взгляните внимательно на код и постарайтесь найти ошибку. Я напишу ответ в
Мини задача И сразу интересный пример из Твиттера. Взгляните внимательно на код и постарайтесь найти ошибку. Я напишу ответ в комментариях для тех, кто хочет сам для начала понять, что не так и потом свериться. Небольшая подсказка: тут потребуется знания стандарта ERC20. #security #erc20

Движемся дальше Очень приятно видеть, что за пару дней к нам пришло еще несколько человек и большое спасибо тем, кто сделал репосты! На этой неделе мы будем решать некоторые задачи по безопасности, также я хочу взглянуть на документацию в ethers, чтобы узнать обо всех доступных функциях, и понемногу затрагивать тему бирж и defi (пока не знаю, с какой стороны, но точно не арбитража и биржевых игр). В целом, продолжаем совершенствовать наши знания. Всем приятной недели и легкого обучения!

Обзор пройденного Мы прошли кучу нового и интересного материала на канале, и пришло время собрать очередной пост с быстрыми ссылками и навигацией. Решение задач Решение задач Ethernaut (1-25) Поиск по хештегам #ethernaut Решение задач Damn Vulnerable Defi (1-10) Поиск по хештегам #dvd #DamnVulnerableDefi Решение задач Capture The Ethers (1-20) Поиск по хештегам #capture #cte Безопасности и оптимизация газа Безопасность и взлом контрактов v1.0 Подсказки по безопасности (9 постов) Поиск по хештегам #security #tip #st Оптимизация газа (18 постов) Поиск по хештегам #gas #optimization #hint Уязвимость в struct Опасность tx.origin Защити свой Метамаск Гайд по проверке контракта (pdf) Работа с памятью Структура / хранение данных Динамические массивы и мэппинги в storage Разбор нюансов Лезем в опкод! (5 постов) Из чего состоит транзакция? (5 постов) Описание Remix Debugger (3 поста) Другое Логические побитовые операции Что такое динамические NFT? MetaMask Flask and Snaps Чтение событий в mainnet Ролевая система (access control) Если захотите поделиться где-нибудь одним из постов, пожалуйста, оставляйте ссылки на канал. Приятного обучения.

Ролевая система (access control) Вчера вышел новый урок на Youtube канале Ильи, который рассказывает нам о ролевой системе в смарт контрактах. Другими словами, нам расскажут, как создать смарт контракт, с помощью которого мы сможем создавать роли для управления функциями в нашем проекте, например, модератора - для вывода средств, админа - для управления модераторами и т.д. Как я понял, это разбор примера контракта от open zeppelin, поэтому его безопасность уже будет на хорошем уровне. Кстати, там по ссылке можно найти примеры и других контрактов для управления доступом: AccessControlCrossChain, AccessControlEnumerable и Ownable2Step. Видео урок Всем приятного просмотра и легкой пятницы!

Из чего состоит транзакция? Часть 5 Узнать публичный ключ не составляет труда, если с аккаунта была хоть раз отправленная какая-либо транзакция, так как raw tx hex уже содержит всю необходимую информацию. Для этих целей мы использовали библиотеку ethereumjs-tx, а также я делился отдельным сервисом, который все это может делать онлайн. С приватным ключом дела обстоят сложнее. В последней задаче CTE Account, где нужно было захватить приватный ключ для отправки транзакций, первым делом мы переходили в etherscan и смотрели транзакции. Разбивая каждую транзакцию на детали (nonce, gasPrice, gasLimit, to, value, data, v, r, s), можно было заметить, что в некоторых из них значения R совпадали. Это могло происходить из-за того, что в формуле случайное число (или nonce) было одинаковым. Для получения приватного ключа из этих транзакций потребуется использовать софт, который работает с ECDSA и может получать данные из хеша. Очень многие источники ссылаются на эту страницу, где при помощи Python пользователь получает приватный ключ из хеша. Я не особо знаком с Питоном, но остальным это может многое объяснить. Надеюсь, сегодня вы чуточку больше узнали о транзакциях вместе со мной. #transaction #rlp #ecdsa

Из чего состоит транзакция? Часть 4 После того, как мы собрали все значения для проведения транзакции, требуется зашифровать ее. Для этого на помощь приходит Recursive Length Prefix (RLP). Помните же формулу генерации транзакции Keccak256(RLP(...))? RLP - это специальный алгоритм для кодирования объектов в чистые байты. Не уверен на все 100%, но в одной из статей я прочитал, что для кодировки в RLP данные уже заранее должны быть преобразованы в HEX формат. И вот, когда мы кодируем информацию о нашей транзакции через RLP мы получаем Raw Tx Hex, то длинное значение из etherscan. А, если прогнать его через kessac256 мы получаем хеш транзакции из 32 байтов. Вот так это и работает. Далее попробуем разобраться, как получить публичный и приватный ключи из транзакций, как было в задачах CTE. #transaction #rlp #ecdsa