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

И сразу интересный пример из Твиттера.

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

Небольшая подсказка: тут потребуется знания стандарта ERC20.

#security #erc20
👍1
Как создать адрес в сети Эфир на 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
👍4
Два расширения для браузера

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

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

Довольно удобная штука.

Как установить?

Идете по этой ссылке и скачиваете репозиторий. Затем распаковываете его на свой компьютер.

Далее заходите в браузер (в моем случае Chrome), в правом верхнем углу в меню выбираете пункт Дополнительные инструменты -> Расширения,и уже там кликаете на Загрузить распакованное расширение. Откроется окошко с выбором папки.

После всех манипуляций, у вас будет два расширения: для проверки адресов, и для проверки транзакций.

#extentions #tools #toolbox
👍1
А что вы думаете о будущем web3?

Этот топик совсем не по теме канала, но меня немного бомбит со вчерашнего дня.

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

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

Вот мне и захотелось спросить на канале, а верите ли вы сами в будущее web3, в то, что данная профессия будет востребована?
👍5
Задача на день

Одна из простых задач, которая однажды появлялась в челленджах Imminefy. Тут требуется завладеть контрактом.

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

Решение

Посмотрите на модификатор и его условия вначале. Затем на функцию statcall(). Вспомните, как можно передать функцию в низкоуровневых вызовах.

#task
Задача с собеседования

Вчера был на паре зарубежных собеседований на должность аудитора смарт контрактов. Вопросы довольно однообразные: опыт работы, знание 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
👍4
Как создать подписанное сообщение?

Я еще не так хорошо знаком с подписанными сообщениями вне сети (на английском 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
👍1
Передача параметров в 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
Уязвимости с прокси контрактами

Мы уже встречали несколько задач, где нужно было знать логическую работу прокси контрактов (и 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
👍3
Чуть больше о собеседованиях

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

Итак, пара слов о поиске работы и собеседованиях.

Я ищу работу в зарубежных компаниях: как на сайтах агрегаторах вакансий, так и на 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), так будет больше шансов, что резюме заметят.

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

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

Приятной недели и легкого обучения!
7👍4
Zero trust и постоянные проверки

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

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

Остановитесь и взгляните на код на скрине. Функция позволяет пользователя отменить их транзакции в очереди. Сможете найти там баг? Давайте пройдемся по коду.

Пользователь вызывает данную функцию, которая проходит по массиву транзакций, которые должны быть отменены, одновременно проверяя, что transfer.from и msg.sender сходятся. Затем ставит статус транзакции, как "отменена", переводит токены пользователю и порождает событие. И все бы ничего, если бы не одно "но".

Решение

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

Подробнее об этом можно прочитать тут. Этот баг был вовремя обнаружен и хакер получил 10 000 в качестве вознаграждения.

Будьте внимательны и проводите больше времени над раздумьем о дополнительных проверках в коде, особенно там, где есть переводы.

#security
👍1
Изучаем Foundry

На канале у Ильи вышел новый урок про Foundry. Это что-то вроде Hardhat, но для написания тестов используется Solidity.

Вот этот видео урок.

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

В рамках одного из них предлагали скачать архив с файлами для проверки контрактов на уязвимости, и что вы думаете? Проект там был создан для foundry. И мне пришлось в скором темпе перекидывать и адаптировать его под hh, чтобы начать работу.

Поэтому, чтобы вам в будущем не "прижало", просто покопайтесь в foundry в ближайшее время и поймите, как там настраиваются проекты. А в следующем посте я напишу, какие у меня возникли трудности с ним.

#foundry #forge
👍1
Возможные проблемы с Foundry

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

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

В видео уроке хорошо объясняются базовые моменты, и упоминается, что перед установкой Foundry на Windows, нужно будет скачать и установить еще две программы.

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

Во-вторых, скачивание пакетов (типа npm). Тут это работает немного по другому. Тут вы скачиваете git репозиторий. Причем не по ссылке, а именно в команде указываете название репозитория на GitHub, например

forge install foundry-rs/forge-std

В-третьих, я еще до конца не разобрался, но, когда вам присылают архив с проектом в Foundry, то вас скорее всего потребуется установить пакеты для его работы. Пример такого проекта на скрине.

В моем есть remappings.txt, где прописаны следующие строки:

@openzeppelin/=lib/openzeppelin-contracts/contracts/
@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@chainlink/=lib/chainlink/

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

А с командой, как показано в документации:

forge install foundry-rs/forge-std (это пример команды)

у меня постоянно возникали две ошибки: первая:

fatal: not a git repository (or any of the parent directories): .git

которая исправилась у меня через git init, и вторая:

This command requires clean working and staging areas, including no untracked files. Modify .gitignore and/or add/commit first, or add
the --no-commit option.

которая решается удалением из папки lib пустой одноименной директории и последующей командой:

forge install foundry-rs/forge-std --no-commit

После этого в lib создастся папка с нужными контрактами и настройками.

Я еще разбираюсь с остальными файлами, и если будут возникать ошибки, отпишусь здесь.

Буду рад советам, если кто-то уже работал с Foundry и может поделиться секретами быстрой настройки и установки.

#foundry #forge
👍4
Задача от Immunefy

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

Что же не так с этим кодом?

Решение

Это прекрасный пример возможности frontrun атаки с кражей личной подписи пользователя. Мы же все помним, что все транзакции изначально попадают в мемпул, откуда их добавляют валидаторы в блокчейн?

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


Все таки у них прикольные задачи! Там еще есть несколько на канале, постепенно разберем их все.

#security #task
👍2
Кратко о Beacon Proxy

Пару раз в контрактах на аудит встречал интеграции openzeppelin с Beacon Proxy. Я знал и работал с transparent и uups, но про beacon ничего не знал. Давайте поговорим о нем немного.

Beacon Proxy - это такой прокси паттерн,в котором несколько прокси контрактов ссылаются на один контракт Исполнения. Например, у вас есть несколько прокси контрактов, и все они работают с одним контрактом, в котором выполняются все действия. Если бы мы использовали uups или transparent, но нам вручную бы пришлось обновлять контракт Исполнения в каждом прокси, что не очень удобно и может занять некоторое время.

С Beacon Proxy мы можем обновить ссылку на адрес контракта Исполнения только в нем, и все остальные прокси контракты "подцепят" это.

Другими словами Beacon Proxy это некая прослойка между прокси контрактами и контрактом Исполнения.

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

#proxy #beacon
🔥3
Нужен совет сообщества

Хочу посоветоваться с вами по поводу материалов на канале.

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

Недавно я решил двигаться в сторону профессии аудитора смарт контрактов и стал все свое время посвящать разборам задач и уязвимостей в коде. Из этих задач я понимаю 95% кода и их логики. Остальные 5% гуглю, и если инфа действительно новая, то делаю посты на канал. И вот, что получается.

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

Поэтому думаю как поступить лучше.

Делать посты реже, но добавлять только новую информацию на канал? Типа как, "Как сделать это?", "Как подключить кошелек?", "Как использовать uniswap?" и т.д.

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

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

Что вы думаете?
По следам вчерашнего поста

Спасибо всем, кто оставил коммент вчера. Я специально подождал сутки, в надежде, что и другие выскажут свое мнение.

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

Всем спасибо! Продолжаем!