Back to Blog

Отчет об аудите безопасности смарт-контрактов Cakepie

Code Auditing
November 30, 2023
9 min read

Отчетная документация

Элемент Описание
Клиент Magpie XYZ
Объект Смарт-контракты CakePie

История версий

Версия Дата Описание
1.0 30 ноября 2023 г. Первый выпуск

1. Введение

1.1 О проверяемых контрактах

Информация Описание
Тип Смарт-контракт
Язык Solidity
Подход Полуавтоматическая и ручная верификация

Объектом данного аудита является репозиторий с кодом смарт-контрактов CakePie^1 от компании Magpie XYZ. Контракты CakePie поддерживают кампанию CakeRush, в рамках которой пользователи могут конвертировать свои токены CAKE или заблокированные позиции CAKE с PancakeSwap в CakePie. Обратите внимание, что в область аудита включены только файлы CakeRush.sol и PancakeStakingBNBChain.sol; остальные файлы в аудит не входят.

Процесс аудита является итеративным. В частности, мы проводим аудит коммитов, исправляющих обнаруженные проблемы. Если возникают новые проблемы, мы продолжаем этот процесс. Значения SHA коммитов во время аудита приведены в следующей таблице. Наш отчет об аудите охватывает код в начальной версии (Version1), а также новый код (в последующих версиях), направленный на исправление проблем, указанных в отчете.

1.2 Модель безопасности

Для оценки рисков мы следуем стандартам и рекомендациям, широко принятым в отрасли и научном сообществе, включая методику оценки рисков OWASP ^2 и перечень распространенных недостатков безопасности (CWE) ^3. Общая степень серьезности риска определяется на основе вероятности и воздействия. В частности, вероятность используется для оценки того, насколько вероятно, что конкретная уязвимость может быть обнаружена и использована злоумышленником, в то время как воздействие используется для измерения последствий успешной эксплуатации.

В данном отчете как вероятность, так и воздействие классифицируются по двум уровням: высокий и низкий соответственно. Их сочетания показаны в Таблице 1.1.

Соответственно, серьезность, измеряемая в этом отчете, классифицируется по трем категориям: Высокая (High), Средняя (Medium), Низкая (Low). Для полноты картины также используется категория Не определено (Undetermined), если риск не поддается точной оценке.

Кроме того, статус обнаруженной позиции попадает в одну из следующих четырех категорий:

  • Не определено Ответ отсутствует.

  • Принято к сведению Проблема получена клиентом, но еще не подтверждена.

  • Подтверждено Проблема признана клиентом, но еще не исправлена.

  • Исправлено Проблема подтверждена и исправлена клиентом.

2. Результаты аудита

Всего нами обнаружено две потенциальные проблемы. Кроме того, у нас есть три рекомендации и одно примечание.

  • Высокий риск: 1

  • Низкий риск: 1

  • Рекомендация: 3

  • Примечание: 1

ID Серьезность Описание Категория Статус
1 Низкая Потенциальное нарушение согласованности состояния после сброса параметров Безопасность ПО Исправлено
2 Высокая Повторное получение наград mCake Безопасность ПО Исправлено
3 - Проверка параметров в функциях инициализации Рекомендация Принято к сведению
4 - Проверка параметров в контрактах CakeRush Рекомендация Исправлено
5 - Дополнительные условия в модификаторах Рекомендация Принято к сведению
6 - Потенциальный риск централизации Примечание -

Подробности представлены в следующих разделах.

2.1 Безопасность ПО

2.1.1 Потенциальное нарушение согласованности состояния после сброса параметров

Элемент Описание
Серьезность Низкая
Статус Исправлено в версии 2
Появилось в Версии 1

Описание Контракт CakeRush распределяет награды в соответствии с рядом параметров. Следующие функции позволяют сопровождающему проекта сбрасывать некоторые из этих параметров:

function resetMultiplier() external onlyOwner {
        uint256 len = rewardMultiplier.length;
        for (uint8 i = 0; i < len; ++i) {
            rewardMultiplier.pop();
            rewardTier.pop();
        }

        tierLength = 0;
    }

    function resetTimeWeighting() external onlyOwner {
        uint256 len = weightedTime.length;
        for (uint8 i = 0; i < len; ++i) {
            weightedTime.pop();
            weighting.pop();
        }

        weightLength = 0;
    }

Листинг 2.1: CakeRush.sol

Однако эти функции сбрасывают только параметры, но не информацию о пользователях, хранящуюся в переменной состояния userInfos. В результате вычисления в контракте CakeRush могут завершиться ошибкой из-за несогласованности состояния. Например, если параметры будут сброшены и установлены неверные значения, вычитание в строке 155 может привести к ошибке из-за целочисленного переполнения снизу (underflow).

