Все наслышаны о так называемых сканерах безопасности: утилитах, позволяющим сканировать удаленные сервера, что называется, «во все порты», на предмет поиска уязвимостей. Также не секрет, что эти утилиты, созданные официально, чтобы помочь администратору сервера проводить аудит безопасности, во всю используются хаксорами для собирания подробной информации об атакуемом сервере (нажал кнопочку scan, и сиди, плюй в потолок, тулза сама все просканит, пошарит базу уязвимостей и выдаст красивый отчет). Да, я имею в виду такие программы, как Nessus (под *nix), Retina, Shadow Security Scanner, Xspider, Languard Network Scanner и другие (под Win32), и тому подобные утилиты — все они тебе известны, покопайся, в конце концов, в рубрике «софт» нашего сайта.

Но вот (почему-то) намного менее популярны утилиты, призванные помочь программисту в его нелегком деле написания какого-нибудь сетевого приложения (анализаторы исходных текстов aka source code scanners). Что, спросишь, какие тут могут быть уязвимости? Тут тебе и переполнение буфера (классика), и форматирование строки, и еще много всяких ошибок, которые может допустить программер в своем труде из нескольких сотен строк. Поэтому сейчас я попытаюсь охватить хотя бы узкий круг таких программ-сканнеров. Узкий — так как будем считать, что приложение, требующее проверки, написано на Си, а программист работает из никсовой консольки. И если с первым все ясно (Си — безусловно, самый популярный язык), то популярность таких программ под unix-like’системы вызвана, во-первых, малым их размером (.tgz-архив с исходниками сканнера редко весит больше 300 кб), а во-вторых, связанной с Free’шными вариациями Юникса (под сим я понимаю Linux, FreeBSD, и иже с ними, как известную альтернативу дорогим unix-системам) свободой софта, ибо серьезные анализаторы исходных текстов (не просто сканнеры) под Win, с GUI, и всеми делами, стоят больших денег (попробуй поискать их в Митино :).

