Анализатор исходных кодов RATS

    Одним из методов поиска уязвимостей в программном обеспечении является использование анализаторов исходных текстов. В данной посте хочу рассказать об одном из них, а именно о RATS (Rough Auditing Tool for Security). Упоминания о RATS встречались не раз в уважаемых мной источниках, а именно тут, тут и еще здесь. Однако, реального примера использования нигде не было.

    И так, RATS был создан компанией Fortify, предназначен для поиска ошибок в коде, написанном на C/C++,Perl, Ruby, PHP и Python, и, что важно, распространяется бесплатно. Особых чудес от этой утилиты ждать не стоит, однако, места использования «рискованных» функций мы найдем.

    Установка

    Начнем с установки RATS, далее пример для ОС Debian (wheezy), пакет RATS можно взять здесь. Качаем deb-пакет wget ftp.us.debian.org/debian/pool/main/r/rats/rats_2.3-1_amd64.deb и устанавливаем sudo dpkg –i /путь/пакет.deb.
    Проверим все ли корректно установилось, для этого в консоли набираем rats:
    $ rats
    Entries in perl database: 33
    Entries in ruby database: 46
    Entries in python database: 62
    Entries in c database: 334
    Entries in php database: 55
    Total lines analyzed: 0
    Total time 0.000010 seconds
    0 lines per second

    Здесь мы видим, сколько шаблонов типичных ошибок содержится в базе RATS (версии 2.3-1).

    Пример 1

    Теперь давайте опробуем RATS «в бою». Для этого напишем код заведомо содержащий классическую ошибку переполнения буфера и сохраним его в файл vuln_code1.c:

    #include <string.h>
    int main (int argc, char **argv)
    {
    	char buffer[10];
    	strcpy(buffer, argv[1]);
    }
    

    Теперь покажем это файл RATS: $ rats vuln_code1.c

    Analyzing vuln_code1.c
    vuln_code1.c:4: High: fixed size local buffer
    Extra care should be taken to ensure that character arrays that are allocated
    on the stack are used safely. They are prime targets for buffer overflow
    attacks.

    vuln_code1.c:5: High: strcpy
    Check to be sure that argument 2 passed to this function call will not copy
    more data than can be handled, resulting in a buffer overflow.

    Total lines analyzed: 7
    Total time 0.000154 seconds
    45454 lines per second


    RATS сообщает нам о двух ошибках, причем обеим он присваивает высокий (high) уровень опасности.
    Первая «fixed size local buffer» — использование фиксированного размера буфера в строке 4 — char buffer[10].
    Вторая «buffer overflow» — переполнение буфера в строке 5 – при использовании функции strcpy(). Если вместо функции strcpy() использовать gets(), то сообщение RATS будет выглядеть вот так:
    vuln_code1.c:5: High: gets
    Gets is unsafe!!! No bounds checking is performed, buffer is easily overflowable by user. Use fgets(buf, size, stdin) instead


    Пример 2

    Проверим как RATS реагирует на код содержащий уязвимость форматной строки, для этого пишем код с дефектом, функция printf получает входную строку, в соответствии с которой функция ожидает, что перед ее вызовом в стек были занесены два аргумента если данную программу запустить со спецификаторами "%x %x" в качестве параметра, можно увидеть содержимое 4 байт стека.

    #include <stdio.h>
    int main(int argс, char* argv[ ])
    {
    if(argc > 1)
    printf(argv[1]);
    return 0;
    }
    

    RATS увидел ошибку и сообщил:

    vuln_code3.c:5: 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.


    Пример 3

    В этом примере используем код содержащий ошибку переполнения буфера при взаимодействии с переменными окружения:

    #include <stdlib.h>
    int main(int argc, char *argv[ ])
    {
     char *env;
     char buf[100];
     env = getenv("PATH");
     if ( env == NULL ) { return 0; }
     sprintf(buf, "%s", env);
     return 0;
    }
    

    Здесь RATS нашел 3 ошибки:

    vuln_code4.c:5: High: fixed size local buffer
    Extra care should be taken to ensure that character arrays that are allocated
    on the stack are used safely. They are prime targets for buffer overflow
    attacks.

    vuln_code4.c:6: High: getenv
    Environment variables are highly untrustable input. They may be of any length,
    and contain any data. Do not make any assumptions regarding content or length.
    If at all possible avoid using them, and if it is necessary, sanitize them and truncate
    them to a reasonable length.

    Так как переменные окружения могу быть любой длинны, нам стоит внимательно проверять какой длинны буфер мы выделяем для работы с ними.

    vuln_code4.c:8: High: sprintf
    Check to be sure that the 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. Additionally, the format
    string could contain `%s' without precision that could result in a buffer
    overflow.


    Пример 4

    Посмотрим, как обстоят дела с другими языками программирования, и протестируем RATS на уязвимом perl-скрипте:

    open(f,$filename);
     while(<f>)
     {
      print;
     }
    

    если на вход такого скрипта подать «|команда», то команда будет исполнена. В базе RATS такая уязвимость есть, он советует нам внимательно анализировать входные данные при использовании функции open():
    test9.pl:1: Medium: open
    The filename argument of open should be carefully checked if it is being created with any user-supplied string as a compontent of it. Strings should be checked for occurences of path backtracking/relative path components (../ as an example), or nulls, which may cause the underlying C call to interpret the filename to open differently than expected. It is also important to make sure that the final filename does not end in a "|", as this will cause the path to be executed.


    Особенности использования

    • в качестве проверяемого объекта можно задавать директорию содержащую исходные тексты, RATS самостоятельно найдет и проверит все вложенные файлы
    • флаг -l позволяет принудительно задать язык проверяемого исходника
    • флаг -noheader позволяет отключить отображения информационного заголовка
    • флаг -h отображает список и описание других флагов

    Вывод

    За давностью лет не стоит рассматривать RATS как всеобъемлющий анализатор уязвимостей в серьезных проектах, однако как учебный вариант для выявления и понимания хрестоматийных ошибок он вполне пригоден.

    Ссылки

    Подробнее об уязвимостях переполнения буфера: www.securitylab.ru/contest/212095.php
    Хорошая, но сложная книга об анализе и поиске уязвимостей в ПО: www.ozon.ru/context/detail/id/5238324
    Статья, о безопасности в cgi-скриптах: www.getinfo.ru/article358.html

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 4

      +3
      Боюсь, что если скормить ему большой листинг кода, то можно захлебнуться в предупреждениях.
        0
        Смотря насколько листинг большой, вот, например, тест исходников qbittorrent последней версии, предупреждений не так уж и много.
        Отчет RATS
        Entries in perl database: 33
        Entries in ruby database: 46
        Entries in python database: 62
        Entries in c database: 334
        Entries in php database: 55
        Analyzing /ftp/qbittorrent-3.1.11//src/qtnotify/notifications.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcreator/torrentcreatordlg.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcreator/torrentcreatorthread.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcontentmodelfile.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcontentmodelitem.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/ico.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/loglistwidget.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/dnsupdater.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/messageboxraised.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/statussortfilterproxymodel.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/preferences/options_imp.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/powermanagement/powermanagement.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/powermanagement/powermanagement_x11.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcontentmodelfolder.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/smtp.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/lineedit/src/lineedit.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/httpresponsegenerator.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/httpserver.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/httpconnection.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/btjson.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/qjson/parser.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/qjson/json_parser.cc
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/qjson/json_scanner.cc
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/qjson/serializer.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/qjson/json_scanner.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/httprequestparser.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/webui/prefjson.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/programupdater.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/main.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qmacapplication.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/iconprovider.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/downloadthread.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/executionlog.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcontentfiltermodel.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/update_qrc_files.py
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rss_imp.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssfeed.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssfolder.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rsssettingsdlg.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssdownloadrule.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssarticle.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssfile.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssparser.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/automatedrssdownloader.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/feedlistwidget.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssmanager.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/cookiesdlg.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/rss/rssdownloadrulelist.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtlibtorrent/shutdownconfirm.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtlibtorrent/torrentspeedmonitor.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtlibtorrent/qtorrenthandle.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtlibtorrent/torrentmodel.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtlibtorrent/qbtsession.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentimportdlg.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/sessionapplication.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/torrentcontentmodel.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/previewselect.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/statsdialog.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/mainwindow.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtsinglecoreapplication.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlockedfile_win.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtsingleapplication.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlocalpeer.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlockedfile_unix.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlockedfile.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/engineselectdlg.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/sgmllib3.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/nova2.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/novaprinter.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/socks.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/mininova.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/vertor.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/kickasstorrents.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/legittorrents.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/torrentreactor.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/btdigg.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/extratorrent.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/piratebay.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/engines/__init__.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/nova2dl.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/helpers.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova3/__init__.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/searchtab.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/searchengine.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/nova2.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/fix_encoding.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/novaprinter.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/socks.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/mininova.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/vertor.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/kickasstorrents.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/legittorrents.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/torrentreactor.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/btdigg.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/extratorrent.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/piratebay.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/engines/__init__.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/nova2dl.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/helpers.py
        Analyzing /ftp/qbittorrent-3.1.11//src/searchengine/nova/__init__.py
        Analyzing /ftp/qbittorrent-3.1.11//src/scannedfoldersmodel.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/addnewtorrentdialog.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/tracker/qtracker.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/fs_utils.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/autoexpandabledialog.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/misc.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/geoip/geoipmanager.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/proptabbar.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/peerlistwidget.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/propertieswidget.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/downloadedpiecesbar.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/pieceavailabilitybar.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/properties/trackerlist.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/transferlistwidget.cpp
        Analyzing /ftp/qbittorrent-3.1.11//src/updownratiodlg.cpp
        /ftp/qbittorrent-3.1.11//src/ico.cpp:172: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/ico.cpp:180: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/ico.cpp:223: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/ico.cpp:406: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/webui/httpresponsegenerator.cpp:70: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/webui/qjson/json_parser.cc:761: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/downloadthread.cpp:64: High: fixed size local buffer
        /ftp/qbittorrent-3.1.11//src/misc.cpp:434: High: fixed size local buffer
        Extra care should be taken to ensure that character arrays that are allocated
        on the stack are used safely. They are prime targets for buffer overflow
        attacks.

        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/sgmllib3.py:19: High: compile
        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/sgmllib3.py:33: High: compile
        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/sgmllib3.py:56: High: compile
        Argument 1 to this function call should be checked to ensure that it does not
        come from an untrusted source without first verifying that it contains nothing
        dangerous.

        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/socks.py:227: High: gethostbyname
        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/socks.py:292: High: gethostbyname
        /ftp/qbittorrent-3.1.11//src/searchengine/nova3/socks.py:332: High: gethostbyname
        /ftp/qbittorrent-3.1.11//src/searchengine/nova/socks.py:227: High: gethostbyname
        /ftp/qbittorrent-3.1.11//src/searchengine/nova/socks.py:292: High: gethostbyname
        /ftp/qbittorrent-3.1.11//src/searchengine/nova/socks.py:332: High: gethostbyname
        DNS results can easily be forged by an attacker (or arbitrarily set to large values, etc), and should not be trusted.

        /ftp/qbittorrent-3.1.11//src/ico.cpp:251: Medium: read
        /ftp/qbittorrent-3.1.11//src/ico.cpp:407: Medium: read
        /ftp/qbittorrent-3.1.11//src/webui/httpconnection.cpp:60: Medium: read
        /ftp/qbittorrent-3.1.11//src/webui/httpconnection.cpp:80: Medium: read
        /ftp/qbittorrent-3.1.11//src/webui/qjson/json_scanner.cc:3865: Medium: read
        /ftp/qbittorrent-3.1.11//src/webui/qjson/json_scanner.cpp:72: Medium: read
        /ftp/qbittorrent-3.1.11//src/qtlibtorrent/qbtsession.cpp:1608: Medium: read
        /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlocalpeer.cpp:173: Medium: read
        /ftp/qbittorrent-3.1.11//src/qtsingleapp/qtlocalpeer.cpp:250: Medium: read
        /ftp/qbittorrent-3.1.11//src/fs_utils.cpp:214: Medium: read
        /ftp/qbittorrent-3.1.11//src/fs_utils.cpp:214: Medium: read
        Check buffer boundaries if calling this function in a loop
        and make sure you are not in danger of writing past the allocated space.

        /ftp/qbittorrent-3.1.11//src/webui/qjson/json_scanner.cc:4503: Medium: realloc
        Don't use on memory intended to be secure, because the old structure will not be zeroed out.

        /ftp/qbittorrent-3.1.11//src/main.cpp:112: Medium: getchar
        Check buffer boundaries if calling this function in a loop
        and make sure you are not in danger of writing past the allocated space.

        /ftp/qbittorrent-3.1.11//src/main.cpp:142: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:148: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:153: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:154: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:170: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:171: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:362: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:363: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:364: Medium: signal
        /ftp/qbittorrent-3.1.11//src/main.cpp:365: Medium: signal
        When setting signal handlers, do not use the same function to handle multiple signals. There exists the possibility a race condition will result if 2 or more different signals are sent to the process at nearly the same time. Also, when writing signal handlers, it is best to do as little as possible in them. The best strategy is to use the signal handler to set a flag, that another part of the program tests and performs the appropriate action(s) when it is set.
        See also: razor.bindview.com/publish/papers/signals.txt

        /ftp/qbittorrent-3.1.11//src/main.cpp:252: Medium: srand
        Standard random number generators should not be used to
        generate randomness used for security reasons. For security sensitive
        randomness a crytographic randomness generator that provides sufficient
        entropy should be used.

        Total lines analyzed: 37702
        Total time 0.049751 seconds
        757813 lines per second

        +4
        Качаем deb-пакет wget ftp.us.debian.org/debian/pool/main/r/rats/rats_2.3-1_amd64.deb и устанавливаем sudo dpkg –i /путь/пакет.deb.

        Но зачем? Почему не apt-get install rats?
          –2
          Да, можно и так, спасибо.

        Only users with full accounts can post comments. Log in, please.