Проект Vulners за пару лет превратился из агрегатора данных о багах в довольно популярный инструмент пентестера. Это уже полноценный тулкит для поиска эксплоитов, API для Python, плагины для Burp Suite и Chrome, серверный агент. Vulners удобно встраивается в сценарии атак, на нем пишут сканеры уязвимостей. В этой статье мы посмотрим, что может предложить Vulners, а также научимся использовать его Python API в повседневных задачах.


Если вы до этого не сталкивались с Vulners, советуем прочесть вот эту статью. Она даст базовое понимание, о чем вообще речь и зачем нужен этот ресурс.


Также рекомендуем посмотреть этот материал о консольной утилите для поиска эксплойтов getsploit.


Ищем эксплойты из Python


Чем дальше развивался Vulners, тем больше мы получали писем с просьбами дать описание нашего API.


Конечно, начали мы с самого простого — сделали Swagger. Но вскоре заметили, что даже мы сами, используя свой API, изобретаем велосипеды по два раза в день. Каждый разработчик внутри проекта создал свой враппер, чтобы обращаться к Vulners из своих утилит. В конце концов нас самих достал такой зоопарк, и мы решили унифицировать работу с API хотя бы для Python. Вот так и появился публичный Python-API.


Без ТЗ результат ХЗ


Для начала мы собрали статистику обращений к API и выяснили, что самые часто запрашиваемые функции — это:


  • поиск;
  • запросы на выгрузку коллекций для локального использования;
  • попытки использовать API от Vulners Burp Scanner Plugin;
  • переиспользование вызовов утилиты getsploit.

Ну что же, какие вызовы надо реализовать в будущем враппере, стало понятно. Но ведь пользователи Python-библиотек совсем не хотят разбираться, что в какой параметр отправляется (для этого API-либа и нужна). Так что основная задача — сделать API удобным и простым.


Как устроена библиотека


Как и в любом враппере, начали мы с велосипеда — сделали простую обертку на базе requests для того, чтобы обращаться к JSON API.


Тут все просто: создается opener, который потом обрабатывает все запросы приложения в рамках одной сессии. И сюда же вынесены основные URL, чтобы можно было потом добавлять новые пути для запросов.


class Vulners(object):

    def __init__(self, proxies=None):
        """
        Set default URLs and create session object
        :param proxies: {} dict for proxy supporting. Example: {"https": "myproxy.com:3128"}
        """

        # Default URL's for the Vulners API
        self.__vulners_urls = {
            'search':       "https://vulners.com/api/v3/search/lucene/",
            'software':     "https://vulners.com/api/v3/burp/software/",
            'id':           "https://vulners.com/api/v3/search/id/",
            'suggest':      "https://vulners.com/api/v3/search/suggest/",
            'ai':           "https://vulners.com/api/v3/ai/scoretext/",
            'archive':      "https://vulners.com/api/v3/archive/collection/"
        }
        # Default search parameters
        self.__search_size = 100

        # Requests opener
        self.__opener = requests.session()
        self.__opener.headers = {'User-Agent': 'Vulners Python API %s' % api_version}
        if proxies is not None:
            if not isinstance(proxies, dict):
                raise TypeError("Proxies must be a dict type")
            self.__opener.proxies.update(proxies)

Вторым «подкапотным» помощником стали обертки для инициации GET- и POST-запросов. Они просто перекидывают переданный dict по URL из списка, определенного в init.


После получения результата функция adapt_response_content или возвращает dict, сформированный из JSON-ответа сервера, или отдает его в raw-виде в случае не JSON-ответа.


def __vulners_get_request(self, vulners_url_key, json_parameters):
    """
    Tech wrapper for the unified
    :param vulners_url_key: Key for the self.vulners_urls dict
    :param json_parameters: {} dict for the API call
    :return: 'data' key from the response
    """
    # Return result
    response = self.__opener.get(self.__vulners_urls[vulners_url_key], params=json_parameters)
    return self.__adapt_response_content(response)

def __vulners_post_request(self, vulners_url_key, json_parameters):
    """
    Tech wrapper for the unified
    :param vulners_url_key: Key for the self.vulners_urls dict
    :param json_parameters: {} dict for the API call
    :return: 'data' key from the response
    """
    # Return result
    response = self.__opener.post(self.__vulners_urls[vulners_url_key], json=json_parameters)
    return self.__adapt_response_content(response)

Возникает вопрос: не лучше ли самому использовать requests? Нет. С такими вызовами все еще не разобраться без знания API Vulners. Поэтому мы сделали публичные вызовы-обертки, которые реализуют функциональность Vulners без лишнего погружения в структуру вызовов.


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