Короче, смысл считаю поясненным. Рассматриваем сканнеры исходного кода под юниксовую консоль (беги срочно ставить линукс :), задача которых — указать программисту на ошибки в их детище, как то: неправильные и потенциально опасные вызовы библиотечных функций, переполнение буфера, и так далее. Перед прочтением рекомендую ознакомиться хотя бы с основными аспектами «теории багов в Си-программах», об этом писали в каком-то из номеров ][, также, помнится, много подобной инфы валялось на Void.ru (правда, он сейчас вроде как закрыт временно 🙁

Да, кстати, пара слов о том, на чем сканнеры тестились. Для тестов использовались вот эти две программы:

test1.zip

Этот исходник взят из дистрибутива рассматриваемой ниже программы pscan, и содержит вызовы и объявления основных функций, в которых могут содержаться различные проблемы, соответственно, программы, содержащие такие функции, могут быть уязвимы. Достоинство программы — в очень хороших комментариях и структуре: последовательно дается возможно небезопасное объявление функции, и сразу — априори безопасный вариант, для сравнения.

test2.zip

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

ITS4

http://www.cigital.com/services/its4

ITS4 (эта аббревиатура — сокращение от английской фразы «It’s The Software Stupid! Security Scanner») — одна из самых известных утилит для статического анализа исходных текстов на языке C/C++ на предмет наличия возможных уязвимостей. ITS4 способна идентифицировать потенциально опасные вызовы функций, которые при различных обстоятельствах могут привести к переполнению буфера, и, соответственно, предупреждать программиста. Надо заметить, что переполнение буфера — это самый частый результат ошибок программиста, на котором основано большинство уязвимостей удаленных систем. Некоторые из этих уязвимостей довольно легко обнаружить (например, использование в коде сишной библиотечной функции gets почти всегда влечет за собой проблемы безопасности). Некоторые же функции более «неуловимы» (strcpy, sprintf) и требуют тщательного анализа, наконец, некоторые вызовы функций априори безопасны (strncpy, strncat), но, как и все остальные, могут быть неправильно использованы, что повлечет за собой дыру в системе безопасности.
Утилита предлагает альтернативные методы локализации и решения найденных потенциальных проблем, все проблемы и рекомендуемые решения берутся из базы данных, которая, будучи представлена в виде файла, всегда может быть обновлена или переделана под себя пользователем.

Разработчики ITS4 с одинаковым успехом используют утилиту для аудита как больших программных продуктов, так и маленьких open-source проектов. Как и все рассматриваемые здесь программы, сканер ITS4 работает в консольном режиме. Утилита сканирует сорц и анализирует вызовы стандартных функций на потенциальную опасность, представляя программисту информацию о возможных последствиях применения той или иной функции, как то: переполнение буфера, форматирование строки, и многое другое. А также степень риска. Помимо этого, утилита выдает краткое описание проблемы и предположения, как ее можно устранить.
Рассмотрим применение утилиты ITS4 в операционной системе
Linux.

Утилита поставляется в стандартном tar.gz архиве, после извлечения всех файлов в отдельную папку и стандартного процесса компиляции (./configure, make, make install) получаем папку its4, в которой содержится три каталога: bin — непосредственно и исполняемым файлом its4, its4 — с базой уязвимостей, и man — со страницей справочника. Всю необходимую информацию о параметрах, с которыми запускается утилита, можно почерпнуть из этой страницы ($ man /its4/man/man1/its4.1), здесь приведем основные параметры с их описанием:

Параметры запуска: $ /.its4 [option]… [file]… 
Параметр file — путь к исходному C/C++ файлу
Флаг option (рассмотрим основные):

—a, -add=name
Добавить новое имя функции в базу данных только для этого сеанса сканирования. 

—D, —no-descriptions
не выводить описания потенциальных проблем (только результаты сканирования)

-i, —ignore=function
Игнорировать анализ данной функции. Может применяться любое количество раз.

-I, —limit=function
Не анализировать никакие функции, кроме указанных. Может применяться любое количество раз.

-o, —output=filename
Вывести отчет сканирования в указанный файл. По умолчанию используется стандартный поток вывода (на экран).

-S, —no-solutions
Не выводить советы по возможному решению проблемы.

-Q, —quiet
«Тихий» режим. Выводится минимум информации, данный флаг аналогичен совместному использованию флагов -D и
-S.

-v, —db-location=file
Указать путь к базе уязвимостей (для возможности держать несколько баз, каждую для определенных целей).

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

Рассмотрим наш пример test1.c:

[root@localhost bin]# [root@localhost bin]# ./its4 /root/scanz/test1.c
/root/scanz/test1.c:38:(Urgent) fprintf
/root/scanz/test1.c:44:(Urgent) fprintf
/root/scanz/test1.c:49:(Urgent) fprintf
Non-constant format strings can often be attacked.
Use a constant format string.
—————-
/root/scanz/test1.c:108:(Urgent) printf
/root/scanz/test1.c:113:(Urgent) printf
/root/scanz/test1.c:118:(Urgent) printf
Non-constant format strings can often be attacked.
Use a constant format string.
—————-
/root/scanz/test1.c:66:(Urgent) sprintf
/root/scanz/test1.c:77:(Urgent) sprintf
/root/scanz/test1.c:96:(Urgent) sprintf
Non-constant format strings can often be attacked.
Use a constant format string.
—————-
/root/scanz/test1.c:130:(Urgent) syslog
Non-constant format strings can often be attacked.
Use a constant format string.
—————-
/root/scanz/test1.c:57:(Very Risky) sprintf
/root/scanz/test1.c:69:(Very Risky) sprintf
/root/scanz/test1.c:99:(Very Risky) sprintf
/root/scanz/test1.c:125:(Very Risky) sprintf
This function is high risk for buffer overflows
Use snprintf if available, or precision specifiers, if available.

Здесь мы видим, что в некоторых строках (38, 108, 130) используются строки с непостоянным (неявно указанным) форматом, что, очевидно, может привести к такой известной ошибке, как форматирование строки. Как решение проблемы, ITS4 предлагает использовать постоянный формат строки. Когда формат строки «непостоянный», т.е. не задан явно, и утилита расценивает уровень опасности как urgent, т.е. «немедленно подлежащий исправлению». В строках же 57..125 (последний блок в отчете ITS4) та же функция (sprintf) может быть причиной переполнения буфера (уровень опасности, как видим, «очень велик»), о чем нас и предупреждает утилита, рекомендуя по возможности использовать более защищенную функцию snprintf, аналогичную данной, но имеющую одним из параметров фиксированное количество передаваемых символов.
Замечу, что гибкость утилиты ITS4 заключается еще и в том, что база уязвимостей может быть как угодно модифицирована пользователем «под себя» для решения конкретных задач.

Flawfinder

http://www.dwheeler.com/flawfinder

Flawfinder (Flaw — трещина, щель, изъян, Find — искать, © Lingvo 7 :), это программа, призванная искать в исходном коде программы уязвимые, с точки зрения безопасности, места. В отличие от известной утилиты ITS4, flawfinder является программным обеспечением, свободно распространяемым в соответствии с Open Source Definition и Free Software Foundation’s GNU project, под лицензией General Public License
(GPL).

Flawfinder также работает под Unix-системами (или, говоря более точно, в соответствии с лицензией на торговую марку «Unix», под Unix-like системами :), тестируется разработчиками под ОС GNU/Linux, и может быть легко портирована под Win32. Для корректной работы требует интерпретатор языка Python версии 1.5 или выше (под версией 1.3 или ниже не функционирует), ибо на языке Python написан. Утилита уже включается в такие дистрибутивы Linux, как Debian, и, возможно, в некоторые другие. Поставляется либо в стандартном .tar.gz архиве, либо как RPM-пакет (первоначально rpm (Red Hat package manager) был разработан компанией Red Hat для своей ОС Red Hat Linux, но сейчас включается практически в любой дистрибутив в силу популярности формата, и ты это знаешь :).

Текущая версия утилиты — 0.21. Причем номер версии определяется не «сырым» состоянием программы (алгоритм уже достаточно хорошо отработан и программа отлажена), а размером базы уязвимостей — она еще сравнительно мала и нуждается в пополнении.

Установка утилиты стандартная: распаковка в отдельный
каталог и запуск в нем make install. В случае же rpm-пакета вообще никаких сложностей (кроме зависимостей) возникать не может.

Flawfinder можно передавать в качестве аргумента как отдельные файлы, так и целые директории для анализа групп C/C++ файлов (в т.ч. и по маске). Утилита анализирует каждый файл, и на выходе, в случае обнаружения потенциальной уязвимости, присваивает ей степень риска по шестибальной шкале (от 0 — минимальный риск, до 5 — очень большой риск). Степень эта зависит как от вида функции, так и от ее параметров и переменных. Например, постоянные строки могут быть уязвимы намного реже, чем строки с переменным форматом. Очевидно, далеко не каждый найденный flawfinder’ом баг — потенциальная уязвимость, и рассматривать все выданные утилитой ошибки как априори требующие исправления, не нужно. Рекомендуется сначала исправить те баги, что входят в категорию «Highest Risk». Также, если какую-либо особенность программы flawfinder принял за уязвимость, но вы знаете, что это не так, рекомендуется в коде внести перед вашей функцией комментарий типа /* Flawfinder: ignore */, или же, наоборот, запустить программу с ключом -newerignore для отключения игнорирования.

Рассмотрим основные ключи запуска утилиты (они все доступны при запуске программы с ключом -help):

—version
Напечатать версию программы и выйти.

 -n (—newerignore)
Не игнорировать вызовы никакой функции, даже если в комментариях наличествует директива
:ignore.

-I (—immediate)
Показывать найденные уязвимости тут же, не дожидаясь окончания процесса сканирования (полезно в случае проверки какого-либо большого количества файлов, например, ядра Linux =).

-savehitlist=/PATH
Сохранить отчет о сканировании в файл

Заценим работу тулзы в Линухе 🙂 . Запустим сканирование файлов test1.c и test2.c

[root@localhost flawfinder-0.21]# ./flawfinder test2.c
Flawfinder version 0.21, (C) 2001 David A. Wheeler.
Number of dangerous functions in C ruleset: 55
Examining test2.c
test2.c:29 [5] (buffer) gets: does not check for buffer overflows. Use fgets() instead.
test2.c:14 [4] (buffer) strcpy: does not check for buffer overflows. Consider using strncpy or strlcpy.
test2.c:17 [4] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf.
test2.c:18 [4] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf.
test2.c:19 [4] (format) sprintf: Potential format string problem. Make format string constant.
test2.c:20 [4] (format) printf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
test2.c:22 [4] (buffer) scanf: the scanf() family’s %s operation, without a limit specification, permits buffer overflows. Specify a limit to %s, or use a different input function.
test2.c:24 [4] (buffer) scanf: the scanf() family’s %s operation, without a limit specification, permits buffer overflows. Specify a limit to %s, or use a different input function.
test2.c:35 [4] (format) syslog: if syslog’s format strings can be influenced by an attacker, they can be exploited. Use a constant format string for syslog.
test2.c:13 [2] (buffer) strcpy: does not check for buffer overflows. Consider using strncpy or strlcpy. Risk is low because the source is a constant string.
test2.c:16 [2] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf. Risk is low because the source has a constant
maximum length.
test2.c:12 [1] (buffer) strcpy: does not check for buffer overflows. Consider using strncpy or strlcpy. Risk is low because the source is a constant character.
test2.c:15 [1] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf. Risk is low because the source is a constant character.
test2.c:23 [1] (buffer) scanf: the scanf() family’s %s operation, without a limit specification, permits buffer overflows. Specify a limit to %s, or use a different input function. Only low-risk scanf formats detected.
Number of hits = 14
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!

Тут мы видим, что уязвимость с самым
высокой степенью риска (5) найдена всего одна, в 29-й строчке, и связана она с отсутствием проверки на переполнение буфера. Что ж, buffer overflow это классика жанра =). Также в функциях sprintf найдено отсутствие проверки на формат передаваемой строки (он непостоянен), в функциях scanf нет ограничения на количество принимаемых символов, что также может быть причиной переполнения буфера, наконец, не менее классическое использование опасной strcpy вместо безопасной strncpy. По выдаваемому утилитой отчету все понятно без дополнительных комментариев. 

Во втором тесте отметим лишь те типы уязвимостей, которые не были замечены в первом исходнике:

[root@localhost flawfinder-0.21]# ./flawfinder /root/testz/test1.c
Flawfinder version 0.21, (C) 2001 David A. Wheeler.
Number of dangerous functions in C ruleset: 55
Examining /root/testz/test1.c
/root/testz/test1.c:38 [4] (format) fprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
/root/testz/test1.c:44 [4] (format) fprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
/root/testz/test1.c:61 [4] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf.
/root/testz/test1.c:66 [4] (format) sprintf: Potential format string problem. Make format string constant.
……

………

/root/testz/test1.c:118 [4] (format) printf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
/root/testz/test1.c:130 [4] (format) syslog: if syslog’s format strings can be influenced by an attacker, they can be exploited. Use a constant format string for syslog.
/root/testz/test1.c:146 [4] (format) fprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
/root/testz/test1.c:54 [2] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf. Risk is low because the source has a constant maximum length.
/root/testz/test1.c:83 [1] (port) snprintf: On some very old systems, snprintf is incorrectly implemented and permits buffer overflows; there are also incompatible standard definitions of it. Check it during installation, or use something else.
/root/testz/test1.c:88 [1] (port) snprintf: On some very old systems, snprintf is incorrectly implemented and permits buffer overflows; there are also incompatible standard definitions of it. Check it during installation, or use something else.
Number of hits = 20
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!
[root@localhost flawfinder-0.21]#

Здесь видим как раз тот случай, когда функция используется потенциально опасная, но в контексте программы риск минимален, т.к. в данном случае (54 строка) хоть в функции sprintf и не выполняется проверка на переполнение буфера, но в исходнике определена фиксированная длина аргумента. Также программа заботливо предупреждает о том, что старые системы неверно выполняют функцию snprintf в 83, 88 строках, очевидно, из-за несовместимого со стандартом объявления этой функции в данной строке.

Оставить мнение

Check Also

Что можно сделать с iPhone, зная пасскод. Как сливают данные, уводят iCloud и блокируют остальные устройства

Последние несколько месяцев мы много писали о нововведениях в iOS 11. «Теперь-то заживем!»…