function quoteConvert(
        uint256 _amountToConvert,
        address _account
    )
        external
        view
        returns (
            uint256 newUserFactor,
            uint256 newTotalFactor,
            uint256 newUserWeightedFactor,
            uint256 newWeightedTotalFactor
        )
    {
        if (_amountToConvert == 0 || rewardMultiplier.length == 0 || weighting.length == 0)
            return (0, 0, 0, 0);

        UserInfo storage userInfo = userInfos[_account];
        uint256 accumulated = _amountToConvert + userInfo.converted;

        uint256 factorAccuNoWeighting = 0;
        uint256 i = 1;
        while (i < rewardTier.length && accumulated > rewardTier[i]) {
            factorAccuNoWeighting += (rewardTier[i] - rewardTier[i - 1]) * rewardMultiplier[i - 1];
            i++;
        }
        factorAccuNoWeighting += (accumulated - rewardTier[i - 1]) * rewardMultiplier[i - 1];

        uint256 factorToEarnNoWeighting = (factorAccuNoWeighting / DENOMINATOR) - userInfo.factor;

Листинг 2.2: CakeRush.sol

Что еще хуже, если пользователи вызовут функции convert или convertWithCakePool сразу после сброса параметров (до того, как будут установлены новые — например, с помощью атаки типа back-running), это может привести к сбросу общих и взвешенных коэффициентов, записанных в контракте, из-за логики в строках 141-142.

Воздействие Сброс параметров может привести к несогласованному и неверному состоянию.

Предложение Устанавливайте новые параметры после очистки старых.

Отзыв от команды проекта Множители не будут сбрасываться после начала кампании Cake Rush.

2.1.2 Повторное получение наград mCake

Элемент Описание
Серьезность Высокая
Статус Исправлено в версии 3
Появилось в Версии 2

Описание После блокировки токенов CAKE в контракте пользователи могут получать токены mCake в качестве награды через функцию claim. Однако функция содержит ошибку, которая позволяет пользователям забирать награды несколько раз. В следующем сегменте кода, если сумма превышает значение пользователя, происходит перевод или внесение общей суммы. Правильная реализация должна возвращать только положенную сумму, поэтому текущая реализация фактически позволяет пользователю многократно забирать награды mCake.

function claim(bool _isStake) external nonReentrant {
        UserInfo storage userInfo = userInfos[msg.sender];
        if (claimedMCake[msg.sender] >= userInfo.converted) revert AlreadyClaimed();
        if (_isStake && userInfo.converted > 0) {
            if (masterCakepie == address(0)) revert MasterCakepieNotSet();
            IERC20(mCakeOFT).safeApprove(address(masterCakepie), userInfo.converted);
            IMasterCakepie(masterCakepie).depositFor(
                address(mCakeOFT),
                address(msg.sender),
                userInfo.converted
            );
        } else if (userInfo.converted > 0) {
            IERC20(mCakeOFT).transfer(msg.sender, userInfo.converted);
            emit Claim(msg.sender, userInfo.converted);
        }

        claimedMCake[msg.sender] = userInfo.converted;
    }

Листинг 2.3: CakeRush.sol

Воздействие Пользователи могут многократно получать награды mCake.

Предложение Пересмотрите логику получения наград.

2.2 Дополнительные рекомендации

2.2.1 Проверка параметров в функциях инициализации

Элемент Описание
Статус Принято к сведению
Появилось в Версии 1

Описание В функциях инициализации контрактов CakeRush и PancakeStakingBNBChain присутствуют параметры, которые нельзя изменить после инициализации. Рекомендуется проверять правильность этих параметров непосредственно внутри функций инициализации.

function __CakeRush_init(
        address _cake,
        address _mCakeOFT,
        address _masterCakepie
    ) public initializer {
        __Ownable_init();
        __ReentrancyGuard_init();
        __Pausable_init();
        cake = _cake;
        mCakeOFT = _mCakeOFT;
        masterCakepie = _masterCakepie;
    }

Листинг 2.4: CakeRush.sol

Воздействие Н/Д

Предложение Добавьте проверки параметров в функции инициализации.

2.2.2 Проверка параметров в контрактах CakeRush

Элемент Описание
Статус Исправлено в версии 2
Появилось в Версии 1

Описание В контракте CakeRush существует возможность добавления нескольких параметров, касающихся распределения наград. Однако нет проверки того, что эти параметры установлены правильно в соответствии с допущениями контракта. В частности, в функциях setMultiplier и setTimeWeighting необходимо проверять дополнительные условия (например, свойство монотонного возрастания массивов rewardTier и weightedTime).

function setMultiplier(
        uint256[] calldata _multiplier,
        uint256[] calldata _tier
    ) external onlyOwner {
        if (_multiplier.length == 0 || (_multiplier.length != _tier.length)) revert LengthInvalid();

        for (uint8 i = 0; i < _multiplier.length; ++i) {
            if (_multiplier[i] == 0) revert InvalidAmount();
            rewardMultiplier.push(_multiplier[i]);
            rewardTier.push(_tier[i]);
            tierLength += 1;
        }
    }

Листинг 2.5: CakeRush.sol

Воздействие Н/Д

Предложение Проверяйте параметры в функциях, которые их устанавливают.

2.2.3 Дополнительные условия в модификаторах

Элемент Описание
Статус Принято к сведению
Появилось в Версии 1

Описание В контракте CakeRush модификатор _onlyPancakeStaking содержит избыточное условие. Согласно семантике этого модификатора, проверки msg.sender != pancakeStaking было бы достаточно.

modifier _onlyPancakeStaking() {
        if (pancakeStaking == address(0) || msg.sender != pancakeStaking)
            revert OnlyPancakeStaking();
        _;
    }

Листинг 2.6: CakeRush.sol

Воздействие Н/Д

Предложение Удалите избыточные условия из модификатора.

2.3 Примечания

2.3.1 Потенциальный риск централизации

Описание Владелец контракта CakeRush обладает значительными привилегиями по изменению критических конфигураций. Это создает единую точку отказа. Если злоумышленник скомпрометирует владельца, он потенциально сможет вывести систему из строя.

Кроме того, токены CAKE в контракте не обрабатываются явным образом для их блокировки в контракте VECake. Вместо этого CakeRush позволяет владельцу выводить все эти CAKE, что означает обязательное условие блокировки токенов CAKE после вывода. Однако эта логика не гарантируется на уровне кода, что также вызывает опасения по поводу централизации.

Отзыв от команды проекта Команда сделала владельца контракта мультиподписным (multisig) кошельком, чтобы снизить риски.

3. Уведомления и примечания

3.1 Отказ от ответственности

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

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

Область действия данного аудита ограничена кодом, упомянутым в разделе 1.1. Если прямо не указано иное, безопасность самого языка (например, языка Solidity), базовой цепочки инструментов компиляции и вычислительной инфраструктуры не входит в область аудита.

3.2 Процедура аудита

Мы проводим аудит в соответствии со следующей процедурой:

  • Обнаружение уязвимостей Мы сначала сканируем смарт-контракты с помощью автоматических анализаторов кода, а затем вручную проверяем (отклоняем или подтверждаем) найденные ими проблемы.

  • Семантический анализ Мы изучаем бизнес-логику смарт-контрактов и проводим дальнейшее исследование возможных уязвимостей с помощью инструмента автоматического фаззинга (разработанного нашей исследовательской группой). Мы также вручную анализируем возможные сценарии атак совместно с независимыми аудиторами для перекрестной проверки результатов.

  • Рекомендации Мы предоставляем разработчикам полезные советы с точки зрения передовых методов программирования, включая оптимизацию газа, стиль написания кода и т.д.

Основные контрольные точки приведены ниже.

3.2.1 Безопасность ПО

  • Reentrancy (Повторный вход)

  • DoS (Отказ в обслуживании)

  • Контроль доступа

  • Обработка данных и поток данных

  • Обработка исключений

  • Недоверенные внешние вызовы и поток управления

  • Согласованность инициализации

  • Работа с событиями (Events)

  • Ошибочная случайность

  • Неправильное использование системы прокси

3.2.2 Безопасность DeFi

  • Семантическая согласованность

  • Функциональная согласованность

  • Управление правами доступа

  • Бизнес-логика

  • Операции с токенами

  • Чрезвычайные механизмы (Emergency)

  • Безопасность оракулов

  • Белые и черные списки

  • Экономическое воздействие

  • Пакетные переводы (Batch transfer)

3.2.3 Безопасность NFT

  • Дублирование элементов

  • Верификация получателя токена

  • Безопасность офчейн-метаданных

3.2.4 Дополнительные рекомендации

  • Оптимизация потребления газа

  • Качество и стиль кода

Примечание Вышеперечисленные контрольные точки являются основными. Мы можем использовать дополнительные проверки в ходе аудита в зависимости от функциональности проекта.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit