Статья Тысяча и одна уязвимость. Проводим аудит безопасности GNU/Linux «на лету»

Конкурс: Встречаем 2020 статьями по инфобезу

Тысяча и одна уязвимость. Проводим аудит безопасности GNU/Linux «на лету»

Всем привет!

Не так давно по долгу службы я столкнулся с необходимостью проведения «моментальных» аудитов безопасности машин, работающих на операционных системах Debian-based Linux. Целью таких процедур, которые должны были проводиться регулярно на разных хостах (не обязательно объединенных в одну локальную сеть), было выявление уязвимых версий установленных в системе пакетов по открытым базам данных. В силу определенных обстоятельств некоторая часть ПО, крутящегося в системах, не всегда могла быть обновлена достаточно оперативно, поэтому основным назначением аудита должен был стать своеобразный «алерт» о нависшей угрозе, что делать с которой уже решали специально обученные люди.

Сообщество знает целую галактику способов проведения подобных чек-ап'ов, однако бо́льшая часть из них предполагает развертывание громоздких программных комплексов, которые постоянно мониторят текущую обстановку. Чаще всего это связано с тем фактом, что там, где такие автоматизированные аудиты безопасности в принципе нужны, они нужны на постоянной основе в режиме реалтайма. Напротив, если речь заходит о более «портативных» сканерах уязвимостей, то в этой ситуации спектр существующих решений заметно сужается: основная их часть представляет из себя самописные (на коленке) скрипты, ориентированные на какую-то одну базу данных (чаще всего нацеленная на эксплуатацию найденных брешей).

Немного погуляв по сети в надежде отыскать что-то достойное моих самодурских прихотей и не найдя ничего, что удовлетворило бы меня полностью, я не придумал ничего лучше, чем пополнить этот список любительских скриптов своим творением. О том, как я написал простой и удобный враппер для набирающего популярность агрегатора ИБ-контента , я расскажу далее.

Vulners — база данных уязвимостей

Основой для будущего сканера было решено выбрать крупную базу данных уязвимостей от российских разработчиков. Этот проект включает в себя обширную коллекцию сведений об уязвимостях систем на базе Linux и предлагает RESTful API для удобного взаимодействия с последней. Одной из ключевых особенностей проекта является возможность проведения «удаленного» аудита безопасности Linux-хоста.

vulners-web.png


Более подробно о том, почему это так круто, можно прочитать на , а мы вернемся к моей истории.

«То что нужно!» — в итоге воскликнул я и закопался в изучение существующих инструментов, использующих Vulners в качестве своей базы знаний.

Далеко ходить не потребовалось — сам агрегатор предлагает ряд программных продуктов для упрощения работы со своей БД, в том числе:
  • vulners-scanner – Proof-of-Concept аудита безопасности Linux, демонстрирующий возможности API Vulners.com;
  • vulners-agent – агент для Linux-сервера, позволяющий проводить сканирование по планировщику cron;
  • nmap-vulners – NSE-скрипт для Nmap, позволяющий выявить угрозы безопасности, исходя из информации, полученной от сервисов, которые запущенны на открытых портах исследуемого хоста;
  • api – средство разработчика, представляющее из себя враппер веб-API Vulners.com в виде подключаемого модуля для Python (доступен для установки через PyPI).
На первый взгляд все выглядит прекрасно, и, казалось бы, проблема уже решена — осталось только выбрать то, что мне больше подходит... Однако как обычно мои капризы и хотелки взяли верх, и я не пожелал пользоваться ни одним из этих средств. Почему так произошло:
  1. Первый сканер, как я понимаю, является форком Python-приложения от стороннего разработчика (репозиторий, к слову, на данный момент находится в архиве, и более не поддерживется автором), которое попросту отказалось заводиться, когда я в первый раз решил посмотреть, что оно умеет. Немного повозившись, я решил траблы с запуском, но мне категорически не понравился вывод скрипта. В довесок ко всему прочему проект состоит из нескольких исходников, что, разумеется, улучшает структуру кода, но идет в разрез с моим представлением об идеальной портативности: я хотел иметь возможность использовать скрипт также и для редтим-мероприятий, где лучшим вариантом является отказ от сохранения наступательного кода на жесткий диск (бесконтактная доставка боевой нагрузки, об этом далее).
  2. Агент для сервера выглядит очень интересно, но тащит за собой тонну зависимостей, поэтому сразу нет — мне не хотелось выходить за рамки стандартной библиотеки Python.
  3. По этой же причине, к сожалению, пришлось отказаться от готового питоновского API для Vulners. Мне была нужна всего пара POST-запросов, и тянуть ради этого целый requests (который требует API), я посчитал кощунством.
