Signature Malleability
Нашел интересную ветку в Твиттере с описанием данной уязвимости.
Все подписи содержат в себе значения:
R - a point on the secp256k1 elliptic curve (32 bytes)
S - a point on the secp256k1 elliptic curve (32 bytes)
V - recovery id (1 byte)
Имея на руках подпись и подписанное сообщение, любой пользователь может восстановить адрес, кому эта подпись принадлежит, используя функцию ecrecover(hash, v, r, s).
Уязвимость Signature Malleability может содержать в себе две и более разных подписей для восстановления для одного и того же подписанного сообщения. Это может быть достигнуто изменением оригинальной подписи и недостаточной валидацией.
В данном примере используется модификация подписи EIP2098 (Компактная подпись), которая помещает V (0 или 1) на верх бита S. Это приводит к тому, что подпись становится на 1 бит короче, и теперь нужно, чтобы контракт делал дополнительное действие - разворачивание подписи.
Посмотрите на пример выше на скрине. Тут передается подпись, восстанавливается адрес и сообщение сохраняется в маппинг, чтобы предотвратить replay атаку.
Тем не менее мы можем выполнить эту функцию дважды: с нормальной подписью и, модифицировав ее, с EIP2098.
Чаще всего используется библиотеки от OpenZeppeling. Эта уязвимость возможна на версиях ниже 4.7.3.
Обращайте на это внимание.
#security #ECDSA #signature
Нашел интересную ветку в Твиттере с описанием данной уязвимости.
Все подписи содержат в себе значения:
R - a point on the secp256k1 elliptic curve (32 bytes)
S - a point on the secp256k1 elliptic curve (32 bytes)
V - recovery id (1 byte)
Имея на руках подпись и подписанное сообщение, любой пользователь может восстановить адрес, кому эта подпись принадлежит, используя функцию ecrecover(hash, v, r, s).
Уязвимость Signature Malleability может содержать в себе две и более разных подписей для восстановления для одного и того же подписанного сообщения. Это может быть достигнуто изменением оригинальной подписи и недостаточной валидацией.
В данном примере используется модификация подписи EIP2098 (Компактная подпись), которая помещает V (0 или 1) на верх бита S. Это приводит к тому, что подпись становится на 1 бит короче, и теперь нужно, чтобы контракт делал дополнительное действие - разворачивание подписи.
Посмотрите на пример выше на скрине. Тут передается подпись, восстанавливается адрес и сообщение сохраняется в маппинг, чтобы предотвратить replay атаку.
Тем не менее мы можем выполнить эту функцию дважды: с нормальной подписью и, модифицировав ее, с EIP2098.
Чаще всего используется библиотеки от OpenZeppeling. Эта уязвимость возможна на версиях ниже 4.7.3.
Обращайте на это внимание.
#security #ECDSA #signature
👍3
Signature Malleability 2
Ну, и еще одна уязвимость от того же автора из Твиттер.
Посмотрите на скрин. Вероятно, вы видели или сами реализовывали такое восстановление подписи у себя в контракте.
Но тут чего-то не хватает?
А точнее, тут не хватает валидации S значения!
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ) {
return (address(0), RecoverError.InvalidSignatureS);
}
Если открыть контракт от OpenZeppelin, то там увидите довольно большой комментарий, зачем нужна проверка этого значения.
Из-за особенностей работы системы, сюда вы можете передать две разные подписи (с одинаковым подписанным сообщением) и получить один и тот же восстановленный адрес!
В этой ветке дается объяснения почему это происходит, и как это связано с EIP2 и secp256k1n/2. Спойлер: особенности шифрования.
Как я понял, вообще нужно быть очень аккуратными и внимательными с этими подписями и их восстановлением.
#security #signature #eip2
Ну, и еще одна уязвимость от того же автора из Твиттер.
Посмотрите на скрин. Вероятно, вы видели или сами реализовывали такое восстановление подписи у себя в контракте.
Но тут чего-то не хватает?
А точнее, тут не хватает валидации S значения!
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ) {
return (address(0), RecoverError.InvalidSignatureS);
}
Если открыть контракт от OpenZeppelin, то там увидите довольно большой комментарий, зачем нужна проверка этого значения.
Из-за особенностей работы системы, сюда вы можете передать две разные подписи (с одинаковым подписанным сообщением) и получить один и тот же восстановленный адрес!
В этой ветке дается объяснения почему это происходит, и как это связано с EIP2 и secp256k1n/2. Спойлер: особенности шифрования.
Как я понял, вообще нужно быть очень аккуратными и внимательными с этими подписями и их восстановлением.
#security #signature #eip2
👍1
E в Ethereum Signed Message
Знали ли вы, что буква Е в Ethereum Signed Message (подписанные сообщения), на самом деле параметр, а не просто буква?
В исходном коде сообщение выглядит так:
0x19 <0x45 (E)> <thereum Signed Message:\n" + len(message)> <data to sign>
0x45 или "E" - говорит, что используется одна из версий подписи сообщений.
Больше информации на скрине.
#signature
Знали ли вы, что буква Е в Ethereum Signed Message (подписанные сообщения), на самом деле параметр, а не просто буква?
В исходном коде сообщение выглядит так:
0x19 <0x45 (E)> <thereum Signed Message:\n" + len(message)> <data to sign>
0x45 или "E" - говорит, что используется одна из версий подписи сообщений.
Больше информации на скрине.
#signature
👍1
Новые задачи CTF
На каникулах встретил еще несколько интересных проектов, где можно поучиться решать задачки и попрактиковаться с уже пройденными DVD и Ethernaut, но используя Foundry.
Не помню, чтобы видел их в какой-либо подборке, поэтому надеюсь, что первый публикую их в ру сегменте.
Mr Steal Yo Crypto
CTF Protocol
QuillCTF
И для практики в Foundry:
Damn Vulnerable DeFi
Ethernaut CTF
Fifty years Capture the Ether
Приятных вам голодных игр!
#ctf
На каникулах встретил еще несколько интересных проектов, где можно поучиться решать задачки и попрактиковаться с уже пройденными DVD и Ethernaut, но используя Foundry.
Не помню, чтобы видел их в какой-либо подборке, поэтому надеюсь, что первый публикую их в ру сегменте.
Mr Steal Yo Crypto
CTF Protocol
QuillCTF
И для практики в Foundry:
Damn Vulnerable DeFi
Ethernaut CTF
Fifty years Capture the Ether
Приятных вам голодных игр!
#ctf
👍2
Классная задача от Immunefi
Уже в первых числах января Immunefi выложила еще одну задачу, которая меня очень впечатлила.
Для того, чтобы понять всю идею, откройте скрин на весь экран и внимательно прочитайте код строчка за строчкой.
Я напишу ответ не закрытый, как обычно, так как большинство участников точно не знает, в чем тут может быть проблема.
С кодом все ок. По крайней мере, если не знать особенностей работы контрактов токенов и разных EIP.
В случае с ERC20 - все будет ок. Однако проблемы могут начаться, если хакер захочет использовать токены ERC777.
Если кто не знает, то такие токены стандарта ERC777 при трансфере имеют не одну, а целых две callback функции:
_callTokensToSend() - которая вызывается до фактической отправки токенов;
_callTokensReceived() - которая вызывается после отправки токенов.
Обе они в рамках функции transfer(). Поняли теперь, в чем дело в задаче?
Используя _callTokensToSend() токена, хакер может заходить в функцию deposit() несколько раз (reentrancy), и спровоцировать увеличенное количество shares!
Лично я не знал этого момента. Пришлось покопаться в сети, чтобы понять принципы работы.
Интересно, да?
#task #security #erc777
Уже в первых числах января Immunefi выложила еще одну задачу, которая меня очень впечатлила.
Для того, чтобы понять всю идею, откройте скрин на весь экран и внимательно прочитайте код строчка за строчкой.
Я напишу ответ не закрытый, как обычно, так как большинство участников точно не знает, в чем тут может быть проблема.
С кодом все ок. По крайней мере, если не знать особенностей работы контрактов токенов и разных EIP.
В случае с ERC20 - все будет ок. Однако проблемы могут начаться, если хакер захочет использовать токены ERC777.
Если кто не знает, то такие токены стандарта ERC777 при трансфере имеют не одну, а целых две callback функции:
_callTokensToSend() - которая вызывается до фактической отправки токенов;
_callTokensReceived() - которая вызывается после отправки токенов.
Обе они в рамках функции transfer(). Поняли теперь, в чем дело в задаче?
Используя _callTokensToSend() токена, хакер может заходить в функцию deposit() несколько раз (reentrancy), и спровоцировать увеличенное количество shares!
Лично я не знал этого момента. Пришлось покопаться в сети, чтобы понять принципы работы.
Интересно, да?
#task #security #erc777
👍2
Аудиты, тесты и больше практики
Вот уже пару дней, как делаю конкурсный аудит с code4rena, и уже не в первый раз ловлю себя на одном моменте.
В обучении и практике нет "серединки".
Чаще всего, задачи и тестовые проекты ограничиваются парой небольших контрактов, а задачи и того меньше - парой функций.
А тесты? Все обучающие видео и статьи строятся вокруг "Как начать делать тесты"? Попробуйте найти хоть одно видео, где приводится тестирование мостов или крупных проектов.
После обучения наступает практика. Мы идем на конкурсные проекты или устраиваемся на работу, получаем первый архив проекта и начинаем офигивать!
10+ перекликающихся контрактов, 5000 строк кода, туча импортов и непонятных настроек. И это хорошо, если разработчики постарались и написали комментарии с подробным описанием функций, идеи проекта и natspec. А если нет?..
К чему я это все веду.
После того как изучили базис и написали свои первые контракты, идите на популярные площадки, типа code4rena, скачивайте конкурсные проекты и старайтесь разобраться в них: написать свои тесты, оптимизировать функции и т.д.
Чем раньше вы погрузитесь в "боевой" режим разработчика, тем быстрее будете набираться опыта.
А я пошел дальше разбираться с foundry.
#практика
Вот уже пару дней, как делаю конкурсный аудит с code4rena, и уже не в первый раз ловлю себя на одном моменте.
В обучении и практике нет "серединки".
Чаще всего, задачи и тестовые проекты ограничиваются парой небольших контрактов, а задачи и того меньше - парой функций.
А тесты? Все обучающие видео и статьи строятся вокруг "Как начать делать тесты"? Попробуйте найти хоть одно видео, где приводится тестирование мостов или крупных проектов.
После обучения наступает практика. Мы идем на конкурсные проекты или устраиваемся на работу, получаем первый архив проекта и начинаем офигивать!
10+ перекликающихся контрактов, 5000 строк кода, туча импортов и непонятных настроек. И это хорошо, если разработчики постарались и написали комментарии с подробным описанием функций, идеи проекта и natspec. А если нет?..
К чему я это все веду.
После того как изучили базис и написали свои первые контракты, идите на популярные площадки, типа code4rena, скачивайте конкурсные проекты и старайтесь разобраться в них: написать свои тесты, оптимизировать функции и т.д.
Чем раньше вы погрузитесь в "боевой" режим разработчика, тем быстрее будете набираться опыта.
А я пошел дальше разбираться с foundry.
#практика
👍2
В дополнение к предыдущему посту
Сейчас проводится конкурс на аудит контрактов Astaria.
Почему я предлагаю этот проект?
На мой взгляд он держит хорошую планку по уровню простоты и сложности одновременно. С одной стороны - нормальная документация, с другой - недостаток описания функций; с одной стороны - много небольших контрактов, с другой - основные контракты длинные; при этом некоторые скрытые в памяти параметры. В общем, он стоит того, чтобы посидеть с ним.
Что можно сделать для своей практики?
Прочитайте документацию, скачайте, распакуйте и установите проект. Не думайте, что осталась пара дней до окончания. Вы оставите его и продолжите тренироваться после.
Прежде всего постарайтесь ответить себе на следующие вопросы:
1) Понимаю ли я основную идею проекта?
2) Понимаю ли я, за что отвечает каждый контракт?
3) Понимаю ли я их взаимосвязь?
4) Понимаю ли я исходную точку для пользователя?
5) Понимаю ли я весь набор файлов в проекте?
6) Понимаю ли я подключенные библиотеки?
Этого будет вполне достаточно для работы дальше. Не волнуйтесь, если это займет у вас несколько дней.
Далее попробуйте написать свои тесты для него:
1) Создать Сейф от имени пользователя;
2) Сделать перевод;
3) Добавить пользователей и от их имени проведите транзакции;
4) Отдайте NFT в займ;
5) Прочитайте переменные памяти контракта;
Если вы сможете сделать все, то последующие аудиты и разборы кода будут даваться легче. Если не сможете, не расстраивайтесь.
Просто возьмите за правило раз-два в месяц брать конкурсные проекты и разбираться в них. Это станет наикрутейшей практикой. И никакое платное обучение не сможет это превзойти.
Дерзайте!
#практика
Сейчас проводится конкурс на аудит контрактов Astaria.
Почему я предлагаю этот проект?
На мой взгляд он держит хорошую планку по уровню простоты и сложности одновременно. С одной стороны - нормальная документация, с другой - недостаток описания функций; с одной стороны - много небольших контрактов, с другой - основные контракты длинные; при этом некоторые скрытые в памяти параметры. В общем, он стоит того, чтобы посидеть с ним.
Что можно сделать для своей практики?
Прочитайте документацию, скачайте, распакуйте и установите проект. Не думайте, что осталась пара дней до окончания. Вы оставите его и продолжите тренироваться после.
Прежде всего постарайтесь ответить себе на следующие вопросы:
1) Понимаю ли я основную идею проекта?
2) Понимаю ли я, за что отвечает каждый контракт?
3) Понимаю ли я их взаимосвязь?
4) Понимаю ли я исходную точку для пользователя?
5) Понимаю ли я весь набор файлов в проекте?
6) Понимаю ли я подключенные библиотеки?
Этого будет вполне достаточно для работы дальше. Не волнуйтесь, если это займет у вас несколько дней.
Далее попробуйте написать свои тесты для него:
1) Создать Сейф от имени пользователя;
2) Сделать перевод;
3) Добавить пользователей и от их имени проведите транзакции;
4) Отдайте NFT в займ;
5) Прочитайте переменные памяти контракта;
Если вы сможете сделать все, то последующие аудиты и разборы кода будут даваться легче. Если не сможете, не расстраивайтесь.
Просто возьмите за правило раз-два в месяц брать конкурсные проекты и разбираться в них. Это станет наикрутейшей практикой. И никакое платное обучение не сможет это превзойти.
Дерзайте!
#практика
❤1
Задачка на день
Ну, и небольшая задачка на день. Сможете найти, в чем тут проблема?
Решение
В аудитах следует всегда обращать внимание на модификаторы функций, какие условия они нам ставят.
В текущем же примере, он просто сверяет msg.sender с другим параметров, а значит, что функция _safeMint() не защищена от reentrancy атак.
#security #task
Ну, и небольшая задачка на день. Сможете найти, в чем тут проблема?
Решение
В текущем же примере, он просто сверяет msg.sender с другим параметров, а значит, что функция _safeMint() не защищена от reentrancy атак.
👍2
Counter.sol
2.8 KB
Файл-хелпер для работы с Foundry
В недавнем аудите я снова столкнулся с некоторыми тестами в Foundry, которые тормозили весь процесс.
Сегодня я решил создать для себя небольшой файл подсказку для проведения тестов.
Думаю он может быть полезен всем, кто только начинает свою практику. Вы можете скачать его и в любой момент добавлять свои тесты или наработки.
Также прикрепляю файл с базовыми контрактами.
Обращаю внимание, что это простые тесты с комментариями, для общего понимания принципов работы Foundry. Позже добавлю туда практику с прокси контрактами, а также наработки с эксплойтами.
Всем хороших выходных!
#foundry
В недавнем аудите я снова столкнулся с некоторыми тестами в Foundry, которые тормозили весь процесс.
Сегодня я решил создать для себя небольшой файл подсказку для проведения тестов.
Думаю он может быть полезен всем, кто только начинает свою практику. Вы можете скачать его и в любой момент добавлять свои тесты или наработки.
Также прикрепляю файл с базовыми контрактами.
Обращаю внимание, что это простые тесты с комментариями, для общего понимания принципов работы Foundry. Позже добавлю туда практику с прокси контрактами, а также наработки с эксплойтами.
Всем хороших выходных!
#foundry
🔥5
День задач на канале
Сегодня я подготавливаю отчет для своего конкурсного аудита, поэтому на канале объявляется день задач.
Итак, первая: была помечена как High Risk на code4rena. Сможете понять в чем тут дело?
Решение
В этой задаче стоит обратить внимание не только на саму подпись (мы же помним, что с ними существует достаточное количество проблем?), но и на nonce.
Вроде бы, все правильно написано в коде. Но нет одной единственной проверки. Уже догадались?
Разработчики не проверяют return с call вызова. Это значит, что в случае неудачного вызова, nonce останется прежним, и хакер может использовать подпись с еще действующим nonce в своих целях.
Вот описание с code4rena.
#task #nonce
Сегодня я подготавливаю отчет для своего конкурсного аудита, поэтому на канале объявляется день задач.
Итак, первая: была помечена как High Risk на code4rena. Сможете понять в чем тут дело?
Решение
Вроде бы, все правильно написано в коде. Но нет одной единственной проверки. Уже догадались?
Разработчики не проверяют return с call вызова. Это значит, что в случае неудачного вызова, nonce останется прежним, и хакер может использовать подпись с еще действующим nonce в своих целях.
👍2
Более сложная задача от Immunefi
При аудите всегда следует обращать внимание на переменные и "откуда растут ноги" у токена. Получилось решить?
Решение
Хоть первая функция и оторвана от контекста, смысл бага все же можно уловить: недостаточная проверка токенов. Другими словами хакер может использовать фейковый токен, чтобы получить реальные токены.
#task #token
При аудите всегда следует обращать внимание на переменные и "откуда растут ноги" у токена. Получилось решить?
Решение
Еще одна с code4rena
Данный баг был обозначен как Medium risk. Поняли в чем дело?
Решение
Функция lendToProject может стать не доступной, если количество задач (tasks) будет слишком большим, что приведет к стопорению проекта.
Это происходит из-за того, что цикл расходует весь газ из функции. Такая вот DoS атака.
#task
Данный баг был обозначен как Medium risk. Поняли в чем дело?
Решение
Это происходит из-за того, что цикл расходует весь газ из функции. Такая вот DoS атака.
Простая, но серьезная
Данная задача одна из самых легких среди тех, что я видел. Тем не менее, она была помечена как High Risk. Решили?
Решение
Функция заканчивает свое действие на return и не доходит до проверки require. К чему это может привести, вы и сами знаете.
#task
Данная задача одна из самых легких среди тех, что я видел. Тем не менее, она была помечена как High Risk. Решили?
Решение
👍2
Задача на знание нюансов
Задача была помечена как Medium Risk. Ошибка не столько в самом коде, сколько в логике и знании, как работает язык. Поняли, о чем идет речь?
Решение
Проблема все в том же extcodesize. Нельзя полагаться на него при проверке "Контракт ли это?". В первом случае, хакер может все сделать через конструктор контакта, а в более сложном - поиграться с create2 и selfdestruct(). Т.е. проверку довольно просто обойти.
#task
Задача была помечена как Medium Risk. Ошибка не столько в самом коде, сколько в логике и знании, как работает язык. Поняли, о чем идет речь?
Решение
👍2
И последняя на сегодня
Последняя задача была помечена как Critical. Достаточно серьезная проблема многих контактов, которые используют переводы.
Решение
Заметили маппинги в начале? Как вы думаете, зачем они были указаны?
Да, их значения не обновляются при переводе. А значит, что пользователь может делать перевод несколько раз по одному id и опустошить контракт. Будьте внимательны в своих контрактах!
#task
Последняя задача была помечена как Critical. Достаточно серьезная проблема многих контактов, которые используют переводы.
Решение
Да, их значения не обновляются при переводе. А значит, что пользователь может делать перевод несколько раз по одному id и опустошить контракт. Будьте внимательны в своих контрактах!
👍4
Нет, не задача
Disclaimer. Сегодня я сменил название канала, так как мы уже давно вышли за рамки начального обучения, и материал теперь уже для более продвинутых пользователей.
Сегодня хочу обратить ваше внимание на стандарт ERC4626. По нему ранее была задача у Immunefi, с которой мне пришлось повозиться, чтобы понять в чем там дело.
ERC4626, объясняю своими словами, используется тогда, когда вам нужно выдать пользователям вашего проекта некоторое количество shares взамен их токенов, которые они внесли. Он используется и в играх, и в Dao, и на биржах. При аудитах он встречается довольно часто.
В контрактах, которые используют данный стандарт, нужно обращать внимание на формулу расчета количество shares.
Чаще всего разработчики упускают из вида проблему минта shares для первого пользователя, а он может оказаться хакером.
Хоть я сам и понял суть бага, но объяснить его немного затрудняюсь, поэтому предлагаю вам посмотреть часть видео, где он хорошо разбирается.
Видео разбор.
#erc4626
Disclaimer. Сегодня я сменил название канала, так как мы уже давно вышли за рамки начального обучения, и материал теперь уже для более продвинутых пользователей.
Сегодня хочу обратить ваше внимание на стандарт ERC4626. По нему ранее была задача у Immunefi, с которой мне пришлось повозиться, чтобы понять в чем там дело.
ERC4626, объясняю своими словами, используется тогда, когда вам нужно выдать пользователям вашего проекта некоторое количество shares взамен их токенов, которые они внесли. Он используется и в играх, и в Dao, и на биржах. При аудитах он встречается довольно часто.
В контрактах, которые используют данный стандарт, нужно обращать внимание на формулу расчета количество shares.
Чаще всего разработчики упускают из вида проблему минта shares для первого пользователя, а он может оказаться хакером.
Хоть я сам и понял суть бага, но объяснить его немного затрудняюсь, поэтому предлагаю вам посмотреть часть видео, где он хорошо разбирается.
Видео разбор.
#erc4626
👍1
Хэширование в EIP712
Все чаще встречаюсь с этим стандартом на просторах аудиторских отчетов, и стараюсь осмысливать его шаг за шагом.
Вообще EIP712 был создан для того, чтобы можно было подписывать сообщения, которые состоят не только из строк, но и более сложных параметров: например, struct.
И сегодня разберем, как шифруются структуры. Возьмем такой код:
struct Parent {
uint s;
Child[] children;
}
Child {
uint a;
uint b;
}
Сначала будет хешироваться каждый пункт в Child по отдельности, затем они соединяются (конкатенация) и еще раз хешируются. Из этого получается хеш структуры.
В самом конце, берется S и хеш структуры и высчитывается уже конечный хеш Parent.
#erc712 #struct
Все чаще встречаюсь с этим стандартом на просторах аудиторских отчетов, и стараюсь осмысливать его шаг за шагом.
Вообще EIP712 был создан для того, чтобы можно было подписывать сообщения, которые состоят не только из строк, но и более сложных параметров: например, struct.
И сегодня разберем, как шифруются структуры. Возьмем такой код:
struct Parent {
uint s;
Child[] children;
}
Child {
uint a;
uint b;
}
Сначала будет хешироваться каждый пункт в Child по отдельности, затем они соединяются (конкатенация) и еще раз хешируются. Из этого получается хеш структуры.
В самом конце, берется S и хеш структуры и высчитывается уже конечный хеш Parent.
#erc712 #struct