Мысли вслух
Как я уже писал ранее, я хочу найти работу в сфере безопасности смарт контрактов и аудита, поэтому начал активно штурмовать эту тему. И столкнулся с небольшой проблемой.
На канале мы разобрали достаточно много материалов по безопасности за последние три недели, включая задачи, подсказки, гайд и оптимизацию газа. Еще раньше я расписывал все возможные атаки на смарт контракты, и то, как подготовить его к аудиту. В общем, очень много всего по данной теме.
И теперь, когда я стараюсь найти что-то новое через гугл, youtube, twitter, то попадается также очень много повторного материала. Те же описания уязвимостей, те же простые примеры атак... Короче, я столкнулся с лимитом общедоступного материала. А повторяться совсем не хочется.
Я пошел немного дальше и залез на форумы специализированных компаний, которые предлагают программы bug bounty и поддерживают форумы для white hat хакеров. И там наткнулся на хороший материал / ссылки / примеры по безопасности.
Я хочу взять небольшой перерыв для изучения, так как сам многое не понимаю, поэтому посты на канале будут выходить чуть реже в последующие пару дней.
Потом нужно будет взять какую-нибудь легкую тему на недельку, типа работы с ethers.js, и поразбирать несколько примеров, как соединять сайт и контракт.
Всем хорошего дня!
Как я уже писал ранее, я хочу найти работу в сфере безопасности смарт контрактов и аудита, поэтому начал активно штурмовать эту тему. И столкнулся с небольшой проблемой.
На канале мы разобрали достаточно много материалов по безопасности за последние три недели, включая задачи, подсказки, гайд и оптимизацию газа. Еще раньше я расписывал все возможные атаки на смарт контракты, и то, как подготовить его к аудиту. В общем, очень много всего по данной теме.
И теперь, когда я стараюсь найти что-то новое через гугл, youtube, twitter, то попадается также очень много повторного материала. Те же описания уязвимостей, те же простые примеры атак... Короче, я столкнулся с лимитом общедоступного материала. А повторяться совсем не хочется.
Я пошел немного дальше и залез на форумы специализированных компаний, которые предлагают программы bug bounty и поддерживают форумы для white hat хакеров. И там наткнулся на хороший материал / ссылки / примеры по безопасности.
Я хочу взять небольшой перерыв для изучения, так как сам многое не понимаю, поэтому посты на канале будут выходить чуть реже в последующие пару дней.
Потом нужно будет взять какую-нибудь легкую тему на недельку, типа работы с ethers.js, и поразбирать несколько примеров, как соединять сайт и контракт.
Всем хорошего дня!
👍6
Как скачать смарт контракт из сети?
Нашел прикольный проект, который позволяет решить эту проблему. Нужно просто скопировать адрес контракта, вставить в поле ввода на сайте и ниже появится его полная версия.
Вот ссылка на проект. Возможно, кому-то однажды пригодится.
P.S. В комментариях Nekto делится еще одной ссылкой на крутой проект Smart Contract Sanctuary.
#download #tools #toolbox
Нашел прикольный проект, который позволяет решить эту проблему. Нужно просто скопировать адрес контракта, вставить в поле ввода на сайте и ниже появится его полная версия.
Вот ссылка на проект. Возможно, кому-то однажды пригодится.
P.S. В комментариях Nekto делится еще одной ссылкой на крутой проект Smart Contract Sanctuary.
#download #tools #toolbox
❤1👍1
Набор ресурсов для разработчика
Еще одна отличная подборка ресурсов / программ / github репо, которые будут полезны для всех, кто работает в сфере блокчейна.
Как я понял это авторская упорядоченная подборка на все случаи жизни.
Тут есть материалы для работы с API, ABI, транзакциями, аналитика и еще куча всего!
Жаль, что пока я не понял, как сохранить все в отдельный файл.
#tools #toolbox
Еще одна отличная подборка ресурсов / программ / github репо, которые будут полезны для всех, кто работает в сфере блокчейна.
Как я понял это авторская упорядоченная подборка на все случаи жизни.
Тут есть материалы для работы с API, ABI, транзакциями, аналитика и еще куча всего!
Жаль, что пока я не понял, как сохранить все в отдельный файл.
#tools #toolbox
👍3❤1
Я тебя по IP вычислю!
А знали ли вы, что закинув NFT на кошелек, можно спокойно вычислить IP пользователя? А вместе с этим и геолокацию, которая порой бывает довольно точна.
Подробная статья на английском языке есть тут. Но я дам краткий пересказ, как это вообще возможно.
Уязвимость кроется в некоторых кошельках, включая Метамаск, которые автоматически "подтягивают" NFT для вашего адреса. К примеру, вы создали NFT или купили его на OpenSea, и через некоторое время он появился у вас на балансе в кошельке.
Так, зная ваш адрес кошелька, хакер может создать NFT, указать url нужный ему и передать права на NFT вам. После этого токен появится в вашем кошельке. А что это значит? То, что Метамаск отправит запрос на url для скачивания картинки, а вместе с этим передаст и ваш IP.
Старая угроза заиграла новыми красками!
#nft #metamask #security
А знали ли вы, что закинув NFT на кошелек, можно спокойно вычислить IP пользователя? А вместе с этим и геолокацию, которая порой бывает довольно точна.
Подробная статья на английском языке есть тут. Но я дам краткий пересказ, как это вообще возможно.
Уязвимость кроется в некоторых кошельках, включая Метамаск, которые автоматически "подтягивают" NFT для вашего адреса. К примеру, вы создали NFT или купили его на OpenSea, и через некоторое время он появился у вас на балансе в кошельке.
Так, зная ваш адрес кошелька, хакер может создать NFT, указать url нужный ему и передать права на NFT вам. После этого токен появится в вашем кошельке. А что это значит? То, что Метамаск отправит запрос на url для скачивания картинки, а вместе с этим передаст и ваш IP.
Старая угроза заиграла новыми красками!
#nft #metamask #security
👍5
Разбор задачи от Immunefi
Нашел в сети небольшую задачу от популярной компании Immunefu, которая занимается безопасностью смарт контрактов.
Предлагаю ее вашему внимаю по этой ссылке. Целю является получить желаемый NFT. Ниже будет представлен разбор решения, поэтому вы сможете сначала сами разобрать его, а потом свериться с ответом.
Переменные, маппинги, модификатор и конструктор довольно стандартные для подобных задач.
Далее идет функция list(), которая создает токен и устанавливает время ставок, и collect(), которая позволяет забрать токен победителю. Обе они защищены модификатором от reentrancy. Да и в целом, выглядят ок.
А вот bid() выглядит очень интересно. 4 проверки в начале и запись ставки для NFT, если ранее такой не существовало.
А если уже есть ставка на данный NFT?
В этом случае идет проверка на сумму ставки, если она меньше предложенной ранее, то идет откат транзакции. Если же больше, то предыдущему владельцу возвращается его Эфир, и уже после записывается новый владелец ставки.
Вот тут и кроется уязвимость! Если ставку предыдущего участника не получается вернуть, то выполнение функции дальше тормозится, и новый адрес установить невозможно. Всего-то останется дождаться конца аукциона и забрать свой приз.
Простой контракт может выглядеть так:
contract Attack {
Auction auction;
constructor (address _auction) {
auction = Auction(_auction);
}
function attack (uint256 _id) external payable {
auction.bid{value:2 ether}(_id);
}
receive() external payable {
revert ("...");
}
}
Это простая DoS атака, при этом интересная задача с аукционом.
#dos #challenge
Нашел в сети небольшую задачу от популярной компании Immunefu, которая занимается безопасностью смарт контрактов.
Предлагаю ее вашему внимаю по этой ссылке. Целю является получить желаемый NFT. Ниже будет представлен разбор решения, поэтому вы сможете сначала сами разобрать его, а потом свериться с ответом.
Переменные, маппинги, модификатор и конструктор довольно стандартные для подобных задач.
Далее идет функция list(), которая создает токен и устанавливает время ставок, и collect(), которая позволяет забрать токен победителю. Обе они защищены модификатором от reentrancy. Да и в целом, выглядят ок.
А вот bid() выглядит очень интересно. 4 проверки в начале и запись ставки для NFT, если ранее такой не существовало.
А если уже есть ставка на данный NFT?
В этом случае идет проверка на сумму ставки, если она меньше предложенной ранее, то идет откат транзакции. Если же больше, то предыдущему владельцу возвращается его Эфир, и уже после записывается новый владелец ставки.
Вот тут и кроется уязвимость! Если ставку предыдущего участника не получается вернуть, то выполнение функции дальше тормозится, и новый адрес установить невозможно. Всего-то останется дождаться конца аукциона и забрать свой приз.
Простой контракт может выглядеть так:
contract Attack {
Auction auction;
constructor (address _auction) {
auction = Auction(_auction);
}
function attack (uint256 _id) external payable {
auction.bid{value:2 ether}(_id);
}
receive() external payable {
revert ("...");
}
}
Это простая DoS атака, при этом интересная задача с аукционом.
#dos #challenge
👍3
Защити свой Метамаск
Мы все знаем про случаи махинаций с криптовалютами и токенами в смарт контрактах. Там были зайдествованы смарт контракты, биржи и обменники. Но мошенники развиваются вместе с нами, и теперь они стали чаще использовать web2 для своих атак. Хочу рассказать вам несколько способов, которые участились в последнее время.
Тут нужно еще пояснить про работу кошелька Метамаск в браузере.
Вы замечали, что для сjdершения транзакций сперва нужно ввести свой пароль и открыть кошелек? До тех пор он остается залочен. И после ввода пароля, он открывается и сайт получает информацию об адресе. А значит может узнать все ваши транзакции, состояние счета и т.д.
Более того, если у вас в одной вкладке открыт кошелек с одним адресом, а потом вы открываете новую вкладку и меняете адрес в кошельке, то все сайты получат доступ к обоим адресам! Поэтому тут надо быть внимательным.
При этом, даже если у вас кошелек залочен, то сайт все равно узнает, что вы пользователь метамаска!
И вот как все это может быть использовано.
1. Уведомление о том, что последняя транзакция не прошла. Такое случается, когда вы заходите на сайт злоумышленника, и там, обычно в правом верхнем углу, всплывает уведомление о не прошедшей транзакции. При этом сумма, цель и другие данные совпадают на 100%! И все потому, что данные в блокчейне открыты. Вы нажимаете на уведомление, открывается Метамаск с предлагается выполнить транзакцию. Понятное дело, адрес уже изменен и деньги будут перенаправлены туда.
2. Уведомление о входящей транзакции. Вам показывается, что кто-то отправил некую сумму и вам нужно ее принять. Вы подписываете транзакцию и деньги с вашего счета исчезают. Тут нужно помнить, что подписываются только исходящие транзакции.
3. Копирование дизайна окна Метамаск. Вы заходите на сайт и через некоторое время появляется окно в точности похожее на окно приложения. Пара просты движений и деньги украдены.
При всех этих махинациях ваш кошелек должен быть разлочен в браузере. Также есть несколько способов и с закрытым кошельком.
4. Уведомление на действие. Для начала каким-либо уведомлением или окном мошенник попытается убедить вас разлочить кошелек. Потом идет одно из вышеперечисленных действий.
5. Окно копирующее Метамаск, куда вас попросят ввести секретную фразу. Тут без комментариев.
6. Временная атака. Сайты могут отлавливать разлочивание кошелька, предлагая потом одно из действий перевода средств.
В общем, не попадайтесь на подобные уведомления и берегите свою секретную фразу.
#безопасность #securiry #metamask
Мы все знаем про случаи махинаций с криптовалютами и токенами в смарт контрактах. Там были зайдествованы смарт контракты, биржи и обменники. Но мошенники развиваются вместе с нами, и теперь они стали чаще использовать web2 для своих атак. Хочу рассказать вам несколько способов, которые участились в последнее время.
Тут нужно еще пояснить про работу кошелька Метамаск в браузере.
Вы замечали, что для сjdершения транзакций сперва нужно ввести свой пароль и открыть кошелек? До тех пор он остается залочен. И после ввода пароля, он открывается и сайт получает информацию об адресе. А значит может узнать все ваши транзакции, состояние счета и т.д.
Более того, если у вас в одной вкладке открыт кошелек с одним адресом, а потом вы открываете новую вкладку и меняете адрес в кошельке, то все сайты получат доступ к обоим адресам! Поэтому тут надо быть внимательным.
При этом, даже если у вас кошелек залочен, то сайт все равно узнает, что вы пользователь метамаска!
И вот как все это может быть использовано.
1. Уведомление о том, что последняя транзакция не прошла. Такое случается, когда вы заходите на сайт злоумышленника, и там, обычно в правом верхнем углу, всплывает уведомление о не прошедшей транзакции. При этом сумма, цель и другие данные совпадают на 100%! И все потому, что данные в блокчейне открыты. Вы нажимаете на уведомление, открывается Метамаск с предлагается выполнить транзакцию. Понятное дело, адрес уже изменен и деньги будут перенаправлены туда.
2. Уведомление о входящей транзакции. Вам показывается, что кто-то отправил некую сумму и вам нужно ее принять. Вы подписываете транзакцию и деньги с вашего счета исчезают. Тут нужно помнить, что подписываются только исходящие транзакции.
3. Копирование дизайна окна Метамаск. Вы заходите на сайт и через некоторое время появляется окно в точности похожее на окно приложения. Пара просты движений и деньги украдены.
При всех этих махинациях ваш кошелек должен быть разлочен в браузере. Также есть несколько способов и с закрытым кошельком.
4. Уведомление на действие. Для начала каким-либо уведомлением или окном мошенник попытается убедить вас разлочить кошелек. Потом идет одно из вышеперечисленных действий.
5. Окно копирующее Метамаск, куда вас попросят ввести секретную фразу. Тут без комментариев.
6. Временная атака. Сайты могут отлавливать разлочивание кошелька, предлагая потом одно из действий перевода средств.
В общем, не попадайтесь на подобные уведомления и берегите свою секретную фразу.
#безопасность #securiry #metamask
👍3
Отслеживание стоимости газа
Встретил интересный сервис, который отслеживает стоимость газа и перекладывает ее на различные графики. Тут можно посмотреть стоимость транзакций (газ и $), среднюю стоимость за час, за день, за квартал и т.д.
В общем еще один инструмент для разработчика.
#tool #toolbox #gas #price
Встретил интересный сервис, который отслеживает стоимость газа и перекладывает ее на различные графики. Тут можно посмотреть стоимость транзакций (газ и $), среднюю стоимость за час, за день, за квартал и т.д.
В общем еще один инструмент для разработчика.
#tool #toolbox #gas #price
👍1
Задачи Capture The Ethers. Lotteries
На досуге я решил пройти CTE, пока разбираю более сложный материал. Буду также делать мини разборы, но без кода. Может совсем новички в Solidity захотят попробовать написать свой код, с небольшой подсказкой направления.
Задача 1
Ответ и так указан в переменной.
Задача 2
uint8 лежит в определенной области чисел (2 ** 8). Нужно перебрать все возможный решения брутфорсом. По сути, одна функция в js файле.
Задача 3
Вытаскиваем значение из нулевого слота памяти.
Задача 4
Нам нужно написать другой контракт, где в функции передать ответ в guess() с точно таким же вычислением answer.
Возможно, эту задачу можно пропустить, так как переделывание ее для 0.8 компилятора может занять у вас время.
Задача 5
Одна из самых глупых задач, которые мне приходилось решать. И не потому что решение сложное, а потому что логика странная. Вам нужно написать контракт и потом тупо ждать, когда ответ совпадет с догадкой.
В общем, нужно написать свой контракт, где передавать в lockInGuess() свой вариант ответа, а также еще одну функцию для атаки, которая будет вызвать settle() и делать проверку на isComplete(), чтобы в случае неудачи Эфир не отсылался и транзакция откатывалась. И потом просто спамить атакой, пока ответ и догадка не совпадут. Глупая задача...
Задача 6
Еще одна задача на ожидание... Вся суть здесь заключается в знании, что возвращает block.blockhash(). Нам нужно установить в lockInGuess() значение из нулей и подождать пока 256 блоков будут созданы.
Заметка от меня
Когда я начинал решать эти задачи, то думал, что они будут немного современнее... Большинство использует 0.4 версию языка, что очень устарело и больше не актуально для 0.8. Даже не знаю, стоит ли решать их дальше...
#capture #cte
На досуге я решил пройти CTE, пока разбираю более сложный материал. Буду также делать мини разборы, но без кода. Может совсем новички в Solidity захотят попробовать написать свой код, с небольшой подсказкой направления.
Задача 1
Ответ и так указан в переменной.
Задача 2
uint8 лежит в определенной области чисел (2 ** 8). Нужно перебрать все возможный решения брутфорсом. По сути, одна функция в js файле.
Задача 3
Вытаскиваем значение из нулевого слота памяти.
Задача 4
Нам нужно написать другой контракт, где в функции передать ответ в guess() с точно таким же вычислением answer.
Возможно, эту задачу можно пропустить, так как переделывание ее для 0.8 компилятора может занять у вас время.
Задача 5
Одна из самых глупых задач, которые мне приходилось решать. И не потому что решение сложное, а потому что логика странная. Вам нужно написать контракт и потом тупо ждать, когда ответ совпадет с догадкой.
В общем, нужно написать свой контракт, где передавать в lockInGuess() свой вариант ответа, а также еще одну функцию для атаки, которая будет вызвать settle() и делать проверку на isComplete(), чтобы в случае неудачи Эфир не отсылался и транзакция откатывалась. И потом просто спамить атакой, пока ответ и догадка не совпадут. Глупая задача...
Задача 6
Еще одна задача на ожидание... Вся суть здесь заключается в знании, что возвращает block.blockhash(). Нам нужно установить в lockInGuess() значение из нулей и подождать пока 256 блоков будут созданы.
Заметка от меня
Когда я начинал решать эти задачи, то думал, что они будут немного современнее... Большинство использует 0.4 версию языка, что очень устарело и больше не актуально для 0.8. Даже не знаю, стоит ли решать их дальше...
#capture #cte
👍1
Задача для самопроверки
Нашел прикольную задачу, по типу которой мы уже однажды разбирали на канале. Хотите сами попрактиковаться?
Ссылка на задачу.
#challenge
Нашел прикольную задачу, по типу которой мы уже однажды разбирали на канале. Хотите сами попрактиковаться?
Ссылка на задачу.
#challenge
Уязвимость в struct
Не довелось мне поработать со struct достаточно хорошо, поэтому следующий баг был для меня в новинку.
Рассмотрим просто контракт:
contract NameRegistrar {
bool public unlocked = false; // registrar locked, no name updates
struct NameRecord {
bytes32 name;
address mappedAddress;
}
mapping(address => NameRecord) public registeredNameRecord;
mapping(bytes32 => address) public resolve;
function register(bytes32 _name, address _mappedAddress) public {
NameRecord newRecord;
newRecord.name = _name;
newRecord.mappedAddress = _mappedAddress;
resolve[_name] = _mappedAddress;
registeredNameRecord[msg.sender] = newRecord;
require(unlocked);
}
}
Ничего странного не замечаете? Ошибок каких? Вроде бы их нет. Но есть один недочет.
Тут в контракте newRecord не инициализируется. Поэтому, когда в последующих строках мы устанавливаем значения:
newRecord.name = _name;
newRecord.mappedAddress = _mappedAddress;
они указывают на 0 и 1 слот в памяти, что приводит к установке значений в unlocked. И если мы передадим нужное значение в _name, то можно установить его, как true.
Так можно взломать этот контракт.
Вернее было бы оформить запись в struct так:
NameRecord memory newRecord = NameRecord({name: _name, mappedAddress: _mappedAddress});
Лично я не знал, что в этом случае структура может указывать на слоты памяти переменных. Поэтому важно инициализировать правильно.
Компилятор может указать вам на этот недочет, а в некоторых случая и остановить компиляцию контракта. Будьте внимательны со struct.
#struct #security
Не довелось мне поработать со struct достаточно хорошо, поэтому следующий баг был для меня в новинку.
Рассмотрим просто контракт:
contract NameRegistrar {
bool public unlocked = false; // registrar locked, no name updates
struct NameRecord {
bytes32 name;
address mappedAddress;
}
mapping(address => NameRecord) public registeredNameRecord;
mapping(bytes32 => address) public resolve;
function register(bytes32 _name, address _mappedAddress) public {
NameRecord newRecord;
newRecord.name = _name;
newRecord.mappedAddress = _mappedAddress;
resolve[_name] = _mappedAddress;
registeredNameRecord[msg.sender] = newRecord;
require(unlocked);
}
}
Ничего странного не замечаете? Ошибок каких? Вроде бы их нет. Но есть один недочет.
Тут в контракте newRecord не инициализируется. Поэтому, когда в последующих строках мы устанавливаем значения:
newRecord.name = _name;
newRecord.mappedAddress = _mappedAddress;
они указывают на 0 и 1 слот в памяти, что приводит к установке значений в unlocked. И если мы передадим нужное значение в _name, то можно установить его, как true.
Так можно взломать этот контракт.
Вернее было бы оформить запись в struct так:
NameRecord memory newRecord = NameRecord({name: _name, mappedAddress: _mappedAddress});
Лично я не знал, что в этом случае структура может указывать на слоты памяти переменных. Поэтому важно инициализировать правильно.
Компилятор может указать вам на этот недочет, а в некоторых случая и остановить компиляцию контракта. Будьте внимательны со struct.
#struct #security
🤯2
Опасность tx.origin
Много раз слsшал и сам писал на канале, чтобы никто не использовал tx.origin в своих контрактах.
Я сейчас нашел хороший пример, где показана его уязвимость.
Вот есть контракт:
contract Phishable {
address public owner;
constructor (address _owner) {
owner = _owner;
}
function () public payable {} // collect ether
function withdrawAll(address _recipient) public {
require(tx.origin == owner);
_recipient.transfer(this.balance);
}
}
И вот пример контракта хакера:
contract AttackContract {
Phishable phishableContract;
address attacker;
constructor (Phishable _phishableContract, address _attackerAddress) {
phishableContract = _phishableContract;
attacker = _attackerAddress;
}
function () payable {
phishableContract.withdrawAll(attacker);
}
}
Если каким-то образом хакер убедит пользователя прислать ему некую сумму, то второй подпишет себе приговор на вывод всех средств.
Да, это пример, где от хакера требуются дополнительные действия для убеждения жертвы, но все же опасность tx.origin показана превосходно.
#security #txorigin
Много раз слsшал и сам писал на канале, чтобы никто не использовал tx.origin в своих контрактах.
Я сейчас нашел хороший пример, где показана его уязвимость.
Вот есть контракт:
contract Phishable {
address public owner;
constructor (address _owner) {
owner = _owner;
}
function () public payable {} // collect ether
function withdrawAll(address _recipient) public {
require(tx.origin == owner);
_recipient.transfer(this.balance);
}
}
И вот пример контракта хакера:
contract AttackContract {
Phishable phishableContract;
address attacker;
constructor (Phishable _phishableContract, address _attackerAddress) {
phishableContract = _phishableContract;
attacker = _attackerAddress;
}
function () payable {
phishableContract.withdrawAll(attacker);
}
}
Если каким-то образом хакер убедит пользователя прислать ему некую сумму, то второй подпишет себе приговор на вывод всех средств.
Да, это пример, где от хакера требуются дополнительные действия для убеждения жертвы, но все же опасность tx.origin показана превосходно.
#security #txorigin
Capture The Ether. Math
Я все таки решил просмотреть задачи до конца, чтобы знать другие возможности по уязвимости контрактов, которые могут перетечь в более современные версии.
Задача 1
Простое задание на overflow. Мы вызываем перегрузку числа через 2256–1 / 1018, рассчитываем, сколько нужно передать wei, и взываем функции в контракте buy() и sell().
Такая перегрузка уже не актуальна для Solidity 0.8.
Задача 2
Еще один underflow с подключением стороннего кошелька для проведения транзакций, для которого делаете approve() на проведение транзакций. Затем используете баг в _transfer(), перегружая чужой кошелек, и затем перекидываете себе 1 млн токенов.
Задача 3
Тут условия задачи поначалу меня немного смутили. За кого я должен играть? За пользователя, который положил Эфир и хочет снять его без комиссии пораньше, или за другого пользователя, который получает комиссию? Все решилось пока я не нашел строчку с расчетом суммы снятия в collectPenalty(). Очередной overflow.
Нужно лишь каким-то образом пополнить баланс контракта. Может selfdestruct()?
Задача 4
Эта задание также не актуально для версий старше 0.6. Здесь нужно знать, что через переполнение динамического массива можно получить доступ к слотам памяти и переписать их. Подобную задачу мы решали в ethernaut.
Задача 5
Только вчера я делал пост про уязвимость в struct, и вот столкнулся с задачей, где это показывается. Все как и в посте: donate() делает запись не структуры, а именно слотов памяти. Осталось только правильно отформатировать наш адрес, чтобы он сохранился в слот owner.
От меня
последнюю задачу решим вместе с другим блоком. Она объединяет несколько способов взлома из предыдущих задач. Тоже все понятно, но, возможно, придется чуть более подробно ее расписать.
#capture #cte
Я все таки решил просмотреть задачи до конца, чтобы знать другие возможности по уязвимости контрактов, которые могут перетечь в более современные версии.
Задача 1
Простое задание на overflow. Мы вызываем перегрузку числа через 2256–1 / 1018, рассчитываем, сколько нужно передать wei, и взываем функции в контракте buy() и sell().
Такая перегрузка уже не актуальна для Solidity 0.8.
Задача 2
Еще один underflow с подключением стороннего кошелька для проведения транзакций, для которого делаете approve() на проведение транзакций. Затем используете баг в _transfer(), перегружая чужой кошелек, и затем перекидываете себе 1 млн токенов.
Задача 3
Тут условия задачи поначалу меня немного смутили. За кого я должен играть? За пользователя, который положил Эфир и хочет снять его без комиссии пораньше, или за другого пользователя, который получает комиссию? Все решилось пока я не нашел строчку с расчетом суммы снятия в collectPenalty(). Очередной overflow.
Нужно лишь каким-то образом пополнить баланс контракта. Может selfdestruct()?
Задача 4
Эта задание также не актуально для версий старше 0.6. Здесь нужно знать, что через переполнение динамического массива можно получить доступ к слотам памяти и переписать их. Подобную задачу мы решали в ethernaut.
Задача 5
Только вчера я делал пост про уязвимость в struct, и вот столкнулся с задачей, где это показывается. Все как и в посте: donate() делает запись не структуры, а именно слотов памяти. Осталось только правильно отформатировать наш адрес, чтобы он сохранился в слот owner.
От меня
последнюю задачу решим вместе с другим блоком. Она объединяет несколько способов взлома из предыдущих задач. Тоже все понятно, но, возможно, придется чуть более подробно ее расписать.
#capture #cte
👍1
Capture The Ether. Fifty Years
Да уж, заставила эта задача посидеть несколько часов, чтобы понять ее логику.
Сам я не решил ее, поэтому пошел гуглить ответы, которые были в нескольких вариациях. И вот уже над ними просидел столько времени.
Я сам сразу понял, что вся уязвимость кроется в upsert() else логике, вот только исполнить ее не мог. Вот сам контракт и вот эта функция:
function upsert(uint256 index, uint256 timestamp) public payable {
require(msg.sender == owner);
if (index >= head && index < queue.length) {
Contribution storage contribution = queue[index];
contribution.amount += msg.value;
} else {
require(timestamp >= queue[queue.length - 1].unlockTimestamp + 1 days);
contribution.amount = msg.value;
contribution.unlockTimestamp = timestamp;
queue.push(contribution);
}
}
Как мы видим из контракта, msg.value переписывает первый слот памяти, где лежит длина массива, а timestamp - второй слот (head), который защищает от цикла повторного вывода денег с массива.
Что нужно тут понимать?
Во-первых, принципы работы overflow.
Нам нужно каким-то образом записать в timestamp значение 0. Но просто так этого мы сделать не можем, будет выдавать ошибку. Поэтому нам нужно для начала создать переполнение чисел uint256 (2256 - 1), а в нашем случае минус один день, т.е. (2256-86400 секунд). И уже только после этого действия (транзакции), мы сможем записать "0" в timestamp второй транзакцией, что также обновить head до 0 (каким он и должен быть!).
Во-вторых, msg.value обновляет длину массива, поэтому нам нужно отправлять не по одному Эфиру (10**18), а по 1 Wei, тогда каждый wei будет равен размерности длины массива.
В-третьих, когда выполняется действие queue.push(contribution) в данном примере, в массив записывается значение msg.value, которое мы отправляем в Wei и еще "+1". Другими словами, после того как мы в первый раз отправим транзакцию и передадим 1 Wei, то на балансе контракта будет 1 Эфир и 1 Wei, а в массиве 1 Эфир и 2 Wei.
При этой, учитывая, что длина массива на момент получения транзакций уже будет равна "1", и мы, как бы отправляя 1 Wei, пытаемся перезаписать это значение, то благодаря push, который увеличивает длину массива на 1, ошибки не будет. И длина массива всегда будет плюсоваться.
Представляю, что из моего текста это тоже звучит мало понятно, поэтому вот вам две ссылки на английском языке, которые помогут разобраться с этой задачей. Первая и вторая. Но придется тоже посидеть.
Для решение этой задача нам нужно будет отправить несколько транзакций, постепенно увеличивая количество отправляемых Wei на +1, и переписывая overflow timestamp с "2**256-86400" до "0" до "86400", и так по кругу.
Потом мы сможем вызвать withdraw() и забрать некоторое количество Wei и Эфир.
Теперь понимаю, почему эта задача является самой дорогостоящей среди заданий CTE.
#capture #cte
Да уж, заставила эта задача посидеть несколько часов, чтобы понять ее логику.
Сам я не решил ее, поэтому пошел гуглить ответы, которые были в нескольких вариациях. И вот уже над ними просидел столько времени.
Я сам сразу понял, что вся уязвимость кроется в upsert() else логике, вот только исполнить ее не мог. Вот сам контракт и вот эта функция:
function upsert(uint256 index, uint256 timestamp) public payable {
require(msg.sender == owner);
if (index >= head && index < queue.length) {
Contribution storage contribution = queue[index];
contribution.amount += msg.value;
} else {
require(timestamp >= queue[queue.length - 1].unlockTimestamp + 1 days);
contribution.amount = msg.value;
contribution.unlockTimestamp = timestamp;
queue.push(contribution);
}
}
Как мы видим из контракта, msg.value переписывает первый слот памяти, где лежит длина массива, а timestamp - второй слот (head), который защищает от цикла повторного вывода денег с массива.
Что нужно тут понимать?
Во-первых, принципы работы overflow.
Нам нужно каким-то образом записать в timestamp значение 0. Но просто так этого мы сделать не можем, будет выдавать ошибку. Поэтому нам нужно для начала создать переполнение чисел uint256 (2256 - 1), а в нашем случае минус один день, т.е. (2256-86400 секунд). И уже только после этого действия (транзакции), мы сможем записать "0" в timestamp второй транзакцией, что также обновить head до 0 (каким он и должен быть!).
Во-вторых, msg.value обновляет длину массива, поэтому нам нужно отправлять не по одному Эфиру (10**18), а по 1 Wei, тогда каждый wei будет равен размерности длины массива.
В-третьих, когда выполняется действие queue.push(contribution) в данном примере, в массив записывается значение msg.value, которое мы отправляем в Wei и еще "+1". Другими словами, после того как мы в первый раз отправим транзакцию и передадим 1 Wei, то на балансе контракта будет 1 Эфир и 1 Wei, а в массиве 1 Эфир и 2 Wei.
При этой, учитывая, что длина массива на момент получения транзакций уже будет равна "1", и мы, как бы отправляя 1 Wei, пытаемся перезаписать это значение, то благодаря push, который увеличивает длину массива на 1, ошибки не будет. И длина массива всегда будет плюсоваться.
Представляю, что из моего текста это тоже звучит мало понятно, поэтому вот вам две ссылки на английском языке, которые помогут разобраться с этой задачей. Первая и вторая. Но придется тоже посидеть.
Для решение этой задача нам нужно будет отправить несколько транзакций, постепенно увеличивая количество отправляемых Wei на +1, и переписывая overflow timestamp с "2**256-86400" до "0" до "86400", и так по кругу.
Потом мы сможем вызвать withdraw() и забрать некоторое количество Wei и Эфир.
Теперь понимаю, почему эта задача является самой дорогостоящей среди заданий CTE.
#capture #cte
👍1
Capture The Ether. Accounts
Задача 1
Для того, чтобы решить эту задачу нужно пройти два условия: переделать имя smarx в значение bytes32 и подобрать адрес, внутри которого будут символы "badc0de".
Задача покажется не такой уж сложной, если вспомнить одну из предыдущих, где мы генерировали адреса контрактов.
Первое условие решается строкой return bytes32("smarx"), а для второго - только брутфорс, или перебор адресов.
Мы же помним как в старых задачах генерируются новые адреса? Конечно, на основе текущего и nonce по формуле:
address(keccak256(0xd6, 0x94, _addr, nonce))
и простая функция для перебора может выглядеть так:
function bruteforce (address _addr, uint8 nonce) returns (address) {
return address(keccak256(0xd6, 0x94, _addr, nonce));
}
Выполнив ее некоторое количество раз, можно подобрать адрес, внутри которого и будут символы "badc0de".
Задача 2
Интересная задача, не столько на взлом, сколько на знание основ работы сети Эфира. Здесь нам нужно узнать публичный ключ для подписи транзакций.
Тут есть варианты получения hex транзакции с etherscan или других сервисов, которые позволяют просмотреть действия на адресе.
Нужно найти адрес или контракт, открыть его транзакции и нажать на кнопку "Get Raw Transaction Hex". Там вы получите длинный набор символов.
Используя ethereumjs-tx мы можем получить публичный ключ из hex транзакции. Для этого создадим новый js и пропишем:
require EtX = require('ethereumjs-tx');
const rawTx = 'hexTx';
console.log('0x'+new EthereumTx(rawTx).getSenderPublicKey().toString('hex'));
Используя эту библиотеку, можно в rawTx передать и информацию о транзакции в формате:
let rawTx = {
nonce: '0x00',
gasPrie: 1000000,
gasLimit: ...
}
let tx = new EthereumTx(rawTx);
console.log('0x'+tx.serialize().toString('hex'));
Оставлю тут ссылку на саму библиотеку в npm.
Задача 3
В задаче нужно отправить транзакцию от имени владельца. Честно признаться, я так и не понял как решить эту задачу, в том смысле, что тут скорее нужно хорошо понимать, как подписываются транзакции в блокчейне. Эту тему я оставил на дополнительное изучение.
#capture #cte
Задача 1
Для того, чтобы решить эту задачу нужно пройти два условия: переделать имя smarx в значение bytes32 и подобрать адрес, внутри которого будут символы "badc0de".
Задача покажется не такой уж сложной, если вспомнить одну из предыдущих, где мы генерировали адреса контрактов.
Первое условие решается строкой return bytes32("smarx"), а для второго - только брутфорс, или перебор адресов.
Мы же помним как в старых задачах генерируются новые адреса? Конечно, на основе текущего и nonce по формуле:
address(keccak256(0xd6, 0x94, _addr, nonce))
и простая функция для перебора может выглядеть так:
function bruteforce (address _addr, uint8 nonce) returns (address) {
return address(keccak256(0xd6, 0x94, _addr, nonce));
}
Выполнив ее некоторое количество раз, можно подобрать адрес, внутри которого и будут символы "badc0de".
Задача 2
Интересная задача, не столько на взлом, сколько на знание основ работы сети Эфира. Здесь нам нужно узнать публичный ключ для подписи транзакций.
Тут есть варианты получения hex транзакции с etherscan или других сервисов, которые позволяют просмотреть действия на адресе.
Нужно найти адрес или контракт, открыть его транзакции и нажать на кнопку "Get Raw Transaction Hex". Там вы получите длинный набор символов.
Используя ethereumjs-tx мы можем получить публичный ключ из hex транзакции. Для этого создадим новый js и пропишем:
require EtX = require('ethereumjs-tx');
const rawTx = 'hexTx';
console.log('0x'+new EthereumTx(rawTx).getSenderPublicKey().toString('hex'));
Используя эту библиотеку, можно в rawTx передать и информацию о транзакции в формате:
let rawTx = {
nonce: '0x00',
gasPrie: 1000000,
gasLimit: ...
}
let tx = new EthereumTx(rawTx);
console.log('0x'+tx.serialize().toString('hex'));
Оставлю тут ссылку на саму библиотеку в npm.
Задача 3
В задаче нужно отправить транзакцию от имени владельца. Честно признаться, я так и не понял как решить эту задачу, в том смысле, что тут скорее нужно хорошо понимать, как подписываются транзакции в блокчейне. Эту тему я оставил на дополнительное изучение.
#capture #cte
Capture The Ether. Miscellaneous
Задача 1
Тут нужно захватить ownership.
Такие задачи мы уже решали. Обратите внимание на написание функции, которая должна выполнять роль конструктора. Нам не потребуется даже писать другой контракт.
Задача 2
Пример контракта на атаку reentrancy.
Здесь нужно знать различия ERC20 и ERC223, которое заключается в том, что при отправке токенов вызывается дополнительная функция tokenFallback(). Из этого можно подготовить атаку.
Создать контракт и от его имени пополнить банк на весь доступный баланс токенов (500к). Создать свою функцию tokenFallback(), которая будет отправлять дополнительный запрос на вывод средств. Затем просто вызвать withdraw().
#capture #cte
Задача 1
Тут нужно захватить ownership.
Такие задачи мы уже решали. Обратите внимание на написание функции, которая должна выполнять роль конструктора. Нам не потребуется даже писать другой контракт.
Задача 2
Пример контракта на атаку reentrancy.
Здесь нужно знать различия ERC20 и ERC223, которое заключается в том, что при отправке токенов вызывается дополнительная функция tokenFallback(). Из этого можно подготовить атаку.
Создать контракт и от его имени пополнить банк на весь доступный баланс токенов (500к). Создать свою функцию tokenFallback(), которая будет отправлять дополнительный запрос на вывод средств. Затем просто вызвать withdraw().
#capture #cte
Как узнать публичный ключ из транзакции?
Нашел интересный сайт, который позволяет получать публичный ключ из raw hash транзакции.
Нужно для начала провести транзакцию с адреса, затем получить на etherscan или где-то еще raw hash, потом заходите на сайт, выбираете пункт Transaction и вставляете туда хеш.
Сайт проекта.
#public #key #tx #raw
Нашел интересный сайт, который позволяет получать публичный ключ из raw hash транзакции.
Нужно для начала провести транзакцию с адреса, затем получить на etherscan или где-то еще raw hash, потом заходите на сайт, выбираете пункт Transaction и вставляете туда хеш.
Сайт проекта.
#public #key #tx #raw
Заметка от меня
В последнее время на канале было большое количество задач, разборов и поиска уязвимостей в контрактах. Предполагаю, что некоторым участникам это могло немного надоесть. Теперь я хочу немного разбавить контент на канале.
Задача все также останутся на канале. После всего пройденного я более чем уверен, что разборы заданий помогут нам смотреть на контракты под другим углом и видеть "проблемы" там, где обычные разработчики их упускают. При этом мы будем брать только одну задачу в день. Чтобы все смогли посмотреть ее и попробовать решить самим.
Вместе с этим будут появляться материалы по другим основам блокчейн разработки, как например, сегодня я планирую сделать несколько постов про использование дебагера в ремиксе, а чуть позже поговорить про опкод.
Также мне интересно в ближайшее время вспомнить и подучить ethers, и как его использовать на фроненде.
Другими словами, хочется сделать чтобы на канале за день проходили посты: разбор уязвимости контракта, новое по блокчейну и кодингу, работа с фронтендом, и, возможно, будем поднимать знания по биржам и экономическим факторам. Первые два обязательно, остальные - по силам.
Вот как-то так.
Всем приятного дня и легкого обучения!
В последнее время на канале было большое количество задач, разборов и поиска уязвимостей в контрактах. Предполагаю, что некоторым участникам это могло немного надоесть. Теперь я хочу немного разбавить контент на канале.
Задача все также останутся на канале. После всего пройденного я более чем уверен, что разборы заданий помогут нам смотреть на контракты под другим углом и видеть "проблемы" там, где обычные разработчики их упускают. При этом мы будем брать только одну задачу в день. Чтобы все смогли посмотреть ее и попробовать решить самим.
Вместе с этим будут появляться материалы по другим основам блокчейн разработки, как например, сегодня я планирую сделать несколько постов про использование дебагера в ремиксе, а чуть позже поговорить про опкод.
Также мне интересно в ближайшее время вспомнить и подучить ethers, и как его использовать на фроненде.
Другими словами, хочется сделать чтобы на канале за день проходили посты: разбор уязвимости контракта, новое по блокчейну и кодингу, работа с фронтендом, и, возможно, будем поднимать знания по биржам и экономическим факторам. Первые два обязательно, остальные - по силам.
Вот как-то так.
Всем приятного дня и легкого обучения!
🔥3
Задача на день
Эта задача была в Paradigm CTF 2021.
Я прикрепил два файла контрактов для тех, кто захочет сам посмотреть и решить их. Вообще, это задание на внимательность и знание стандарта ERC20.
Целью является заполучить 50 Эфиров на баланс контракта Setup.
Маленькая подсказка: не усложняйте! Все проще, чем кажется.
Ну, и вопрос по такому формату: Нужно ли прикладывать решение или делать пост с ним в конце дня?
UPD. Решение.
После пары часов поиска уязвимости в контракте, я осознал, что все решение кроется в условии задачи. Нужно просто пополнить счет контракта на нужную сумму. Контракт wallet вам вообще не нужен для этого. Создайте свой контракт и напишите функцию, которая делает депозит, типа такой:
setup.WETH().deposit.value(msg.value)();
setup.WETH().transfer(address(setup), setup.WANT());
Порой нужно просто читать условие внимательно...
#task #paradigm2021 #ctf
Эта задача была в Paradigm CTF 2021.
Я прикрепил два файла контрактов для тех, кто захочет сам посмотреть и решить их. Вообще, это задание на внимательность и знание стандарта ERC20.
Целью является заполучить 50 Эфиров на баланс контракта Setup.
Маленькая подсказка: не усложняйте! Все проще, чем кажется.
Ну, и вопрос по такому формату: Нужно ли прикладывать решение или делать пост с ним в конце дня?
UPD. Решение.
setup.WETH().deposit.value(msg.value)();
setup.WETH().transfer(address(setup), setup.WANT());
Порой нужно просто читать условие внимательно...