Аудит вне рамок - 9
Отличный пример логического недочета, который нашел только Trust, в протоколе Forgeries.
Он указывает на то, что, не смотря на использование безопасного и общепринятого Chainlink VRF для генерации случайного числа, сама функция в контракте может иметь уязвимость.
Обращаем внимание при аудите
Даже если в функции используются общепринятые безопасные решения сторонних протоколов, тот же Chainlink, Uniswap и т.д., это не значит, что сама функция также безопасна.
В таких случаях, нам потребуется также изучать те сторонние решение, чтобы понять, как они используются и что, может пойти не так.
В данном случае, у контракта всегда на балансе должно быть некоторое количество токенов Link, для успешной генерации новых чисел, иначе транзакция зависает на 24 часа до пополнения баланса. В течение этого времени, админ протокола может "играть" с выдачей результатов функции в свою пользу.
Меня всегда поражало, как такие аудиторы, как Trust, могут думать вне рамок контракта. Хочу научиться также.
#audit #outofbox
Отличный пример логического недочета, который нашел только Trust, в протоколе Forgeries.
Он указывает на то, что, не смотря на использование безопасного и общепринятого Chainlink VRF для генерации случайного числа, сама функция в контракте может иметь уязвимость.
Обращаем внимание при аудите
Даже если в функции используются общепринятые безопасные решения сторонних протоколов, тот же Chainlink, Uniswap и т.д., это не значит, что сама функция также безопасна.
В таких случаях, нам потребуется также изучать те сторонние решение, чтобы понять, как они используются и что, может пойти не так.
В данном случае, у контракта всегда на балансе должно быть некоторое количество токенов Link, для успешной генерации новых чисел, иначе транзакция зависает на 24 часа до пополнения баланса. В течение этого времени, админ протокола может "играть" с выдачей результатов функции в свою пользу.
Меня всегда поражало, как такие аудиторы, как Trust, могут думать вне рамок контракта. Хочу научиться также.
#audit #outofbox
❤1
Баг в компиляторе Solidity
В начале февраля был пост о том, что команда Dedaub обнаружила баг в компиляторе, который задел огромное количество задеплоеных контрактов.
Подробнее об этом можно прочитать в этой ветке в Твиттере и в данном посте на GitHub, но я кратно опишу, в чем была суть.
Если вы использовали функции из подключенной библиотеки в конструкторе своего контракта, то они должны были быть использованы только в initcode. Однако созданный из них байткод включался также и в runtime. Это приводило к тому, что размер контракта увеличивался, как и стоимость его разворачивания. В некоторых случаях, такой "не нужный код" мог занимать до трети от размера контракта!
По словам комментаторов, этот баг актуален для всех версий Solidity ниже 0.18, т.е. самой последней.
#solidity #solc
В начале февраля был пост о том, что команда Dedaub обнаружила баг в компиляторе, который задел огромное количество задеплоеных контрактов.
Подробнее об этом можно прочитать в этой ветке в Твиттере и в данном посте на GitHub, но я кратно опишу, в чем была суть.
Если вы использовали функции из подключенной библиотеки в конструкторе своего контракта, то они должны были быть использованы только в initcode. Однако созданный из них байткод включался также и в runtime. Это приводило к тому, что размер контракта увеличивался, как и стоимость его разворачивания. В некоторых случаях, такой "не нужный код" мог занимать до трети от размера контракта!
По словам комментаторов, этот баг актуален для всех версий Solidity ниже 0.18, т.е. самой последней.
#solidity #solc
🔥3
ERC-4337 в основной сети Ethereum
Разработчики развернули стандарт ERC-4337 в основной сети Ethereum. Это ключевое усовершенствование блокчейна, которое существенно упростит доступ пользователей к заблокированным кошелькам.
Стандарт ERC-4337 позволит разработчикам Ethereum реализовать технологию абстракции учетной записи. Это значит, что пользователям больше не придется запоминать или записывать сложную фразу для восстановления. Вместо этого уникальные криптографические ключи можно будет фиксировать в стандартных модулях безопасности смартфонов. Таким образом, абстракция превратит телефоны в простые в использовании аппаратные кошельки, что может значительно способствовать массовому внедрению криптовалют.
У данной технологии также есть ряд других важных преимуществ:
- двухфакторная аутентификация
- установка лимитов
- подписание транзакций при помощи биометрии
- использование ключей для блокчейн-игр без необходимости постоянного подтверждения транзакций
- временная блокировка кошелька при потере устройства
- восстановление доступа к кошельку при помощи сторонних сервисов
По словам разработчиков Ethereum, абстракция учетной записи имеет «те же функции, что и банк, без необходимости доверять банку». Эксперты считают, что в 2023 году смарт-аккаунты получат мощный импульс для развития.
#eip4337
Разработчики развернули стандарт ERC-4337 в основной сети Ethereum. Это ключевое усовершенствование блокчейна, которое существенно упростит доступ пользователей к заблокированным кошелькам.
Стандарт ERC-4337 позволит разработчикам Ethereum реализовать технологию абстракции учетной записи. Это значит, что пользователям больше не придется запоминать или записывать сложную фразу для восстановления. Вместо этого уникальные криптографические ключи можно будет фиксировать в стандартных модулях безопасности смартфонов. Таким образом, абстракция превратит телефоны в простые в использовании аппаратные кошельки, что может значительно способствовать массовому внедрению криптовалют.
У данной технологии также есть ряд других важных преимуществ:
- двухфакторная аутентификация
- установка лимитов
- подписание транзакций при помощи биометрии
- использование ключей для блокчейн-игр без необходимости постоянного подтверждения транзакций
- временная блокировка кошелька при потере устройства
- восстановление доступа к кошельку при помощи сторонних сервисов
По словам разработчиков Ethereum, абстракция учетной записи имеет «те же функции, что и банк, без необходимости доверять банку». Эксперты считают, что в 2023 году смарт-аккаунты получат мощный импульс для развития.
#eip4337
👍8😢1
Выпустили Foundry v0.2.0
Полное описание всех улучшений можно прочитать тут или в ветке одного из разработчиков.
Если говорить кратко, то:
1) Скорость компиляции стала еще быстрее;
2) Также как и скорость проведения тестов;
3) Команда forge test -vvvv показывает не только путь выполнения, но и выводит данные на каждый субвызов;
4) Отчет по газу стал еще круче;
5) Появился интерактивный дебаггер;
6) Добавились новые читкоды (пока список не нашел, возможно, еще не обновили доки);
7) Появилась еще более гибкая кастомизация toml файла;
8) Более простая установка;
Классно, что такая программа развивается вместе с потребностями разработчиков и аудиторов.
#foundry
Полное описание всех улучшений можно прочитать тут или в ветке одного из разработчиков.
Если говорить кратко, то:
1) Скорость компиляции стала еще быстрее;
2) Также как и скорость проведения тестов;
3) Команда forge test -vvvv показывает не только путь выполнения, но и выводит данные на каждый субвызов;
4) Отчет по газу стал еще круче;
5) Появился интерактивный дебаггер;
6) Добавились новые читкоды (пока список не нашел, возможно, еще не обновили доки);
7) Появилась еще более гибкая кастомизация toml файла;
8) Более простая установка;
Классно, что такая программа развивается вместе с потребностями разработчиков и аудиторов.
#foundry
👍9❤1
Заметка о проведении аудита
На прошлой неделе я взял конкурсный аудит. Позже знакомый разработчик попросил также проверить и его проект. И я хочу рассказать о своем опыте последней недели.
Начну с того, что в январе я брал первые конкурсные проекты и особо не понимал, с чего начинать и куда двигаться. Моей стратегией было просмотреть контракты, почитать документацию и искать уязвимости. Не то, чтобы это было не правильной тактикой, но она не принесла плоды. В этот раз я решил пойти другим путем.
Перед поиском багов я решил досконально изучить проект. Это значит, что я не только прочитал официальную документацию и readme файлы проекта, но и делал заметки по ходу всего изучения. К некоторым абзацам я возвращался снова и снова, чтобы понять саму идею проекта. Только после этого я стал "копаться в коде".
Когда читаешь каждую функцию по-отдельности, то кажется, что все понятно. Но спустя некоторое время и пару контрактов, ты уже не можешь сказать, что она делает. Тогда я попробовал построить схему их "потока" действий, просто типа майнд карты.
И только спустя более 40 часов изучения, я смог понять всю идею разработчиков и по памяти разложить ход действий, с учетом изменений в памяти контракта.
Только после этого я приступил к поиску уязвимостей. Самое сложное было это отойти от "мыслей разработчика" и попытаться посмотреть на проект глазами взломщика, выявляя все не стандартные действия, которые может совершить пользователь.
Очень надеюсь, что у меня получилось найти несколько хороших багов. С нетерпением буду ждать результатов.
Что по дружескому проекту, то тут все проще. Хоть количество контрактов и не большое, всего 4 штуки, но они были намного понятнее, чем серьезный конкурсный аудит. Тем не менее, на его изучение мне потребовался день, вместе с постоянной перепиской с разработчиком.
Как я понял, в аудите 80% всего времени нужно тратить не столько на поиск багов, сколько на понимание ключевой идеи разработчиков. Только тогда вы сможете понимать, какие действия были запланированы, а какие будут неожиданностью.
Всем удачных аудитов!
#audit
На прошлой неделе я взял конкурсный аудит. Позже знакомый разработчик попросил также проверить и его проект. И я хочу рассказать о своем опыте последней недели.
Начну с того, что в январе я брал первые конкурсные проекты и особо не понимал, с чего начинать и куда двигаться. Моей стратегией было просмотреть контракты, почитать документацию и искать уязвимости. Не то, чтобы это было не правильной тактикой, но она не принесла плоды. В этот раз я решил пойти другим путем.
Перед поиском багов я решил досконально изучить проект. Это значит, что я не только прочитал официальную документацию и readme файлы проекта, но и делал заметки по ходу всего изучения. К некоторым абзацам я возвращался снова и снова, чтобы понять саму идею проекта. Только после этого я стал "копаться в коде".
Когда читаешь каждую функцию по-отдельности, то кажется, что все понятно. Но спустя некоторое время и пару контрактов, ты уже не можешь сказать, что она делает. Тогда я попробовал построить схему их "потока" действий, просто типа майнд карты.
И только спустя более 40 часов изучения, я смог понять всю идею разработчиков и по памяти разложить ход действий, с учетом изменений в памяти контракта.
Только после этого я приступил к поиску уязвимостей. Самое сложное было это отойти от "мыслей разработчика" и попытаться посмотреть на проект глазами взломщика, выявляя все не стандартные действия, которые может совершить пользователь.
Очень надеюсь, что у меня получилось найти несколько хороших багов. С нетерпением буду ждать результатов.
Что по дружескому проекту, то тут все проще. Хоть количество контрактов и не большое, всего 4 штуки, но они были намного понятнее, чем серьезный конкурсный аудит. Тем не менее, на его изучение мне потребовался день, вместе с постоянной перепиской с разработчиком.
Как я понял, в аудите 80% всего времени нужно тратить не столько на поиск багов, сколько на понимание ключевой идеи разработчиков. Только тогда вы сможете понимать, какие действия были запланированы, а какие будут неожиданностью.
Всем удачных аудитов!
#audit
👍9
Отличный совет от аудитора
Недавно вышел новый Shorts на YouTube от опытного аудитора Owen Thurm, в котором он дает дельный совет, как проводить аудит и на что обращать внимание.
Возможно, для начинающих это будет не очень понятно, тем не менее, запомните, что он говорит.
Ссылка на видео.
Вообще, мне нравится, что все больше крутых аудиторов делятся своими знаниями в Твиттере, Ютуб, на курсах.
#audit
Недавно вышел новый Shorts на YouTube от опытного аудитора Owen Thurm, в котором он дает дельный совет, как проводить аудит и на что обращать внимание.
Возможно, для начинающих это будет не очень понятно, тем не менее, запомните, что он говорит.
Ссылка на видео.
Вообще, мне нравится, что все больше крутых аудиторов делятся своими знаниями в Твиттере, Ютуб, на курсах.
#audit
YouTube
Never Run Out Of Smart Contract Exploit Ideas
Join our community aimed at building and sharing a wealth of blockchain and solidity knowledge to help developers/auditors of all levels transform the web3 ecosystem: https://lab.guardianaudits.com/
Complete Smart Contract Auditing System: https://youtu.be/5g…
Complete Smart Contract Auditing System: https://youtu.be/5g…
👍2❤1
Аудит в коопе
Вероятно, некоторые из вас знают, что в недавнем конкурсе на аудит Optimism двое участников, Trust и Obront, получили более 100к за одну единственную уязвимость в коде.
О самом баге мы узнаем больше, когда выйдет отчет. А вчера Obront поделился в Твиттере, как они организовали свою работу совместно с Trust. Предлагаю перевод данной ветки.
1) Они создали отдельный сервер на Дискорд. Не канал, а именно сервер. Это позволило организовать общение по тематическим веткам, и держать основные моменты аудита в фокусе.
2) У них было три основные категории на сервере:
- Текстовые каналы: любые обсуждения, не связанные с какими-либо багами;
- Лиды: обсуждали все, что казалось интересным по коду (например, неподтвержденные баги);
- Подтвержденные баги
3) Они оба "шли по коду", как если бы они делали аудит каждый по отдельности. И как только кто-либо находил интересную штуку, он начинал новый канал в Лидах. Это позволяло держать партнера в курсе находок, не прерывая друг друга.
4) После того, как Лид был подтвержден, он перемещался в другой раздел: Подтвержденные баги. Они использовали смайлы для обозначения уровня угрозы уязвимости (⚪️, 🟡, 🟢), а также ✅, когда отчет был написан, и 🎉, когда отчет был отправлен.
5) В целом, они делали аудит по всем контрактам. Однако были некоторые моменты, куда каждый углублялся сам, при этом партнер уже не тратил на это время и занимался другим.
6) Телефонные созвоны. Порой это может отвлекать, но они иногда устраивали короткие созвоны, чтобы "быть на одной волне":
- Брифинг: когда партнер углублялся в нюанс кода, нужно было, чтобы другой узнал о результатах;
- Брейнсторм: после 1 недели они обсуждали возможные эксплойты и фокус на 2 неделю;
- Обмен знаниями: тут и так понятно;
7) В конце всего, каждый из них написал свой отчет в markdown файле и опубликовал его на канале в нужном разделе. Так они могли дать обратную связь друг другу.
На мой взгляд, это прекрасный способ организации работы. Во всяком случае, топовые аудиторы нашли его самым эффективным для своей работы.
#audit
Вероятно, некоторые из вас знают, что в недавнем конкурсе на аудит Optimism двое участников, Trust и Obront, получили более 100к за одну единственную уязвимость в коде.
О самом баге мы узнаем больше, когда выйдет отчет. А вчера Obront поделился в Твиттере, как они организовали свою работу совместно с Trust. Предлагаю перевод данной ветки.
1) Они создали отдельный сервер на Дискорд. Не канал, а именно сервер. Это позволило организовать общение по тематическим веткам, и держать основные моменты аудита в фокусе.
2) У них было три основные категории на сервере:
- Текстовые каналы: любые обсуждения, не связанные с какими-либо багами;
- Лиды: обсуждали все, что казалось интересным по коду (например, неподтвержденные баги);
- Подтвержденные баги
3) Они оба "шли по коду", как если бы они делали аудит каждый по отдельности. И как только кто-либо находил интересную штуку, он начинал новый канал в Лидах. Это позволяло держать партнера в курсе находок, не прерывая друг друга.
4) После того, как Лид был подтвержден, он перемещался в другой раздел: Подтвержденные баги. Они использовали смайлы для обозначения уровня угрозы уязвимости (⚪️, 🟡, 🟢), а также ✅, когда отчет был написан, и 🎉, когда отчет был отправлен.
5) В целом, они делали аудит по всем контрактам. Однако были некоторые моменты, куда каждый углублялся сам, при этом партнер уже не тратил на это время и занимался другим.
6) Телефонные созвоны. Порой это может отвлекать, но они иногда устраивали короткие созвоны, чтобы "быть на одной волне":
- Брифинг: когда партнер углублялся в нюанс кода, нужно было, чтобы другой узнал о результатах;
- Брейнсторм: после 1 недели они обсуждали возможные эксплойты и фокус на 2 неделю;
- Обмен знаниями: тут и так понятно;
7) В конце всего, каждый из них написал свой отчет в markdown файле и опубликовал его на канале в нужном разделе. Так они могли дать обратную связь друг другу.
На мой взгляд, это прекрасный способ организации работы. Во всяком случае, топовые аудиторы нашли его самым эффективным для своей работы.
#audit
👍8
Твит от Pashov
Прекрасный по своему содержанию твит от хорошего аудитора, который должен понять каждый.
Основной перевод: Есть некоторая причина, почему профессия называется Исследователь по безопасности смарт контрактов, так как вы должны быть хороши в поисковых мероприятиях. Прежде чем просить совет или задавать вопрос, попробуйте поискать ответ в Твиттере или Гугл. Так вы сможете усилить свои навыки и знания в данной сфере.
#hint
Прекрасный по своему содержанию твит от хорошего аудитора, который должен понять каждый.
Основной перевод: Есть некоторая причина, почему профессия называется Исследователь по безопасности смарт контрактов, так как вы должны быть хороши в поисковых мероприятиях. Прежде чем просить совет или задавать вопрос, попробуйте поискать ответ в Твиттере или Гугл. Так вы сможете усилить свои навыки и знания в данной сфере.
#hint
👍8
Немного о конкурсах и аудиторах
На днях думал о том, что ваши результаты в публичных конкурсных аудитах, говорят больше, чем какие-либо другие профессиональные достижения. В частности для аудиторов.
У вас может быть свой личный репо на GitHub, куда вы скидываете свои отчеты по частным аудитам, работа в компании с громкими проектами, свои каналы и блоги, где вы описываете уязвимости или разбираете взломы, но пара High или Med найденных уязвимостей в публичных конкурсах и ваше имя под ними вкупе с размером выплаты за них, скажут больше, чем все вышеперечисленное.
Тоже самое и с устройством на работу. Вместо того, чтобы присылать резюме с описанием, какие проекты вы делали, сколько учились и какой крутой вы специалист, можно будет просто присылать свой рейтинг из таблицы, например на code4rena, и выдержки из финальных отчетов с вашем именем. Уверен, что это качественно сыграет роль в найме, в том числе в зарубежных компаниях.
Поэтому, если вы планируете полноценно работать аудитором, то лучше делать ставку на публичные конкурсные платформы.
#hint
На днях думал о том, что ваши результаты в публичных конкурсных аудитах, говорят больше, чем какие-либо другие профессиональные достижения. В частности для аудиторов.
У вас может быть свой личный репо на GitHub, куда вы скидываете свои отчеты по частным аудитам, работа в компании с громкими проектами, свои каналы и блоги, где вы описываете уязвимости или разбираете взломы, но пара High или Med найденных уязвимостей в публичных конкурсах и ваше имя под ними вкупе с размером выплаты за них, скажут больше, чем все вышеперечисленное.
Тоже самое и с устройством на работу. Вместо того, чтобы присылать резюме с описанием, какие проекты вы делали, сколько учились и какой крутой вы специалист, можно будет просто присылать свой рейтинг из таблицы, например на code4rena, и выдержки из финальных отчетов с вашем именем. Уверен, что это качественно сыграет роль в найме, в том числе в зарубежных компаниях.
Поэтому, если вы планируете полноценно работать аудитором, то лучше делать ставку на публичные конкурсные платформы.
#hint
👍8❤1
Аудит вне рамок - 10
У меня какой-то период восхищения работой аудитора Trust. Если, читая обычные отчеты, мне попадались описания достаточно прямолинейных уязвимостей, то у него они какие-то более изощренные.
Вот один из его отчетов для протокола Holograph. Описания багов вы можете найти в статье, а я, как обычно, укажу на некоторые моменты.
Обращаем внимание при аудите
1) Несколько ошибок было, где функция полагалась на tx.gasprice. Это могло привести как к средним, так и высоким степеням риска. Складывается такое ощущение, что "tx." вообще должен стать красным флагом для аудитора.
2) Если протокол работает на нескольких сетях, то нужно учитывать стоимость газа на той, которая будет оплачивать проведение транзакции.
3) Если протокол использует свои собственные вариации стандартов ERC20, ERC721, ERC1155 и других, то нужно очень внимательно их изучить, чтобы понимать разницу в кодах и представлять, к чему могут привести последствия.
4) Если работаете с количеством газа, то обращайте внимание, в каком месте в assembly учитывается этот opcode.
5) Если в проекте используются EIP, которые официально не добавили в сеть, то нужно дополнительно изучать его документацию, на предмет возможности использования в протоколе.
6) Не подсчитывайте стоимость газа для пересылки самого Эфира, так как он может "застрять" в контракте навсегда.
Отличный отчет, который помог мне узнать, что в контрактах могут быть большие проблемы, если он использует собственные функции для работы с количеством газа.
#audit #outofbox
У меня какой-то период восхищения работой аудитора Trust. Если, читая обычные отчеты, мне попадались описания достаточно прямолинейных уязвимостей, то у него они какие-то более изощренные.
Вот один из его отчетов для протокола Holograph. Описания багов вы можете найти в статье, а я, как обычно, укажу на некоторые моменты.
Обращаем внимание при аудите
1) Несколько ошибок было, где функция полагалась на tx.gasprice. Это могло привести как к средним, так и высоким степеням риска. Складывается такое ощущение, что "tx." вообще должен стать красным флагом для аудитора.
2) Если протокол работает на нескольких сетях, то нужно учитывать стоимость газа на той, которая будет оплачивать проведение транзакции.
3) Если протокол использует свои собственные вариации стандартов ERC20, ERC721, ERC1155 и других, то нужно очень внимательно их изучить, чтобы понимать разницу в кодах и представлять, к чему могут привести последствия.
4) Если работаете с количеством газа, то обращайте внимание, в каком месте в assembly учитывается этот opcode.
5) Если в проекте используются EIP, которые официально не добавили в сеть, то нужно дополнительно изучать его документацию, на предмет возможности использования в протоколе.
6) Не подсчитывайте стоимость газа для пересылки самого Эфира, так как он может "застрять" в контракте навсегда.
Отличный отчет, который помог мне узнать, что в контрактах могут быть большие проблемы, если он использует собственные функции для работы с количеством газа.
#audit #outofbox
👍3
Необычная функция
Просто хочу поделиться необычной логикой работы функции, которую я вчера встретил в аудите. За все время обучения лично я столкнулся с этим впервые, что вызвало некоторые недоумения.
Я постараюсь разложить ее "по полочкам". Итак, вот сам контракт, если вдруг кому будет интересно.
И там есть такая функция (я ее обрезал, убрав не интересные части):
function stake (
AssetType _assetType,
uint256 _timelockId,
uint256,
uint256,
uint256
) external nonReentrant {
uint256 timelockOption = timelockOptions[_assetType][_timelockId];
function (uint256) _s1 = _stakeS1Citizen;
function (uint256) _s2 = _stakeS2Citizen;
function (uint256) _b = _stakeBytes;
function (uint256) _lp = _stakeLP;
function (uint256) _stake;
assembly {
switch _assetType
case 0 {
_stake := _s1
}
case 1 {
_stake := _s2
}
case 2 {
_stake := _b
}
case 3 {
_stake := _lp
}
default {}
}
_stake(timelockOption);
}
Возможно, для опытным разработчиков она окажется простой, но для других - интересным опытом.
Обратите внимание, что в параметрах функции 5 аргументов, 3 из которых обозначены просто как тип uint256 без переменных.
Далее, я не совсем разобрался, как называется это действие, но мы создаем некие поинтеры на другие функции в контракте и кладем их в переменные _s1, _s2, _b, _lp.
_stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - да, это все функции в данном контракте, например:
function _stakeS1Citizen (uint256 _timelock) private {}
Также нужно учесть, что в данном примере, один из аргументов в функции, assetType - это enum. Вот как он выглядит:
enum AssetType {S1_CITIZEN, S2_CITIZEN, BYTES, LP}
Т.е. вы поняли, что происходит в функции?
Мы создали поинтеры на другие функции в контракте, а затем через assembler прогнались по enum и переопределили в поинтер _stake необходимую для нас опцию!
Другими словами, исполнение данной функции продолжится уже в другой функции, учитывая значения AssetType!
Дальше еще круче!
Помните те 3 безыменных аргумента uint256 в функции?
Они передаются в последующие функции, как calldata! Например, одна из функция такая:
function _stakeBytes (uint256) ) private {
uint256 amount;
uint256 citizenId;
uint256 seasonId;
assembly{
amount := calldataload(0x44)
citizenId := calldataload(0x64)
seasonId := calldataload(0x84)
}
}
Эта calldata из безымянных uint256 передается в другие функции и расшифровывается в assembly. И что самое интересное, во всех 4 функциях _stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - расшифровываются разные calldata в зависимости от полученных в главное функции stake!
В общем, меня впечатлил данный контракт! Надеюсь и вам он понравится.
#function
Просто хочу поделиться необычной логикой работы функции, которую я вчера встретил в аудите. За все время обучения лично я столкнулся с этим впервые, что вызвало некоторые недоумения.
Я постараюсь разложить ее "по полочкам". Итак, вот сам контракт, если вдруг кому будет интересно.
И там есть такая функция (я ее обрезал, убрав не интересные части):
function stake (
AssetType _assetType,
uint256 _timelockId,
uint256,
uint256,
uint256
) external nonReentrant {
uint256 timelockOption = timelockOptions[_assetType][_timelockId];
function (uint256) _s1 = _stakeS1Citizen;
function (uint256) _s2 = _stakeS2Citizen;
function (uint256) _b = _stakeBytes;
function (uint256) _lp = _stakeLP;
function (uint256) _stake;
assembly {
switch _assetType
case 0 {
_stake := _s1
}
case 1 {
_stake := _s2
}
case 2 {
_stake := _b
}
case 3 {
_stake := _lp
}
default {}
}
_stake(timelockOption);
}
Возможно, для опытным разработчиков она окажется простой, но для других - интересным опытом.
Обратите внимание, что в параметрах функции 5 аргументов, 3 из которых обозначены просто как тип uint256 без переменных.
Далее, я не совсем разобрался, как называется это действие, но мы создаем некие поинтеры на другие функции в контракте и кладем их в переменные _s1, _s2, _b, _lp.
_stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - да, это все функции в данном контракте, например:
function _stakeS1Citizen (uint256 _timelock) private {}
Также нужно учесть, что в данном примере, один из аргументов в функции, assetType - это enum. Вот как он выглядит:
enum AssetType {S1_CITIZEN, S2_CITIZEN, BYTES, LP}
Т.е. вы поняли, что происходит в функции?
Мы создали поинтеры на другие функции в контракте, а затем через assembler прогнались по enum и переопределили в поинтер _stake необходимую для нас опцию!
Другими словами, исполнение данной функции продолжится уже в другой функции, учитывая значения AssetType!
Дальше еще круче!
Помните те 3 безыменных аргумента uint256 в функции?
Они передаются в последующие функции, как calldata! Например, одна из функция такая:
function _stakeBytes (uint256) ) private {
uint256 amount;
uint256 citizenId;
uint256 seasonId;
assembly{
amount := calldataload(0x44)
citizenId := calldataload(0x64)
seasonId := calldataload(0x84)
}
}
Эта calldata из безымянных uint256 передается в другие функции и расшифровывается в assembly. И что самое интересное, во всех 4 функциях _stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - расшифровываются разные calldata в зависимости от полученных в главное функции stake!
В общем, меня впечатлил данный контракт! Надеюсь и вам он понравится.
#function
👍7🤯1
Как стать хорошим аудитором
В обучении продажам популярные коучи и эксперты любят повторять одну фразу: "Хороший продажник воспринимает доллар в кармане другого продажника, как личное оскорбление". И я подумал, что это прекрасно применимо и к аудиторам.
По сути, в этой сфере получается то, что "крутость аудитора" пропорционально его заработку: чем больше ты зарабатываешь, тем более крутой ты профи.
Если мы будем стараться "выжимать" из аудитов по-максимому, то уже напрямую сможем конкурировать с топовыми аудиторами, типа Trust, и "забирать доллары из их кармана".
Вероятно, потому мне и нравится эта профессия: что ты сам отвечаешь за свой заработок, свой рост и свою профессиональную репутацию.
#мысливслух
В обучении продажам популярные коучи и эксперты любят повторять одну фразу: "Хороший продажник воспринимает доллар в кармане другого продажника, как личное оскорбление". И я подумал, что это прекрасно применимо и к аудиторам.
По сути, в этой сфере получается то, что "крутость аудитора" пропорционально его заработку: чем больше ты зарабатываешь, тем более крутой ты профи.
Если мы будем стараться "выжимать" из аудитов по-максимому, то уже напрямую сможем конкурировать с топовыми аудиторами, типа Trust, и "забирать доллары из их кармана".
Вероятно, потому мне и нравится эта профессия: что ты сам отвечаешь за свой заработок, свой рост и свою профессиональную репутацию.
#мысливслух
👍7
Аудит вне рамок - 11
Пока я полностью погружен в новый конкурсный аудит, предлагаю вам ознакомиться с интересным разбором уязвимостей протокола PartyDao, снова от Trust.
Обращаем внимание при аудите
Больше всего в данном отчете меня привлекло то, что, несмотря на огромное количество проверок при создании предложений (proposals) в Dao, всегда можно найти несколько критический уязвимостей.
Когда мы имеем дело с proposals, то должны проверять не малое количество сценариев и нюансов работы с ними:
1) В какие временные рамки можно создавать предложения? Можно ли указать прошедшее время?
2) Кто может создавать предложения?
3) Можно ли перезаписывать предложения?
4) Кто может голосовать?
5) Как фиксируются голоса: на основе баланса, по snapshot или как-то еще?
6) Можно ли создавать предложение и сразу активировать его, или есть период охлаждения?
7) Можно ли создавать несколько предложений с одного аккаунта?
8) Что будет если создающий предложение может быть в нескольких ролях: например, хакер и он же владелец NFT, пользователь и он же участник Dao, пользователь и он же покупатель NFT и т.д.
При этом особое внимание нужно обращать на проверки, типа require и if, продумывая, как и кто может обойти их.
В общем, аудит с proposals лучше проводить нескольким аудиторам, которые смогут посмотреть на проект с разных точек зрения.
#audit #outofbox
Пока я полностью погружен в новый конкурсный аудит, предлагаю вам ознакомиться с интересным разбором уязвимостей протокола PartyDao, снова от Trust.
Обращаем внимание при аудите
Больше всего в данном отчете меня привлекло то, что, несмотря на огромное количество проверок при создании предложений (proposals) в Dao, всегда можно найти несколько критический уязвимостей.
Когда мы имеем дело с proposals, то должны проверять не малое количество сценариев и нюансов работы с ними:
1) В какие временные рамки можно создавать предложения? Можно ли указать прошедшее время?
2) Кто может создавать предложения?
3) Можно ли перезаписывать предложения?
4) Кто может голосовать?
5) Как фиксируются голоса: на основе баланса, по snapshot или как-то еще?
6) Можно ли создавать предложение и сразу активировать его, или есть период охлаждения?
7) Можно ли создавать несколько предложений с одного аккаунта?
8) Что будет если создающий предложение может быть в нескольких ролях: например, хакер и он же владелец NFT, пользователь и он же участник Dao, пользователь и он же покупатель NFT и т.д.
При этом особое внимание нужно обращать на проверки, типа require и if, продумывая, как и кто может обойти их.
В общем, аудит с proposals лучше проводить нескольким аудиторам, которые смогут посмотреть на проект с разных точек зрения.
#audit #outofbox
Стрим от Патрика
До конца недели я буду плотно работать с конкурсным аудитом zkSync Era. Даже, если ничего не получится найти, то хотя бы узнаю, как работает проект в деталях.
А пока что, Патрик Коллинс, создатель 32 часового обучающего видео по Solidity, проводит ежедневные стримы на Твитч, в которых делает аудит вживую.
Для тех, кто не знал, Патрик недавно ушел с ChainLink и открыл свою аудиторскую компанию. Полагаю, так он хочет привлечь к ней внимание.
Ну, а для нас, это будет хорошим поводом посмотреть, как проходит работа аудитора: от подготовки до просмотра кода.
Первый стрим уже был вчера. Сегодня будет новый в 23:30 по мск.
Записи изначально сохраняются на Твитч, но он планирует позже выложить их на Ютуб.
Ссылка на канал Патрика на Твитч.
Всем приятного просмотра.
#audit
До конца недели я буду плотно работать с конкурсным аудитом zkSync Era. Даже, если ничего не получится найти, то хотя бы узнаю, как работает проект в деталях.
А пока что, Патрик Коллинс, создатель 32 часового обучающего видео по Solidity, проводит ежедневные стримы на Твитч, в которых делает аудит вживую.
Для тех, кто не знал, Патрик недавно ушел с ChainLink и открыл свою аудиторскую компанию. Полагаю, так он хочет привлечь к ней внимание.
Ну, а для нас, это будет хорошим поводом посмотреть, как проходит работа аудитора: от подготовки до просмотра кода.
Первый стрим уже был вчера. Сегодня будет новый в 23:30 по мск.
Записи изначально сохраняются на Твитч, но он планирует позже выложить их на Ютуб.
Ссылка на канал Патрика на Твитч.
Всем приятного просмотра.
#audit
👍9
Соберем воркшоп / шеринг / конфу? Часть 2
Ранее я делал пост с предложением собрать небольшой онлайн воркшоп или конференцию. Вот ссылка, если хотите прочитать больше.
Если говорить кратко, то я хотел сделать некоторый онлайн проект на регулярной основе, где спикеры делились бы знаниями и последними новостями из мира web3.
Настало время собрать спикеров.
На данный момент, есть несколько человек, которые готовы раскрыть темы аудита, абстрактных аккаунтов и lens протокола.
Если вы хотите выступить спикером и раскрыть интересующую вас тему, то напишите мне в личку или в комментариях к посту.
Позже мы создадим мини-чат для спикеров, чтобы обговорить темы детальнее, а также обсудить дату и время, которая будет удобна для всех.
Не бойтесь, если думаете, что у вас не хватит опыта или просто стесняетесь выступать с презентацией. Главное, чтобы тема вас зажигала и вы могли рассказать о ней. А с презентацией мы поможем.
Кто готов?
P.S. Буду признателен, если сделаете репост в свои каналы и чаты, или просто продублируете сообщение о наборе спикеров для онлайн конференции.
#conf #workshop
Ранее я делал пост с предложением собрать небольшой онлайн воркшоп или конференцию. Вот ссылка, если хотите прочитать больше.
Если говорить кратко, то я хотел сделать некоторый онлайн проект на регулярной основе, где спикеры делились бы знаниями и последними новостями из мира web3.
Настало время собрать спикеров.
На данный момент, есть несколько человек, которые готовы раскрыть темы аудита, абстрактных аккаунтов и lens протокола.
Если вы хотите выступить спикером и раскрыть интересующую вас тему, то напишите мне в личку или в комментариях к посту.
Позже мы создадим мини-чат для спикеров, чтобы обговорить темы детальнее, а также обсудить дату и время, которая будет удобна для всех.
Не бойтесь, если думаете, что у вас не хватит опыта или просто стесняетесь выступать с презентацией. Главное, чтобы тема вас зажигала и вы могли рассказать о ней. А с презентацией мы поможем.
Кто готов?
P.S. Буду признателен, если сделаете репост в свои каналы и чаты, или просто продублируете сообщение о наборе спикеров для онлайн конференции.
#conf #workshop
❤6
По следам аудита zkSync Era. Часть 1
Вчера закончился вышеназванный конкурсный аудит и мне хотелось бы сказать несколько слов о нем.
Для начала, упомяну, что я пропустил февральский аудит Optimism, так после первого взгляда решил, что он еще "не моего поля ягода". А зря...
По своей сути, zkSync, так же как и Optimism, является layer 2 от Эфира. Другими словами, вы проводите аудит смарт контрактов другого уровня, нежели популярные протоколы с nft и токенами.
Не могу сказать, что мои поиски багов увенчались успехом, тем не менее я вынес для себя несколько уроков, которые могут быть полезны и вам.
1. Чтение документации происходит на всех уровнях аудита.
Раньше я полагал, что аудитору необходимо заранее прочитать все имеющиеся доки по протоколу, а потом уже плотно садится за просмотр кода. Другими словами, прочитал описание проекта, сделал заметки, понял основную идею и вперед на поиски.
Теперь же я понимаю, что изучение доков идет на всех уровнях аудита. Вы читаете первый раз для общего понимания, затем перечитываете еще раз и делаете заметки, уже после, аудируя конкретный контракт, постоянно перечитываете информацию по логике конкретной функции и ее хода.
Только так вы сможете понять сразу несколько вещей:
- Что делает эта конкретная функция?
- Какой результат ее исполнения должен быть?
И что самое главное:
- Что подразумевал разработчик, когда ее писал?
- Какой ход исполнения, может нарушить результат?
Интересно то, что на многих курсах или интервью, я слышал много раз о том, что очень важно изучать всю доступную информацию о протоколе перед аудитом. Но никто не говорил, как это делает он, или вообще, как это делать.
#zksync #era #audit #feedback
Вчера закончился вышеназванный конкурсный аудит и мне хотелось бы сказать несколько слов о нем.
Для начала, упомяну, что я пропустил февральский аудит Optimism, так после первого взгляда решил, что он еще "не моего поля ягода". А зря...
По своей сути, zkSync, так же как и Optimism, является layer 2 от Эфира. Другими словами, вы проводите аудит смарт контрактов другого уровня, нежели популярные протоколы с nft и токенами.
Не могу сказать, что мои поиски багов увенчались успехом, тем не менее я вынес для себя несколько уроков, которые могут быть полезны и вам.
1. Чтение документации происходит на всех уровнях аудита.
Раньше я полагал, что аудитору необходимо заранее прочитать все имеющиеся доки по протоколу, а потом уже плотно садится за просмотр кода. Другими словами, прочитал описание проекта, сделал заметки, понял основную идею и вперед на поиски.
Теперь же я понимаю, что изучение доков идет на всех уровнях аудита. Вы читаете первый раз для общего понимания, затем перечитываете еще раз и делаете заметки, уже после, аудируя конкретный контракт, постоянно перечитываете информацию по логике конкретной функции и ее хода.
Только так вы сможете понять сразу несколько вещей:
- Что делает эта конкретная функция?
- Какой результат ее исполнения должен быть?
И что самое главное:
- Что подразумевал разработчик, когда ее писал?
- Какой ход исполнения, может нарушить результат?
Интересно то, что на многих курсах или интервью, я слышал много раз о том, что очень важно изучать всю доступную информацию о протоколе перед аудитом. Но никто не говорил, как это делает он, или вообще, как это делать.
#zksync #era #audit #feedback
👍2🔥1👏1
По следам аудита zkSync Era. Часть 2
Далее еще один момент, который редко где упоминают.
2. Задавайте вопросы разработчикам и общайтесь в чатах конкурса.
Не зря code4rena и sherlock создают отдельные ветки в своем Дискорде и представляют команду разработчиков или ответственное лицо, который готов отвечать на вопросы.
За время аудита я задал более 20 различных вопросов по zkSync одному из разработчиков. И на каждый был получен детальный ответ! Это сильно помогло мне понять идею некоторых действий и функций.
Не бойтесь писать им в личку! Используйте гугл переводчик, если есть проблемы с английским. Во-первых, это в их интересах дать качественные ответы, которые, возможно, помогут сделать их проект безопаснее. А, во-вторых, это поможет вам лично разобраться с деталями, возможно, найти баг и получить вознаграждение.
#zksync #era #audit #feedback
Далее еще один момент, который редко где упоминают.
2. Задавайте вопросы разработчикам и общайтесь в чатах конкурса.
Не зря code4rena и sherlock создают отдельные ветки в своем Дискорде и представляют команду разработчиков или ответственное лицо, который готов отвечать на вопросы.
За время аудита я задал более 20 различных вопросов по zkSync одному из разработчиков. И на каждый был получен детальный ответ! Это сильно помогло мне понять идею некоторых действий и функций.
Не бойтесь писать им в личку! Используйте гугл переводчик, если есть проблемы с английским. Во-первых, это в их интересах дать качественные ответы, которые, возможно, помогут сделать их проект безопаснее. А, во-вторых, это поможет вам лично разобраться с деталями, возможно, найти баг и получить вознаграждение.
#zksync #era #audit #feedback
👍6
По следам аудита zkSync Era. Часть 3
Ну, и последний, не совсем очевидный момент, но:
3. На следующий аудит вы потратите меньше сил.
Проекты зачастую возвращаются на конкурсную площадку через некоторое время, после исправлений и совершенствований предыдущего аудита.
Вы уже будете знать проект изнутри, понимать "путь" функций, знать о найденных багах, а, соответственно, и о проблемных местах, поэтому будет гораздо легче проводить новое расследование.
И все это вы получите, не говоря уж о том, что знатно прокачаете свои навыки.
В конце, хотел бы добавить свое собственное наблюдение по конкурсным проектам.
Я бы порекомендовал начинающим брать более сложные проекты, чтобы начать формировать свой собственный формат аудита. С чего начинать, как двигаться, какие инструменты использовать и т.д.
У меня было так, что я уделял меньше внимания проектам, которые считал простыми. Типа, просмотрел, нашел - не нашел, закрыл. Со сложными - хотелось закопаться в код и доки на пару суток и понять, в чем там дело.
Это помогает мне развиваться. Надеюсь и вы сможете найти для себя пару новых идеи для следующего своего аудита.
#zksync #era #audit #feedback
Ну, и последний, не совсем очевидный момент, но:
3. На следующий аудит вы потратите меньше сил.
Проекты зачастую возвращаются на конкурсную площадку через некоторое время, после исправлений и совершенствований предыдущего аудита.
Вы уже будете знать проект изнутри, понимать "путь" функций, знать о найденных багах, а, соответственно, и о проблемных местах, поэтому будет гораздо легче проводить новое расследование.
И все это вы получите, не говоря уж о том, что знатно прокачаете свои навыки.
В конце, хотел бы добавить свое собственное наблюдение по конкурсным проектам.
Я бы порекомендовал начинающим брать более сложные проекты, чтобы начать формировать свой собственный формат аудита. С чего начинать, как двигаться, какие инструменты использовать и т.д.
У меня было так, что я уделял меньше внимания проектам, которые считал простыми. Типа, просмотрел, нашел - не нашел, закрыл. Со сложными - хотелось закопаться в код и доки на пару суток и понять, в чем там дело.
Это помогает мне развиваться. Надеюсь и вы сможете найти для себя пару новых идеи для следующего своего аудита.
#zksync #era #audit #feedback
👍3
Найденный баг в Optimism
Хочу тут еще сделать пост о найденном баге, который принес Trust и Obront + 150к в конкурсном аудите. Вот ссылка на сам баг.
Мне пришлось перечитывать его несколько раз, что понять его смысл. Вероятно, вы сможете осознать его быстрее.
Как я сам понял, недочёт крылся в расчетах газа для проведения транзакции. В одной из особенный функций Оптимизм была заложена идея, что пользователь может на свой страх и риск провести транзакцию, которая будет стоить в разы меньше, чем если бы была осуществлена обычным способом. Сама транзакция банальна - перевод денег с L2 на L1.
Так вот, тут расчеты основывали на проверке:
require(gasleft() >= _tx.gasLimit + 20000, "...");
которая была перед вызовом:
bool success = SafeCall.call(
_tx.target,
gasleft() - 20000,
_tx.value,
_tx.data
);
и все бы ничего, если между ними не было установки переменной: l2Sender = _tx.sender.
Разработчики не учли, что и это тоже требует расхода газа.
В связи с этим расход газа, требующийся для прохождения проверки require, отличался от количества газа, которое требовалось для успешного выполнении транзакции.
Если газа не хватало, то активы пользователя навсегда блокировались бы на контракте.
Вот такая маленькая деталь принесла такие большие деньги!
#audit #optimism
Хочу тут еще сделать пост о найденном баге, который принес Trust и Obront + 150к в конкурсном аудите. Вот ссылка на сам баг.
Мне пришлось перечитывать его несколько раз, что понять его смысл. Вероятно, вы сможете осознать его быстрее.
Как я сам понял, недочёт крылся в расчетах газа для проведения транзакции. В одной из особенный функций Оптимизм была заложена идея, что пользователь может на свой страх и риск провести транзакцию, которая будет стоить в разы меньше, чем если бы была осуществлена обычным способом. Сама транзакция банальна - перевод денег с L2 на L1.
Так вот, тут расчеты основывали на проверке:
require(gasleft() >= _tx.gasLimit + 20000, "...");
которая была перед вызовом:
bool success = SafeCall.call(
_tx.target,
gasleft() - 20000,
_tx.value,
_tx.data
);
и все бы ничего, если между ними не было установки переменной: l2Sender = _tx.sender.
Разработчики не учли, что и это тоже требует расхода газа.
В связи с этим расход газа, требующийся для прохождения проверки require, отличался от количества газа, которое требовалось для успешного выполнении транзакции.
Если газа не хватало, то активы пользователя навсегда блокировались бы на контракте.
Вот такая маленькая деталь принесла такие большие деньги!
#audit #optimism
👍6
По следам аудита от Патрика Коллинса
Выше я делал пост о том, что создатель 32-часового курса по Solidity, Патрик Коллинс, открыл свою аудиторскую компанию и решил провести марафон на несколько дней, делая аудит одного из проектов вживую на стриме.
Я посмотрел его стримы и, таки, мне есть, что сказать.
Точнее обратиться к новичкам и "вечно обучающимся". Не тратьте время на 101% изучения языка, способов проведения тестов и постоянного надумывания, что у вас не хватает какого-нибудь опыта. Всего у вас хватает!
Патрик, не смотря на его опыт и знания, разрешает себе заглядывать в документацию Foundry, EVM, wikipedia, чтобы посмотреть, как реализовать конкретный тест или, что значит этот "сдвиг".
Это нормально! Вы не обязаны знать все, что связано с языком и работой Эфира, чтобы начать что-то делать. Просто невозможно держать все в голове.
Поэтому, немного расслабьтесь и приступайте к практике прямо сегодня.
#audit #feedback
Выше я делал пост о том, что создатель 32-часового курса по Solidity, Патрик Коллинс, открыл свою аудиторскую компанию и решил провести марафон на несколько дней, делая аудит одного из проектов вживую на стриме.
Я посмотрел его стримы и, таки, мне есть, что сказать.
Точнее обратиться к новичкам и "вечно обучающимся". Не тратьте время на 101% изучения языка, способов проведения тестов и постоянного надумывания, что у вас не хватает какого-нибудь опыта. Всего у вас хватает!
Патрик, не смотря на его опыт и знания, разрешает себе заглядывать в документацию Foundry, EVM, wikipedia, чтобы посмотреть, как реализовать конкретный тест или, что значит этот "сдвиг".
Это нормально! Вы не обязаны знать все, что связано с языком и работой Эфира, чтобы начать что-то делать. Просто невозможно держать все в голове.
Поэтому, немного расслабьтесь и приступайте к практике прямо сегодня.
#audit #feedback
👍10❤1
Аудит вне рамок - 12
Интересный аудиторский отчет протокола Rysk, который попросил Trust посмотреть один единственный контракт, который напрямую связан с UniswapV3.
Стоит отметить, что только в этом одном контракте аудитор нашел 2 High, 4 Medium и 4 Low проблемы. И, не смотря на то, что некоторые ошибки можно было найти просто внимательно вчитываясь в код и его логику, несколько нюансов нужно было знать наверняка и исследовать прицельно.
Обращаем внимание при аудите
Если не знаете какой-либо момент из популярного протокола, который используется в контракте, для которого вы делаете аудит, то стоит потратить некоторое время для изучения данного нюанса.
Также и с sqrtPriceX96 в UniswapV3. Вот кто из вас, не заглядывая в доки, может сказать, за что он отвечает? В моем случае, мне будет трудно объяснить это даже, заглянув в документацию...
Два бага в контракте были основаны на том, что разработчики не до конца понимали особенностей работы с sqrtPriceX96 (TRST-M-1, TRST-M-3).
На данный момент, простыми словами эти баги я описать не могу, поэтому пошел изучать этот вопрос глубже.
#audit #outofbox
Интересный аудиторский отчет протокола Rysk, который попросил Trust посмотреть один единственный контракт, который напрямую связан с UniswapV3.
Стоит отметить, что только в этом одном контракте аудитор нашел 2 High, 4 Medium и 4 Low проблемы. И, не смотря на то, что некоторые ошибки можно было найти просто внимательно вчитываясь в код и его логику, несколько нюансов нужно было знать наверняка и исследовать прицельно.
Обращаем внимание при аудите
Если не знаете какой-либо момент из популярного протокола, который используется в контракте, для которого вы делаете аудит, то стоит потратить некоторое время для изучения данного нюанса.
Также и с sqrtPriceX96 в UniswapV3. Вот кто из вас, не заглядывая в доки, может сказать, за что он отвечает? В моем случае, мне будет трудно объяснить это даже, заглянув в документацию...
Два бага в контракте были основаны на том, что разработчики не до конца понимали особенностей работы с sqrtPriceX96 (TRST-M-1, TRST-M-3).
На данный момент, простыми словами эти баги я описать не могу, поэтому пошел изучать этот вопрос глубже.
#audit #outofbox
👍1