def cpeVulnerabilities(self, cpeString):
      """
      Find software vulnerabilities using CPE string. See CPE references at https://cpe.mitre.org/specification/
      :param cpe: CPE software string, see https://cpe.mitre.org/specification/
      :return: {merged by family dict}
      """
      dataDocs = {}
      if len(cpeString.split(":")) <= 4:
          raise ValueError("Malformed CPE string. Please, refer to the https://cpe.mitre.org/specification/. Awaiting like 'cpe:/a:cybozu:garoon:4.2.1'")
      version = cpeString.split(":")[4]
      results = self.__burpSoftware(cpeString, version, type='cpe')
      for element in results.get('search'):
          elementData = element.get('_source')
          dataDocs[elementData.get('bulletinFamily')] = dataDocs.get(elementData.get('bulletinFamily'), []) + [elementData]
      return dataDocs

Соответственно, организация кода внутри библиотеки получилась достаточно прозрачной.


Все методы, доступные без двойного подчеркивания, публичные и организуют запросы на внутренние реализации методов, которые формируют необходимые запросы к API и обеспечивают проверку типизации и контента.


As easy as «pip install vulners»


Но ведь что там под капотом у нас, как это работает, обычно никому не интересно! Библиотека должна дать результат — удобные и практичные вызовы, которые решают поставленные задачи: ищут эксплойты и информацию об уязвимостях. Для того чтобы не пришлось ставить ее руками с GitHub, мы поместили ее в репозиторий PyPI.


Ставим:


pip install -U vulners

И импортируем библиотеку в своем коде:


import vulners

vulners_api = vulners.Vulners()

Вот и все, что вам понадобится для использования Vulners API. Теперь можно попробовать решить собственные задачи, используя этот инструмент.




Пробуем искать


Что же он умеет в итоге? Давайте пробежимся по функциям и примерам кода на Python.


  • vulners_api.search даст возможность поискать в базе точно так же, как сделано в web-версии.


    heartbleed_related = vulners_api.search("heartbleed", limit=10)

  • vulners_api.document позволяет найти конкретную CVE или advisory по ее идентификатору.


    CVE_2017_14174 = vulners_api.document("CVE-2017-14174")

  • vulners_api.searchExploit делает поиск только по коллекциям эксплоитов (Exploit-DB, Packet Storm, Seebug и другим).


    wordpress_exploits = vulners_api.searchExploit("wordpress 4.7.0")

  • vulners_api.softwareVulnerabilities по переданному названию ПО и его версии возвращает список уязвимостей.


    results = vulners_api.softwareVulnerabilities("httpd", "1.5")
    exploit_list = results.get('exploit')
    vulnerabilities_list = [results.get(key) for key in results if key not in ['info', 'blog', 'bugbounty']]

  • vulners_api.cpeVulnerabilities — очень полезная штука для интеграции, например, с Nessus — по CPE-строке твоего ПО возвращает список CVE, которые затрагивают этот продукт.


    cpe_results = vulners_api.cpeVulnerabilities("cpe:/a:cybozu:garoon:4.2.1")
    cpe_exploit_list = cpe_results.get('exploit')
    cpe_vulnerabilities_list = [cpe_results.get(key) for key in cpe_results if key not in ['info', 'blog', 'bugbounty']]

  • vulners_api.references возвращает связи и зависимости документов в базе данных. Зачем? Когда нужно, например, по CVE найти патч для конкретной ОС.


    references = vulners_api.references("CVE-2014-0160")

  • vulners_api.aiScore позволяет сделать оценку описания уязвимости, используя нашу нейросеть Vulners AI.


    text_ai_score = vulners_api.aiScore("My cool vulnerability description")

  • vulners_api.archive — самый главный метод для любителей локальной обработки данных. Он выгружает весь контент нужной коллекции для локального использования.


    all_cve = vulners_api.archive("cve")


Такая обвязка функциональности «Вульнерса» позволяет создавать как самодельные сканеры уязвимостей, так и любые другие проекты, где тебе нужно работать с данными об уязвимостях или иным security related контентом.


Следующий ход — за пользователями! Создавайте классный софт, используй API для решения своих повседневных задач автоматизации. Надеюсь, наша библиотека будет вам полезна.


Linux vulnerability scanner. Без регистрации и SMS


Недавно мы рассказывали в журнале "Хакер" о мини-сканере для Linux, который позволяет буквально за пару секунд проверить свой хост на наличие уязвимостей.


Сканер представляет собой скрипт на Python, который после запуска считывает установленные пакеты, отправляет это на сайт Vulners и в ответ получает список уязвимостей. Скрипт отлично подходит для разовых операций, но, если необходимо постоянно следить за состоянием патчей на серверах, особенно когда счет идет на сотни, требуется решение другого уровня.


Чаще всего администраторы выбирают инструмент наподобие Nessus/OpenVAS. Но с этим возникает ряд проблем: нужно создавать учетную запись для сканирования, открывать сетевые доступы и прочее. При этом зачастую внедрение таких систем защиты может сыграть отрицательную роль — сервер для сканирования будут использовать для проведения самой атаки, за счет учетной записи и сетевых доступов. Поэтому использование локального агента — чаще всего более оправданный выбор. Именно так возник сканер (агент) Vulners.