Ремарка: я ни в коем случае не хочу сказать, что предложенные разработчиками Vulners решения «плохие» / «неправильные», или как-то по-другому их раскритиковать — они просто не подошли под мою конкретную ситуацию.

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

vul5can.py [vulskΛn]

Итак, для начала синопсис в виде help'а, и тезисный список того, чем отличается (помимо ума и сообразительности) мой сканер.
Код:
usage: vul5can.py [-h] [--os OS] [--os-version OS_VERSION] [-j] [-a] [-q]
                  [-s SOURCE] [--arch ARCH] [--config-path CONFIG_PATH]
                  [--log-path LOG_PATH] [--stealth] [--valid-api-key]
                  [-v | -r]

optional arguments:
  -h, --help            show this help message and exit
  --os OS               OS type
  --os-version OS_VERSION
                        OS version
  -j, --json            return output as JSON
  -a, --all             also include vulnerable packages associated only with
                        DSA (and not with CVE)
  -q, --quiet           supress progress messages
  -s SOURCE, --source SOURCE
                        remote repository, URI or a local file containing
                        repository packages
  --arch ARCH           "amd64" | "i386" (default: "amd64")
  --config-path CONFIG_PATH
                        path to the directory where you would like vul5can.py
                        to save configuration file
  --log-path LOG_PATH   path to the directory where you would like vul5can.py
                        to save log files
  --stealth             do not save configuration and log files to disk
  --valid-api-key       validate Vulners.com API key before calling audit
                        endpoint
  -v, --verbose         increase verbosity level (use -vv or more for greater
                        effect)
  -r, --raw             return raw API output
Отличительные особенности:
  • Как все уже поняли, сканер написан на Питоне и требует интерпретатор версии >= 3.5. Я специально не стал использовать «f-строки», поддержка которых появилась только в Python 3.6 (хотя в некоторых местах их применение сделало бы код весьма более лаконичным). Внешние зависимости не требуются, только стандартная библиотека.
  • Софтина умещается в один файл исходного кода, что позволяет не тревожить жесткий диск подопытного хоста, и запускать проверку «на лету» (если есть такая необходимость), используя редирект результата загрузки через пайп прямо в bash.
  • Сканер умеет вести логи, а свои настройки (включая чувствительную информацию в виде API-ключа Vulners) хранит в отельном файле. Это может быть удобным для планирования сканирования по cron.
  • Поддерживается stealth-режим, когда никаких следов (логи, файл конфигурации) на машине не остается.
  • В качестве входных данных могут использоваться, как простые текстовые файлы (локальные / на удаленных ресурсах; сжатые с помощью gzip), так и вывод команды dpkg-query, если скрипт запускается прямо на сканируемом хосте.
Довольно болтовни, давайте рассмотрим несколько примеров работы. Я буду писать команду запуска, под ней скриншот и вкратце говорить, что там произошло.

Пример 1. dpkg-query

Сперва «чистый» запуск (по умолчанию, без дополнительных опций).
Код:
$ ./vul5can.py
vul5can-default.png


Визуально вывод можно разделить на 3 части:
  1. баннер и служебная информация;
  2. информационные сообщения о статусе проводимого сканирования;
  3. результат сканирования.
В секции с результатом отображается название уязвимого пакета и максимальный рейтинг опасности (согласно метрике ) среди всех идентификаторов , которые ассоциированы с данной уязвимостью. Информативность вывода можно расширить verbosity-флагами -v/-vv, что я покажу чуть позже.

Данные об установленных в системе пакетах передаются от утилиты dpkg-query таким запросом.
Код:
$ dpkg-query -W -f='${Status} ${Package} ${Version} ${Architecture}\n'|awk '($1 == "install") && ($2 == "ok") {print $4" "$5" "$6}'
Формат, требуемый API Vulners (и часть вывода dpkg-query по совместительству) представлен ниже.
Код:
acl 2.2.53-5 amd64
adduser 3.118 all
adwaita-icon-theme 3.34.0-2 all
aircrack-ng 1:1.5.2-3+b1 amd64
alsa-tools 1.1.7-1 amd64
amass 3.3.1-0kali1 amd64
amass-common 3.3.1-0kali1 all
amd64-microcode 3.20191021.1 amd64
apache2 2.4.41-1 amd64
apache2-bin 2.4.41-1 amd64
apache2-data 2.4.41-1 all
apache2-utils 2.4.41-1 amd64
apparmor 2.13.3-7 amd64
apt 1.8.4 amd64
...
Идем дальше.
Код:
$ ./vul5can.py --os-version 10 -jq
vul5can-json.png


С помощью флагов -j (--json) и -q (-quiet) соответственно можно сгенерировать output в формате JSON и подавить весь остальной вывод на экран, чтобы перенаправить результат сканирования в файл или через пайп другой утилите (к примеру, JSON-процессору , что продемонстрировано ниже). Флаг --os-version отвечает за версию сканируемого дистрибутива, который можно выбрать опцией --os (по умолчанию debian).

Код:
$ ./vul5can.py --os-version 10 -qaj | jq

vul5can-json-jq.png


Здесь я добавил флаг -a (--all), чтобы расширить результат сканирования пакетами, для которых не существует номеров CVE (только бюллетени Debian), и перенаправил JSON-вывод jq.

Пример 2. Удаленный репозиторий

С помощью флага -s (--source) можно задать источник получения входных данных. Так как API требует всего лишь список пакетов в текстовом виде, вовсе не обязательно запускать сканер «изнутри» сканируемого хоста. К тому же, иногда это попросту неудобно.

Флаг -s понимает 3 вида аргументов:
  1. Удаленный (http, https, ftp) deb-репозиторий. такой же, как в файле /etc/apt/sources.list на твоей машине — начинается со слова deb, дальше URI, потом название дистрибутива и список компонентов (через пробел) в конце.
  2. Удаленный (http, https, ftp) файл, содержащий список установленных пакетов в нужном формате. Можно использовать как обычный текстовый файл, так и gz-архив.
  3. Локальный файл, содержащий список установленных пакетов в нужно формате. Можно использовать как обычный текстовый файл, так и gz-архив.
Просканируем репозиторий Ubuntu 18.04 (сборка Bionic) с русскоязычного зеркала их архива.
Код:
$ ./vul5can.py --os ubuntu --os-version 18.04 -s "deb http://ru.archive.ubuntu.com/ubuntu/ bionic main restricted" --arch i386
vul5can-deb-ubuntu.png


Я добавил флаг --arch, чтобы выбрать 32-битную архитектуру (по дефолту — amd64). Красным выделен список файлов, которые скрипт забирает для сканирования.

В этом же примере посмотрим, что из себя представляют более расширенные результаты сканирования.
Код:
$ ./vul5can.py --os ubuntu --os-version 18.04 -s "deb http://ru.archive.ubuntu.com/ubuntu/ bionic main restricted" --arch i386 -v
vul5can-deb-ubuntu-v.png


Если я повторю предыдущую команду с флагом -v (--verbose), то для каждого уязвимого пакета будет отображаться список идентификаторов CVE, которые тем или иным образом относятся к его «слабости».
Код:
$ ./vul5can.py --os ubuntu --os-version 18.04 -s "deb http://ru.archive.ubuntu.com/ubuntu/ bionic main restricted" --arch i386 -vv
vul5can-deb-ubuntu-vv.png


Двойной флаг -vv еще больше расширит вывод, включив в него информацию о бюллетенях безопасности Debian.

Также можно посмотреть, какие конкретно веб-запросы делает сканер через Burp, если потребуется отладить скрипт. Для этого установи две переменные окружения (HTTP_PROXY и HTTPS_PROXY), равными адресу локального прокси-сервера and you're good to go!

vul5can-proxy.png


Однако следует помнить, что в этом случае vul5can слепо доверяет SSL-сертификату, так как конечная точка API живет на HTTPS, и Burp, как человек-по-середине, вынужден вклиниться со своим незвестным никому (особенно питоновскому интерпретатору) сертификатом (ох уж этот Burp!).

vul5can-proxy-burp.png


Пример 3. Удаленный файл

Если значение аргумента для параметра -s начинается с названия протокольной схемы (http, https, ftp), то сканер может дергать отдельные удаленные файлы. Покажем это на примере сканирования списка пакетов, устанавливаемых в анонимной ОС Tails v3.14.2.
Код:
$ ./vul5can.py -s "https://deb.tails.boum.org/dists/3.14.2/main/binary-amd64/Packages.gz"
vul5can-tails.png


Аналогично, если я предварительно скачаю этот архив на свою машину, то я просто смогу указать путь до него в -s и сканер прочитает локальный файл.
Код:
$ wget https://deb.tails.boum.org/dists/3.14.2/main/binary-amd64/Packages.gz
$ ./vul5can.py -s Packages.gz
vul5can-tails-wget.png


Пример 4. Stealth-режим

В случае, когда нежелательно оставлять какие-либо следы своего присутствия на просканированной машине, удобно использовать опцию --stealth.
Код:
$ ./vul5can.py --stealth --valid-api-key
vul5can-stealth.png


Тогда файл с настройками не будет создан, а API-ключ будет спрашиваться в интерактивном режиме каждый раз при запуске сканера. В этом же примере я использовал флаг --valid-api-key для валидации API-ключа на Vulners (выполняется дополнительный POST-запрос).

