• Партнер

  • Pscan

    http://www.striker.ottawa.on.ca/~aland/pscan/

    Pscan (Problem Scanner) - это программа, которая позволяет сканировать код Си-программ на наличие общих ошибок в вызове и объявлении функций, которые часто приводят к такой распространенной ошибке как переполнению буфера. Сканер работает по следующему принципу: он ищет одну из "проблемных" функций (на основе своего списка) и применяет следующее правило. ЕСЛИ последний параметр функции - строка какого-либо формата, И формат строки НЕ постоянен, ТОГДА сравнивает и делает вывод об уязвимости. После того, как потенциальная уязвимость найдена, сканер выдает ее на консоль с предложением о коррекции данного куска кода.

    Pscan является консольной утилитой, работает в Unix-системах, поставляется в tgz-архиве и собирается в бинарный файл стандартной командой make. На выходе, при передаче исполняемому файлу в качестве параметра си-файла, как и все подобные утилиты, сканер выводит номер строки, описание уязвимости и название функции, в которой найдена проблема. Программе можно передавать как отдельный файл, так и задавать сканирование по маске.

    Запуск программы с ключом -v (verbose) даст более детальное описание уязвимостей. Ключ -w позволяет выводить предупреждения, когда строки непостоянного формата
    (non-constant strings) используются как передаваемый в функцию параметр.

    Рассмотрим применение программы, передавая ей для анализа файл test1.c 


    [root@localhost pscan-1.2]# ./pscan test1.c
    test1.c:38 SECURITY: fprintf call should have "%s" as argument 1
    test1.c:66 SECURITY: sprintf call should have "%s" as argument 1
    test1.c:77 SECURITY: sprintf call should have "%s" as argument 1
    test1.c:95 SECURITY: sprintf call should have "%s" as argument 1
    test1.c:118 SECURITY: printf call should have "%s" as argument 0
    test1.c:131 SECURITY: syslog call should have "%s" as argument 1
    [root@localhost pscan-1.2]#

    Как видим, отчет нам выдали в довольно лаконичной форме. Видим, что соответствующим функциям не хватает аргумента "%t" где t - тип передаваемых данных, т.е. это можно интерпретировать как неявно заданный формат строки. Затем, по указанному выше алгоритму, программа сравнивает, так ли на самом деле (т.е. присутствует "%t" или нет), и, в случае неудачи, возвращает 0, иначе - 1.
    Таким образом, в программе test1.c найдена одна ошибка на переполнение буфера (строка 118).

    Запуская программу с ключом -vv, получаем несколько более "разговорчивый" отчет:


    [root@localhost pscan-1.2]# ./pscan -vv /root/scanz/test2.c
    Scanning /root/scanz/test2.c ...
    /root/scanz/test2.c:6 FUNC printf Last argument is variable or reference: BAD
    /root/scanz/test2.c:17 FUNC sprintf Last argument is constant string: OK
    /root/scanz/test2.c:18 FUNC sprintf Last argument is constant string: OK
    /root/scanz/test2.c:19 FUNC sprintf format string with 1 parameters: OK
    /root/scanz/test2.c:20 FUNC sprintf format string with 1 parameters: OK
    /root/scanz/test2.c:21 FUNC sprintf format string with 1 parameters: OK
    /root/scanz/test2.c:22 FUNC printf format string with 1 parameters: OK
    /root/scanz/test2.c:23 FUNC scanf format string with 1 parameters: OK
    /root/scanz/test2.c:24 FUNC scanf format string with 1 parameters: OK
    /root/scanz/test2.c:25 FUNC scanf format string with 1 parameters: OK
    /root/scanz/test2.c:26 FUNC scanf format string with 1 parameters: OK
    /root/scanz/test2.c:29 FUNC printf Last argument is variable or reference: BAD
    /root/scanz/test2.c:35 FUNC syslog format string with 2 parameters: OK
    /root/scanz/test2.c:36 FUNC syslog Last argument is constant string: OK
    /root/scanz/test2.c:38 FUNC syslog Last argument is constant string: OK
    Total problems identified: 2
    [root@localhost pscan-1.2]#

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

    RATS


    http://www.securesw.com/projects.html

    RATS ("Грубая утилита для аудита безопасности", Rough Auditing Tool for Security) - утилита для сканирования исходных кодов программ на С/С++, Perl, PHP и Python и обнаружения уязвимостей, связанных с ошибками в программировании, таких как переполнения буфера и TOCTOU (Time Of Check, Time Of Use). Как подразумевает название программы, она предназначена только для грубого анализа исходника, и может обнаружить не все ошибки, или же наоборот, принять за ошибку корректный участок кода (интересно, что это - признание автора в несовершенстве алгоритма или скромность, граничащая с осторожностью?). То есть "ручную" проверку кода этот сканер не заменит, но серьезно поможет в сем трудном деле.

    Как и подавляющее большинство *nix'овых консольных утилит, RATS поставляется в tar-файле, сжатом gzip'ом, и устанавливается, как и большинство собранных autoconf'ом программ, с помощью процедуры ./configure, make, make install. По умолчанию процедура установки происходит в /usr/local/bin.

    Использование утилиты:

    rats [-d <filename>] [-h] [-r] [-w <level>] [-x] [file1 file2 ... filen]

    Где основные опции:

    -d <filename>
    Путь к альтернативной базе уязвимостей (если дефолтовая не устраивает)

    -h
    Список всех команд

    -l <lang>
    Явное указание языка исходника, даже не взирая на расширение файла, для более точного аудита
    данного языка (позволяется выбирать "c", "perl", "php" и "python").

    -r
    Указание своих, нестандартных вызовов функций, для отражения их в отчете.

    -w <level>
    Установка уровня опасности уязвимостей. Уровень 1 включает только проверку на высокую степень уязвимости (несерьезные, мелкие потенциальные уязвимости игнорируются). Уровень 2 включает в себя проверку на среднюю степень уязвимости (это уровень по умолчанию). Уровень 3 включает также проверку на незначительные, мелкие возможные уязвимости.

    -x
    Указание не грузить стандартные базы уязвимостей (/usr/local/lib) по умолчанию.

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

    Запускаем утилиту, передавая ей файл test2.c


    [root@localhost flawfinder-0.21]# rats -d /root/scanz/rats-1.3/vuln_db.c /root/scanz/Flaw-finder/flawfinder-0.21/test2.c
    not well-formed (invalid token) at line 1
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:13: High: strcpy
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:14: High: strcpy
    Check to be sure that argument 2 passed to this function call will not more
    data than can be handled, resulting in a buffer overflow.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:17: High: sprintf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:18: High: sprintf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:19: High: sprintf
    Check to be sure that the format string passed as argument 2 to this function
    call doest not come from an untrusted source that could have added formatting
    characters that the code is not prepared to handle. Additionally, the format
    string could contain `%s' without precision that could result in a buffer
    overflow.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:18: High: sprintf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:19: High: sprintf
    Check to be sure that the non-constant format string passed as argument 2 to
    this function call does not come from an untrusted source that could have added
    formatting characters that the code is not prepared to handle.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:20: High: printf
    Check to be sure that the non-constant format string passed as argument 1 to
    this function call does not come from an untrusted source that could have added
    formatting characters that the code is not prepared to handle.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:21: High: scanf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:22: High: scanf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:23: High: scanf
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:24: High: scanf
    Check to be sure that the format string passed as argument 2 to this function
    call doest not come from an untrusted source that could have added formatting
    characters that the code is not prepared to handle. Additionally, the format
    string could contain `%s' without precision that could result in a buffer
    overflow.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:25: High: gets
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:28: High: gets
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:29: High: gets
    Gets is unsafe!! No bounds checking is performed, buffer is easily overflowable by user. Use fgets(buf, size, stdin) instead.

    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:32: High: syslog
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:33: High: syslog
    /root/scanz/Flaw-finder/flawfinder-0.21/test2.c:35: High: syslog
    Truncate all input strings to a reasonable length before
    passing them to this function

    В первой группе предупреждений контролируется отсутствие ограничение на длину передаваемого функции strcpy параметра, что может вызвать переполнение буфера. Во втором - та же история с sprintf, нам
    предлагают  убедиться, что вызов функции не идет из опасного источника и не произойдет т.н. "ошибка форматирования строки". При вызове функции gets программа предупреждает, что в данном контексте использование ее не рекомендуется, ибо здесь не используется хоть какой-нибудь проверки и "буфер легко переполняем пользователем". Вместо нее настойчиво требуют использовать более безопасную fgets.
    Наконец, в вызове функции syslog, нам рекомендуют урезать все входные параметры (строки) до приемлемой длины (ограничить длину, другим словом), перед передачей их этой функции.

    Quaudit

    Qaudit.pl - это не совсем программа, а простой кроссплатформенный перл-скрипт для анализа исходных текстов си программ на уязвимости. Для его использования на машине должен быть установлен перл. Главный минус скрипта - отсутствие базы уязвимостей.

    Рассмотрим анализ программы test1.c


    [root@localhost bin]#perl /root/scanz/qaudit.pl
    qaudit.pl::q(uick)audit: version[02]. by: vade79[v9@fakehalo.org].
    --------------------------------------------------------------------------------
    qaudit> help
    interface commands: file audit exit.
    qaudit> file /root/scanz/test1.c
    source file set to: /root/scanz/test1.c.
    qaudit> audit
    executing audit on: /root/scanz/test1.c
    --------------------------------------------------------------------------------
    test1.c:*NOTICE:START: entering format bug check mode.
    test1.c:FMT_CHK:38:WARNING: fprintf(stderr, variable); /* problematic */
    test1.c:FMT_CHK:44:WARNING: fprintf(stderr, format, variable1, variable2);
    test1.c:FMT_CHK:113:WARNING: printf((variable ? fmt1 : fmt2), string3); /* OK */
    test1.c:FMT_CHK:118:WARNING: printf((variable ? string1 : string2)); /* problematic */
    test1.c:*NOTICE:STOP: exiting format bug check mode.
    test1.c:*NOTICE:START: entering bounds check mode.
    test1.c:*NOTICE:STOP: exiting bounds check mode.
    test1.c:*NOTICE:START: entering exec check mode.
    test1.c:*NOTICE:STOP: exiting exec check mode.
    test1.c:*NOTICE:START: entering environmental variable check mode.
    test1.c:*NOTICE:STOP: exiting environmental variable check mode.
    test1.c:*NOTICE:START: entering miscellaneous check mode.
    test1.c:MSC_CHK:54:WARNING: sprintf(buffer, "string"); /* OK */
    test1.c:MSC_CHK:61:WARNING: sprintf(buffer, "%s"); /* OK */
    test1.c:MSC_CHK:66:WARNING: sprintf(buffer, variable); /* problematic */
    test1.c:MSC_CHK:71:WARNING: sprintf(buffer, "%s", variable); /* OK */
    test1.c:MSC_CHK:77:WARNING: sprintf(buffer, "%d", sprintf(buffer1, variable)); /* problematic! */
    test1.c:MSC_CHK:95:WARNING: sprintf(buffer,
    test1.c:MSC_CHK:103:WARNING: sprintf(buffer, "%s %s %s", one, two, three); /* OK */
    test1.c:MSC_CHK:120:WARNING: // sprintf(buffer, variable); C++ comments get ignored, for good or for bad.
    test1.c:MSC_CHK:122:WARNING: /* sprintf(buffer, variable); these comments get ignored, too */
    test1.c:MSC_CHK:129:WARNING: sprintf(s, "PASV port %i assigned to %s", i, remoteident);
    test1.c:*NOTICE:STOP: exiting miscellaneous check mode.
    --------------------------------------------------------------------------------
    qaudit> exit
    exiting qaudit
    [root@localhost scanz]# 

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

    The конец

    Итак, к озакномлению были представлены четыре популярные проги плюс один скрипт :). Я намеренно не стал анализировать качество работы каждой утилиты: исходники-тесты у тебя есть, репорты тоже есть, бери, сравнивай, анализируй и думай 🙂 В принципе, написать самому подобную прогу - не проблема, главное выработать эффективный алгоритм. Ну а потом - никто не мешает тебе запихнуть все это дело в ГУИ. И еще. Надеюсь, ты понимаешь, что далеко не каждая найденный сканнером баг - это баг (а не фича :), т.к. все они подходят к сканирования формально, в силу как раз используемых алгоритмов, и не являются панацеей, однако если твоя прога состоит из нескольких сот строк, и будет использоваться в потенциально небезопасном месте (aka в сети, например, на серваке, да еще при этом обрабатывать какие-либо запросы извне), то проверить ее на подобные баги - не излишество, а суровая необходимость.

    Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии