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

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

Для начала, если вы зайдете на etherscan и кликните любую транзакцию, то увидите информацию о ней, включая хеш, типа такого:

0xb3e9dad434ce64f0f886e5b3bafced3bc72fee467cf1739d0f8f5a141784fbad

В правом углу транзакции будет небольшое окошко меню, где можно найти дополнительные параметры, одним из которых будет Get Raw Tx Hex. Откроется окно и мы увидим более длинную запись, типа такой:

0xf86d822c858502eeae9847826b6c94388c818ca8b9251b393131c08a736a67ccb192978732bdda0cd1511e8026a0220a666d6dd188222bba14b0f77e378aac1910bba8d646edcd0a90d937cf2f15a07d8396243c8b0ced7d7c955ee27b67a4989e49eaf41aa8396191e0a5a40064db

Все это пригодится нам в разборе транзакции на составные части.

Итак, по сути, транзакция состоит из двух больших захэшированных частей:

1. Информация о транзакции
2. Подпись

Генерируется она по формуле:

Keccak256(RLP(nonce,gasPrice,gasLimit,to,value,data,v,r,s))

Техническую часть о транзакциях можно прочесть в Yellow Pages и EIP-155.

Далее подробнее поговорим подробнее о каждой части.

#transaction #rlp #ecdsa
👍5
Из чего состоит транзакция? Часть 2

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

- Nonce. Значение, которое равняется количеству транзакций, отправленных с данного адреса.

- Gas Price. Цена за газ в Wei.

- Gas Limit. Максимальное количество газа, которое может использоваться в этой транзакции.

- To. Адрес назначения транзакции.

- Amount. Количество Эфира отправляемого в транзакции.

- Data. Опциональное поле, в котором можно передать какие-либо данные для проведения транзакции, в том числе и функцию, которую необходимо выполнить.

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

Далее поговорим о данных v, r и s в формуле.

#transaction #rlp #ecdsa
1👍1
Из чего состоит транзакция? Часть 3

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

Символы v, r и s отвечают за подпись транзакции для ее авторизации / подтверждения. Для генерации подписи используется специальный алгоритм Elliptic Curve Digital Signature Algorithm (ECDSA).

С помощью ECDSA формируются значения для R и S по формуле:

C = kG, r=Cx, s = (e + rd) / k

где k - случайное число, g - точка генерации, e - данные для подписи, d - приватный ключ.

Подробное описание расчетов можно найти в этой статье.

Значение для V можно найти в документации для EIP-155 и рассчитывается по формуле v = CHAIN_ID * 2 + 35.

Chain_Id для всех сетей разный. Так для mainnet он равен 1, для Goerly - 5. Поддерживаемые сети можно найти все в том же документе EIP-155.

Теперь для проведения транзакции у нас есть все значения.

#transaction #rlp #ecdsa
👍2
Из чего состоит транзакция? Часть 4

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

Для этого на помощь приходит Recursive Length Prefix (RLP). Помните же формулу генерации транзакции Keccak256(RLP(...))?

RLP - это специальный алгоритм для кодирования объектов в чистые байты. Не уверен на все 100%, но в одной из статей я прочитал, что для кодировки в RLP данные уже заранее должны быть преобразованы в HEX формат.

И вот, когда мы кодируем информацию о нашей транзакции через RLP мы получаем Raw Tx Hex, то длинное значение из etherscan.

А, если прогнать его через kessac256 мы получаем хеш транзакции из 32 байтов.

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

#transaction #rlp #ecdsa
👍3
Из чего состоит транзакция? Часть 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
👍3
Ролевая система (access control)

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

Как я понял, это разбор примера контракта от open zeppelin, поэтому его безопасность уже будет на хорошем уровне. Кстати, там по ссылке можно найти примеры и других контрактов для управления доступом: AccessControlCrossChain, AccessControlEnumerable и Ownable2Step.

Видео урок

Всем приятного просмотра и легкой пятницы!
👍3
Обзор пройденного

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


Решение задач

Решение задач 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)

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

Приятного обучения.
👍6
Движемся дальше

Очень приятно видеть, что за пару дней к нам пришло еще несколько человек и большое спасибо тем, кто сделал репосты!

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

В целом, продолжаем совершенствовать наши знания.

Всем приятной недели и легкого обучения!
Мини задача

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

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

Небольшая подсказка: тут потребуется знания стандарта 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