>
>
Статический анализатор кода PVS-Studio …

Екатерина Никифорова
Статей: 7

Статический анализатор кода PVS-Studio как защита от уязвимостей нулевого дня

Угроза нулевого дня (англ. zero day) – это термин, обозначающий уязвимости, допущенные при разработке, которые еще не были обнаружены. Такие уязвимости могут использоваться злоумышленниками, что в итоге затронет и репутацию компании. Перед разработчиками стоит задача максимально сократить количество дефектов в коде, которые могут стать причиной такой уязвимости. Одним из инструментов, помогающих выявить дефекты безопасности, является статический анализатор кода PVS-Studio для C, C++, C#, Java.

Угроза нулевого дня

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

Некоторым организациям везло, их уязвимость находилась людьми, которые не собирались ей пользоваться, и они просто предоставляли информацию о проблеме. Например, такое было с macOS. Или выходило обновление, которое, помимо новых фич, еще и случайно исправляло угрозу нулевого дня.

Однако бывали и иные ситуации. Например, Google Chrome в свое время срочно пришлось устранять уязвимость, позволяющую злоумышленнику удалённо осуществлять выполнение произвольного кода на устройстве жертвы.

Проблема этой угрозы в том, что от нее невозможно защититься на 100%, так как тяжело защищаться от того, о чем ты пока не знаешь. Однако есть способы уменьшить вероятность возникновения такой угрозы в своем проекте, и далее мы их обсудим, но для начала немного теории.

Статический анализ

Статический анализ программного кода – процесс проверки программного кода анализатором без запуска самой программы. Статический анализ можно рассматривать как автоматизированный процесс обзора кода. В некоторых случаях по эффективности статический анализ превосходит code review, но его нельзя рассматривать как полноценную альтернативу обзору кода несколькими программистами. Ниже я постаралась кратко расписать плюсы и минусы обзора кода и статического анализа кода относительно друг друга.

Обзор кода

Статический анализ

Возможность выявить не только простые, но и высокоуровневые ошибки

Можно найти ошибки даже не зная о таком паттерне дефектов или уязвимости

Улучшается архитектура приложения и вырабатывается единый стиль кодирования

Можно найти ошибки, с трудом поддающиеся поиску во время обзора кода (например, опечатки)

Высокая цена

Более низкая по сравнению с code review цена

Отнимает много времени у программистов. Необходимо делать перерывы, так как быстро притупляется внимание

Неизбежные ложные срабатывания и необходимость настраивать анализатор

CVE и CWE

Common Vulnerabilities and Exposures (CVE) – база данных программных ошибок, которые могут быть использованы злоумышленниками. CVE была создана для того, чтобы упорядочить известные дефекты программ. В большинстве инструментов информационной безопасности использовались собственные базы данных и имена, и, дабы устранить этот хаос и добавить совместимость с различными инструментами, организация MITRE в 1999 году создала CVE. Однако CVE оказалось недостаточно для оценки безопасности кода. Для этого требуется что-то точнее, с подробным описанием проблем и менее грубое, чем она. Поэтому и была создана база Common Weakness Enumeration (CWE), которая удовлетворяет этим требованиям. Если ошибка есть в списке CWE, то есть вероятность, что она приведет к появлению уязвимости, которой может воспользоваться злоумышленник, и попасть в список CVE. Для наглядности можно посмотреть на приведенную ниже диаграмму Эйлера.

Некоторые статические анализаторы могут подсказывать разработчику, что, к примеру, в проекте используется библиотека, в которой найдена уязвимость. Это позволяет выбрать более новую версию библиотеки, в которой уязвимость уже исправлена, и уменьшить вероятность появления проблем с угрозами, появившимися из-за чужого кода.

С приходом в мир разработки списков CVE и CWE многие инструменты информационной безопасности позаботились об их поддержке, в том числе и статические анализаторы. Такие анализаторы можно расценивать как SAST решение. SAST (Static Application Security Testing) позволяет разработчикам находить уязвимости в исходном коде приложения уже на ранних этапах жизненного цикла разработки программного обеспечения.

Использовать SAST при разработке – еще один вариант минимизирования вероятности появления угрозы нулевого дня. Анализатор, классифицирующий свои ошибки согласно CWE, может подсказать, где скрывается возможная уязвимость. И исправляя эти ошибки, разработчик делает свое приложение надежнее и уменьшает вероятность наступления 0-day угрозы.

Существуют различные инструменты статического тестирования защищенности. Для демонстрации возможностей в борьбе с уязвимостями остановимся на инструменте PVS-Studio. Предупреждения этого анализатора могут классифицироваться как CWE. Рассмотрим несколько примеров.

Предупреждение PVS-Studio: CWE-561: Dead Code (V3021).