Если ты работаешь не в stealth-режиме, и тебе хотелось бы изменить дефолтное расположение файла конфигураций и логов (по умолчанию — ~/.config/vul5can/), пользуйся --config-path и --log-path.
Код:
$ ./vul5can.py --quiet --config-path . --log-path .
vul5can-paths.png


Этим действием я инициировал запись vul5can.ini в текущий каталог, а значение настройки path_to_log внутри этого файла поменялась с дефолтной (~/.config/vul5can/log/) на CWD.

vul5can-ini.png


Пример 5. Бесконтактная доставка

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

Предположим, что исходник сканера доступен мне по адресу 127.0.0.1:31337/vul5can.py. Тогда с помощью curl (или wget) я могу сделать следующее.
Код:
$ curl -s 127.0.0.1:31337/vul5can.py | python3 - -avv --stealth --valid-api-key
vul5can-no-touch.png


Только тс-с-с-с, нас здесь не было... Кстати, то же самое можно сделать с помощью wget.
Код:
$ wget -qO- 127.0.0.1:31337/vul5can.py | python3 - -avv --stealth --valid-api-key
В заключение

Вот такая игрушка получилась, надеюсь читать было интересно. Разумеется, самый главный минус такого подхода к аудиту безопасности в том, что информация об установленных в системе пакетах ходит в интернеты (в своем профиле на Vulners можно даже статистику сканирования). Для тех, кому такой вариант по каким-либо причинам не подходит, Vulners позволяет аккумулировать собственную БД, загружая информацию о публичных CVE локально. Поэтому, думаю, что и в этом случае можно выкрутиться.

Сам скрипт находится .

Take care!
 

Сергей Попов

Кодебай
30.12.2015
4 718
6 702
BIT
467
Обратите пожалуйста внимание на последний пункт:

Как принять участие в конкурсе
  1. На конкурс можно подать неограниченное количество статей
  2. Для участия в конкурсе опубликуй свою новую (авторскую) статью в этом разделе форума и выбери префикс "Конкурс"
  3. Скопируй и вставь в начало своей статьи этот текст: "Конкурс: Встречаем 2020 статьями по инфобезу"
  4. Размести ссылку на опубликованную статью в комментарии к данной теме.
 

neonh4ze

Active member
07.06.2018
34
162
BIT
2
Обратите пожалуйста внимание на последний пункт:

Как принять участие в конкурсе
  1. На конкурс можно подать неограниченное количество статей
  2. Для участия в конкурсе опубликуй свою новую (авторскую) статью в этом разделе форума и выбери префикс "Конкурс"
  3. Скопируй и вставь в начало своей статьи этот текст: "Конкурс: Встречаем 2020 статьями по инфобезу"
  4. Размести ссылку на опубликованную статью в комментарии к данной теме.
Угу, исправился, ссылку добавил.
 
  • Нравится
Реакции: Сергей Попов

Bonifazzziy

One Level
01.07.2019
3
3
BIT
0
Супер статья. Собственная разработка, прекрасное описание и четкость изложения. А важность и нужность такого софта трудно переоценить. Спасибо.
 
  • Нравится
Реакции: hodunoff2020 и neonh4ze

Des Nes

One Level
18.08.2019
1
1
BIT
0
Раньше думал, что такие инструменты делаются за рубежом и всякими тру хацкерами, спасибо за статью и за инструмент
 
  • Нравится
Реакции: neonh4ze

sohimaster

One Level
28.01.2019
1
1
BIT
0
Выглядит интересно. Попробую.
От себя хочу добавить, что нет ничего зазорного в том, чтобы использовать requests пусть даже для одного запроса.
 
  • Нравится
Реакции: Shadow User

neonh4ze

Active member
07.06.2018
34
162
BIT
2
Выглядит интересно. Попробую.
От себя хочу добавить, что нет ничего зазорного в том, чтобы использовать requests пусть даже для одного запроса.
Ничего зазорного, определенно. Основной посыл отказа от реквестов был в том, чтобы не тянуть за собой ни одной зависимости, ибо софтина должна была уметь запускаться на абсолютно голой машине (либо там, где у нас нет прав что-либо вообще инсталлировать).
 

Nubusers

Green Team
23.07.2019
55
21
BIT
0
Не плохо:) Для общего моего развития в самый раз.
 

Shadow User

Green Team
10.07.2017
138
29
BIT
0
Выглядит интересно. Попробую.
От себя хочу добавить, что нет ничего зазорного в том, чтобы использовать requests пусть даже для одного запроса.
Ну, многое можно сделать и стандартными библиотеками. Питоновский http, весьма неплох.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!