Linux-форензика в лице трекинга истории подключений USB-устройств

    image

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

    Сей проект носит название usbrip и представляет собой небольшую консольную опенсорс утилиту для Linux-форензики, а именно для работы с историей подключений USB-устройств. Программа написана на чистом Python 3 (с использованием некоторых сторонних модулей) и не требует зависимостей помимо Python 3.x интерпретатора и пары строк из requirements.txt, разрешающихся одной строкой с помощью pip.

    В этом посте я опишу некоторые возможности данного софта и оставлю краткий мануал со ссылкой на источник загрузки.

    Снято! (… в смысле Cut!)

    Примечание. Описываемый в статье функционал актуален для первой версии утилиты. За последней версией с множеством новых плюшек предлагаю перейти в репозиторий.

    Скриншоты


    Получение истории подключений съёмных USB-устройств:

    image

    Поиск дополнительной информации о USB-устройстве по идентификатору модели (PID'у):

    image

    Описание


    Как известно, операционные системы на базе GNU/Linux очень трепетно относятся к логированию разного рода событий, и подключение/отключение USB-устройств не является исключением. В совокупности с одним из пунктов UNIX-философии о «текстовых потоках, как универсальных интерфейсах» информацию об артефактах таких событий (с разной степенью подробности) в зависимости от дистрибутива можно обнаружить в одном или нескольких из следующих текстовых файлов:

    • /var/log/kern.log*;
    • /var/log/syslog*;
    • /var/log/messages*;
    • /var/log/dmesg*;
    • /var/log/daemon.log*.

    FORENSIC-PROOF даже показывает нам такую картинку на этот счет (немного неполную, но неважно):

    image

    Для своей работы usbrip находит универсальные для всех сборок Linux, основанных на Debian (Ubuntu, Linux Mint и др.) и RPM (CentOS, Fedora, openSUSE и др.), лог-файлы, а именно: /var/log/syslog* или /var/log/messages*, парсит их в поисках нужной информации и обликает найденные следы подключений USB-устройств в красивые таблички (или списки — как угодно).

    Также usbrip умеет:

    • создавать списки авторизированных (доверенных) устройств в виде JSON-файлов;
    • искать «события-нарушителей» на основе списка доверенных устройств: такие события (подключение/отключение USB), в которых участвовали USB-устройства, не отмеченные как доверенные;
    • искать дополнительную информацию о USB-устройстве по его VID (Vendor ID) и/или PID (Product ID).

    Справка


    Получить список доступных модулей:

    $ python3 usbrip.py -h

    Получить список доступных подмодулей для конкретного модуля:

    $ python3 usbrip.py <модуль> -h

    Получить список доступных опций для конкретного подмодуля:

    $ python3 usbrip.py <модуль> <подмодуль> -h

    Синтаксис


    
    $ python3 usbrip.py banner
    Вывод на экран баннера утилиты.
    
    $ python3 usbrip.py events history [-q] [-t | -l] [-e] [-n КОЛИЧЕСТВО_СОБЫТИЙ] [-d ДАТА [ДАТА ...]] [-c СТОЛБЕЦ [СТОЛБЕЦ ...]] [-f ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...]]
    Просмотр истории USB-подключений.
    
    $ python3 usbrip.py events gen_auth <ВЫХОДНОЙ_ФАЙЛ.JSON> [-a ПРИЗНАК [ПРИЗНАК ...]] [-q] [-e] [-n КОЛИЧЕСТВО_СОБЫТИЙ] [-d ДАТА [ДАТА ...]] [-f ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...]]
    Формирование списка авторизированных (доверенных) USB-устройств.
    
    $ python3 usbrip.py events violations <ВХОДНОЙ_ФАЙЛ.JSON> [-a ПРИЗНАК [ПРИЗНАК ...]] [-q] [-t | -l] [-e] [-n КОЛИЧЕСТВО_СОБЫТИЙ] [-d ДАТА [ДАТА ...]] [-c СТОЛБЕЦ [СТОЛБЕЦ ...]] [-f ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...]]
    Поиск "событий-нарушителей" на основе списка доверенных устройств.
    
    $ python3 usbrip.py ids search [-q] [--vid VID] [--pid PID] [--offline]
    Поиск дополнительной информации об устройстве по его VID и/или PID по базе данных идентификаторов.
    
    $ python3 usbrip.py ids download [-q]
    Обновление (загрузка) локальной базы данных идентификаторов USB-устройств.
    

    Опции


    
    Опции, поддерживаемые подмодулями 'events history', 'events gen_auth', 'events violations', 'ids search', 'ids download':
        -q, --quiet
        опустить вывод баннера, информационных (зелёных) сообщений, а также не задавать вопросы по ходу выполнения
    
    #####################################################################################
    
    Опции, поддерживаемые подмодулями 'events history', 'events gen_auth', 'events violations':
        -e, --external
        искать только съёмные USB-устройства (у которых есть информация об отсоединении)
    
        -n КОЛИЧЕСТВО_СОБЫТИЙ, --number КОЛИЧЕСТВО_СОБЫТИЙ
        количество последних по дате событий, которое будет выведено
    
        -d ДАТА [ДАТА ...], --date ДАТА [ДАТА ...]
        список дат, по которым будет производится фильтрация событий при поиске
    
        -f ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...], --file ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...]
        список лог-файлов (если не указано, поиск истории событий будет произведен по лог-файлам по умолчанию: /var/log/syslog* или /var/log/messages* в зависимости от версии ОС)
    
    #####################################################################################
    
    Опции, поддерживаемые подмодулями 'events history', 'events violations':
        -t, --table
        сформировать вывод в виде таблицы (если размера окна терминала не хватает для корректного отображения таблицы, вывод автоматически будет сформирован в виде списка; при указании флага -t вывод будет сформирован в виде таблицы принудительно)
    
        -l, --list
        сформировать вывод в виде списка
    
        -c СТОЛБЕЦ [СТОЛБЕЦ ...], --column СТОЛБЕЦ [СТОЛБЕЦ ...]
        список столбцов, которые будут использованы при построении таблицы (имеет действие только при формировании вывода в виде таблицы); разрешённые ключи: "conn", "user", "vid", "pid", "prod", "manufact", "serial", "port", "disconn".
    
    #####################################################################################
    
    Опции, поддерживаемые подмодулями 'events gen_auth', 'events violations':
        -a ПРИЗНАК [ПРИЗНАК ...], --attribute ПРИЗНАК [ПРИЗНАК ...]
        список признаков, которые будут использованы при построении списка авторизированных устройств (а также при поиске "событий-нарушителей" в случае подмодуля 'events violations'); разрешённые ключи: "vid", "pid", "prod", "manufact", "serial".
    
    #####################################################################################
    
    Опции, поддерживаемые подмодулями 'ids search', 'ids download':
        --vid VID
        vendor ID или идентификатор производителя USB-устройства (обычно 4 шестнадцатиричных цифры)
    
        --vid PID
        product ID или идентификатор модели USB-устройства (обычно 4 шестнадцатиричных цифры)
    
        --offline
        если указано, поиск дополнительной информации о USB-устройстве по базе данных идентификаторов будет произведен без предварительного ее (базы) обновления
    

    Примеры использования


    Показать историю подключений всех USB-устройств, опуская баннер, информационные (зелёные) сообщения, а также не задавая вопросы по ходу выполнения (-q, --quite), сформировав вывод в виде списка (-l, --list), включив в него 100 последних найденных событий (-n КОЛИЧЕСТВО_СОБЫТИЙ, --number КОЛИЧЕСТВО_СОБЫТИЙ):
    
    $ python3 usbrip.py events history -ql -n 100
    

    Показать историю подключений съёмных USB-устройств (-e, --external), сформировав вывод в форме таблицы с полями (столбцами) «Connected», «VID», «PID», «Disconnected» и «Serial Number» (-c СТОЛБЕЦ [СТОЛБЕЦ ...], --column СТОЛБЕЦ [СТОЛБЕЦ ...]), отфильтровав поиск по датам (-d ДАТА [ДАТА ...], --date ДАТА [ДАТА ...]), взяв при этом информацию из внешних лог-файлов (-f ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...], --file ЛОГ_ФАЙЛ [ЛОГ_ФАЙЛ ...]):
    
    $ python3 usbrip.py events history -et -c conn vid pid disconn serial -d "Dec  9" "Dec 10" -f /var/log/syslog.1 /var/log/syslog.2.gz
    

    Построить таблицу истории подключений всех USB-устройств и перенаправить вывод в файл для дальнейшего анализа. В том случае, если поток вывода не стандартный stdout ("|" либо ">" к примеру) в выходных данных не будут присутствовать спец. символы, отвечающие за цвет шрифта в терминале, поэтому текстовый файл не будет замусорен нечитаемыми символами. Также нужно отметить, что usbrip использует некоторые UNICODE-константы, поэтому было бы неплохо сразу конвертировать кодировку создаваемого файла в UTF-8 для их корректного отображения (например с помощью encov), а также использовать символы новой строки в Windows-стиле для лучшей переносимости (например с помощью awk):
    
    $ python3 usbrip.py history events -t | awk '{ sub("$", "\r"); print }' > usbrip.txt && enconv -x UTF8 usbrip.txt
    

    Примечание: избавиться от спец. символов, отвечающих за цвет можно и в том случае, если вывод уже был направлен в stdout. Для этого необходимо скопировать полученные данные в новый файл usbrip.txt и добавить еще одну awk-инструкцию:
    
    $ awk '{ sub("$", "\r"); gsub("\\x1B\\[[0-?]*[ -/]*[@-~]", ""); print }' usbrip.txt && enconv -x UTF8 usbrip.txt
    

    Создать список доверенных устройств в виде JSON-файла (trusted/auth.json), содержащего поля «VID» и «PID» первых трех устройств, подключенных 26-го сентября:
    
    $ python3 usbrip.py events gen_auth trusted/auth.json -a vid pid -n 3 -d "Sep 26"
    

    Найти среди истории подключений съёмных USB-устройств «события-нарушители» на основе списка доверенных устройств (trusted/auth.json) по полю «PID» и сформировать вывод в виде таблицы с полями «Connected», «VID» и «PID»:
    
    $ python3 usbrip.py events violations trusted/auth.json -a pid -et -c conn vid pid
    

    Найти дополнительную информацию о USB-устройстве на основе его VID'а и PID'а:
    
    $ python3 usbrip.py ids search --vid 0781 --pid 5580
    

    Загрузить/обновить базу данных идентификаторов USB-устройств (источник здесь):
    
    $ python3 usbrip.py ids download
    

    Ссылки и постскриптум


    Забрать утилиту можно с Гитхаба, все зависимости для запуска и корректной работы указаны в requirements.txt.

    Благодарю за внимание!

    P. S. да, стиль баннера и информационных сообщений вдохновлен проектом sqlmap (*^.^*)

    UPD 13.06.2018. Появилось расследование реального (?) кейса с участием моей утилиты от человека с Codeby (сам в шоке, если честно).
    • +14
    • 8.6k
    • 6
    Share post

    Similar posts

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

    More
    Ads

    Comments 6

      0
      Не срача ради — стоило тащить целый requests?
        0
        А почему нет? Можно было тащить целый urllib.request и просить html через urlopen(), а потом декодировать байты в текст, но зачем, если есть requests? По времени разницы особой не будет (грубый пример, но все же):
        $ python3 -m timeit -s "from requests import get" -n 10 "get('http://www.linux-usb.org/usb.ids', timeout=10)"
        10 loops, best of 3: 1.72 sec per loop
        
        $ python3 -m timeit -s "from urllib.request import urlopen" -n 10 "urlopen('http://www.linux-usb.org/usb.ids', timeout=10).read().decode('cp1252')"
        10 loops, best of 3: 3.05 sec per loop
        

        Или Вы про само написание "import requests; requests.get()" вместо "from requests import get; get()"?
        +1
        urllib — встроенная библиотека, поставляется вместе с интерпретатором python. request — внешняя зависимость, которую нужно установить, и в данном случае (один единственный GET запрос), как мне кажется совершенно не оправдана.
          0
          Согласен, внес изменения.
            0
            неистово плюсую! всегда был приверженцем встроенной библиотеки (не только в Python), ибо использование того что есть и написания собственных либ (если это не забубенная библиотека для GPGPU вычислений, например), дает более правильное и полное понятие о языке ИМХО.
            0
            [sarcasm]Пользователи с systemd могут спать спокойно.[/sarcasm]

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