public string EncodeImage(....)
{
  if (string.IsNullOrWhiteSpace(inputPath))
  {
    throw new ArgumentNullException("inputPath");
  }
  if (string.IsNullOrWhiteSpace(inputPath))
  {
    throw new ArgumentNullException("outputPath");
  }
  ....
}

В этом коде по невнимательности допустили опечатку. В двух условиях if проверяется одна и та же переменная. Судя по генерируемому исключению, во втором условии должна проверяться переменная outputPath. В результате часть кода является недостижимой.

Такие ошибки выглядят на первый взгляд безобидно. Однако, такое впечатление может быть весьма обманчивым. Рассмотрим очень простую и на первый взгляд тоже безобидную ошибку, связанную с дублированием оператора goto.

В своё время эта ошибка стала причиной появления уязвимости в операционной системе iOS.

Описание уязвимости CVE-2014-1266: The SSLVerifySignedServerKeyExchange function in libsecurity_ssl/lib/sslKeyExchange.c in the Secure Transport feature in the Data Security component in Apple iOS 6.x before 6.1.6 and 7.x before 7.0.6, Apple TV 6.x before 6.0.2, and Apple OS X 10.9.x before 10.9.2 does not check the signature in a TLS Server Key Exchange message, which allows man-in-the-middle attackers to spoof SSL servers by using an arbitrary private key for the signing step or omitting the signing step.

static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, 
                                 bool isRsa, 
                                 SSLBuffer signedParams,
                                 uint8_t *signature, 
                                 UInt16 signatureLen)
{
  OSStatus err;
  ....

  if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
    goto fail;
  if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;
  if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;
  ....

fail:
  SSLFreeBuffer(&signedHashes);
  SSLFreeBuffer(&hashCtx);
  return err;
}

Из-за двойного goto также возникает ситуация с недостижимым кодом. Вне зависимости от условий в операторах if будет выполнен второй оператор goto. Это приводит к тому, что проверка подписи не происходит. Функция возвращает 0, который обозначает, что с подписью все хорошо, и далее программа получает ключ с сервера, даже если с подписью есть проблемы. Этот ключ нужен для шифрования данных при передаче.

Последствия такой простой ошибки оказались весьма серьезны. Поэтому нет смысла рассуждать, насколько опасна та или иная ошибка, классифицируемая как CWE. Её просто следует исправить, тем самым сделав код более безопасным.

Кстати, описанная ошибка легко могла бы быть выявлена анализатором PVS-Studio. Он выдал бы здесь сразу два CWE предупреждения:

Давайте рассмотрим ещё один пример. В далеком 2012 году стало известно о проблеме безопасности в MySQL, при которой злоумышленник мог войти в базу данных MySQL. Далее я приведу отрывок кода, который послужил этому причиной.

Описание CVE-2012-2122: sql/password.c in Oracle MySQL 5.1.x before 5.1.63, 5.5.x before 5.5.24, and 5.6.x before 5.6.6, and MariaDB 5.1.x before 5.1.62, 5.2.x before 5.2.12, 5.3.x before 5.3.6, and 5.5.x before 5.5.23, when running in certain environments with certain implementations of the memcmp function, allows remote attackers to bypass authentication by repeatedly authenticating with the same incorrect password, which eventually causes a token comparison to succeed due to an improperly-checked return value.

typedef char my_bool;
my_bool
check_scramble(const char *scramble_arg, const char *message,
                             const uint8 *hash_stage2)
{
  ....
  return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}

Тип возвращаемого значения функции memcmp - int, а тип возвращаемого значения функции check_scramble - my_bool, фактически - char. В результате происходит неявное приведение int к char, при котором отбрасываются значения старших битов. Это приводило к тому, что примерно в 1 случае из 256 удавалось подключиться с любым паролем, зная имя пользователя.

Опять-таки, эту CWE ошибку можно было бы обезвредить и не дать ей превратиться в CVE ещё на этапе написания кода. Например, статический анализатор PVS-Studio выдает следующее предупреждение: CWE-197 (V642): Numeric Truncation Error.

В продолжение этой темы предлагаю посмотреть статью "Как PVS-Studio может помочь в поиске уязвимостей?".

Заключение

0-day уязвимости – вещь, от которой нет гарантированной защиты. Но вероятность их появления можно значительно уменьшить. Для этого могут быть использованы такие специализированные SAST решения, как PVS-Studio. Если в вашем проекте обнаружатся ошибки, которые можно классифицировать как CWE, то стоит обратить на них внимание и исправить. Несмотря на то, что лишь небольшое количество CWE по итогу пополнит список CVE, устраняя CWE-ошибки, вы защищаете своё приложение от многих потенциальных угроз.

Дополнительные ссылки