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

Уязвимости нулевого дня

Уязвимость нулевого дня (также известная как уязвимость 0-day) — это уязвимость компьютерного программного обеспечения, которая неизвестна или не рассмотрена теми, кто должен быть заинтересован в устранении уязвимости (включая поставщик целевого программного обеспечения). Пока уязвимость не будет устранена, хакеры могут использовать ее, чтобы нанести вред компьютерным программам, данным, дополнительным компьютерам или сети. Этот термин означает, что у разработчиков нет ни дня, чтобы исправить дефект, потому что о нем еще никто не знает. Некоторые известные поставщики и программные продукты, такие как Adobe, Windows, Tor browser и многие другие, в прошлом были подвержены уязвимостям нулевого дня.

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

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

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

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

Статический анализ — это метод проверки исходного кода программы с помощью анализатора без запуска самой программы, который можно рассматривать как автоматизированный обзор кода. Иногда статический анализ может быть намного эффективнее рецензирования кода, но не может полностью заменить его. Я попытался обобщить плюсы и минусы проверки кода и статического анализа по отношению друг к другу в следующей таблице:

Обзор кода

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

Помогает находить не только тривиальные, но и высокоуровневые ошибки

Помогает найти незнакомые дефекты или уязвимости

Помогает улучшить архитектуру программы и выработать единый стиль кодирования.

Помогает найти ошибки, незаметные для человеческого глаза (например, опечатки)

Дорогой

Дешевле, чем код-ревью

Занимает много времени программистов. Перерывы необходимы, так как внимание рецензента быстро ослабевает.

Ложные срабатывания неизбежны; пользователь должен настроить анализатор

CVE и CWE

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

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

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

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

Существует множество инструментов SAST. В качестве примера я возьму анализатор 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: функция SSLVerifySignedServerKeyExchange в libsecurity_ssl/lib/sslKeyExchange.c в функции Secure Transport компонента Data Security в Apple iOS 6.x до 6.1.6 и 7.x до 7.0.6, Apple TV 6.x до версии 6.0.2 и Apple OS X 10.9.x до версии 10.9.2 не проверяют подпись в сообщении обмена ключами сервера TLS, что позволяет злоумышленникам подделывать SSL-серверы с помощью произвольный закрытый ключ для шага подписи или пропуска шага подписи.

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:

  • CWE-561 (V779): мертвый код
  • CWE-483 (V640): неправильное разграничение блоков

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

Уязвимость CVE-2012–2122: sql/password.c в Oracle MySQL 5.1.x до 5.1.63, 5.5.x до 5.5.24, 5.6.x до 5.6.6 и MariaDB 5.1.x до 5.1 .62, 5.2.x до 5.2.12, 5.3.x до 5.3.6 и 5.5.x до 5.5.23 при работе в определенных средах с определенными реализациями функции memcmp позволяет удаленным злоумышленникам обходить аутентификацию путем повторной аутентификации. с тем же неправильным паролем, что в конечном итоге приводит к успешному сравнению маркеров из-за неправильно проверенного возвращаемого значения.

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 может помочь в обнаружении уязвимостей?.

Вывод

Вы не можете быть на 100% уверены, что ваша программа защищена от уязвимостей нулевого дня. Но вы все равно можете сделать их гораздо менее вероятными. Это делается с помощью специализированных инструментов SAST, таких как PVS-Studio. Если в вашем проекте обнаружены дефекты, классифицированные как проблемы CWE, обязательно исправьте их. Несмотря на то, что некоторые из дефектов CWE попадают в список CVE, их исправление помогает защитить вашу программу от многих потенциальных угроз.

использованная литература