Ставим сканер на сервере:


  1. Подключите репозиторий — примеры для Debian или Red Hat есть на GitHub.
  2. Установите пакет vulners-agent с помощью пакетного менеджера своего дистрибутива.
  3. Пропишите ключ регистрации в конфигурации. Его можно бесплатно получить на сайте, в разделе userinfo.

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


А мои данные точно никуда не утекут?


Корневое отличие от похожих сканеров — для запуска не требуется привилегий root, скрипт запускается от учетной записи nobody. Сам скрипт занимает буквально 500 строчек кода, поэтому можно довольно быстро его вычитать и убедиться, что нет каких-то закладок.


При первом запуске зарегистрируется агент, также пропишутся дополнительные параметры в настройках — такие как IP-адрес машины и ее имя. Ведь результат анализа нужно как-то смотреть и отличать один сервер от другого. Делать это только на основе внешнего IP-адреса в большинстве случаев невозможно.


Но если вы не хотите, чтобы настоящий IP-адрес и имя сервера отдавались наружу, есть возможность установить фейковые параметры вручную в конфигурационном файле. Для этого в /opt/vulners/conf/vulners.conf нужно задать значения параметров ipaddr и fqdn. После всех этих действий результат сканирования можно будет посмотреть в веб-интерфейсе, с различной группировкой и фильтрами.


Отчет агента об уязвимостях на твоем сервере


Агент позволяет решить проблему патч-менеджмента за считаные минуты, при этом он бесплатный.


Плагин для Burp Suite


Burp Suite давно зарекомендовал себя среди безопасников и исследователей как универсальный швейцарский нож, сочетающий возможности прокси, сканера периметра, фаззера и просто HTTP-клиента.


При пентесте часто приходится автоматизировать поиск ошибок, воспроизводя специфичные для конкретного web-приложения векторы (CSRF-токены, auth-токены), а иногда хочется искать и свежеопубликованные уязвимости систем, плагины и эксплоиты для которых появляются не сразу, даже в больших сканерах типа Nessus.


Зачем нужен плагин


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


Заголовки и тело ответа сервера


Все предельно просто — X-Софт: v.Версия. Чтобы автоматизировать сбор таких данных, в BApp Store уже есть плагин Software Version Reporter. Он в пассивном режиме смотрит ответы от сервера и парсит отпечатки приложений по заранее полученным регуляркам.


Дальше, зная версию софта, можно попробовать поискать известные уязвимости и эксплоиты под нее.


Ищем информацию об уязвимостях


Автоматизируй это!


Поиск по фингерпринтам может быть эффективным подходом для обнаружения багов, но копировать версии ПО и забивать их в «Вульнерс» каждый раз может оказаться утомительно.


Мы написали API и плагин для Burp Suite Software Vulnerability Scanner, который сам дампит фингерпринты атакуемого сайта и прогоняет их по базе Vulners. API принимает на вход два варианта полезной нагрузки:


Software + Version


{"software":"httpd","version":"2.4.23","type":"software"}

CPE (Common Platform Enumeration)


{"software":"cpe:/a:php:php","version":"5.6.27","type":"cpe"}

Запросы совершаются на URL https://vulners.com/api/v3/burp/software/?utm_source=xakep&utm_medium=xtools&utm_campaign=scan. Конечный запрос может выглядеть так:


POST /api/v3/burp/software/?utm_source=xakep&utm_medium=xtools&utm_campaign=scan HTTP/1.1
Host: vulners.com
content-type: application/json
Content-Length: 66

{"software": "cpe:/a:php:php", "version": "5.6.31", "type": "cpe"}

В ответ получаем список уязвимостей и эксплоитов в стандартном формате Vulners.


Список полученных уязвимостей


Как задетектить все


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


Каждое правило содержит в себе:


  • type — тип детекта, формализованный под наиболее эффективный поиск в базе cpe либо software;
  • alias — уникальное имя для детектируемого ПО;
  • regexp — само регулярное выражение, по которому будем находить ПО.

Кстати, правила детекта открыты для контрибьюторов на Гитхабе, присоединяйтесь!


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


А иногда может просто приятно удивить, если ты всего лишь бороздишь просторы интернета с включенным Burp-proxy.


Мы записали видео с реальным примером использования плагина


Наш плагин Software Vulnerability Scanner для Burp Suite можно скачать в официальном магазине приложений bAppStore.


Если вы не пользуетесь Burp Suite...


Если у вас нет лицензии на Burp, но вы хотели бы попробовать, как работает сканер, — мы написали расширение для Chrome. Плагин использует абсолютно те же методы API и правила детекта, что и версия для Burp.


Плагин для «Хрома» сигналит об уязвимом ПО


Outro


Vulners — уже не просто парсер с поиском. Каждый день он обрастает новыми фичами и своей экосистемой. Наши утилиты — это всего лишь пример того, как можно использовать потенциал базы уязвимостей. Но может быть, вы придумаете что-то более крутое? Так что welcome. И не забывайте писать о глюках и улучшениях!


Credits


Эта статья была опубликована нами ранее на Xakep.RU: «Ищем эксплоиты из Python, сканим уязвимые серверы и автоматизируем».

Комментарии (0)