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

INFO

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

Также посмотри этот материал о консольной тулзе для поиска сплоитов getsploit. Мы же займемся более низкоуровневым жонглированием API из Python.

 

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

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

Конечно, начали мы с самого простого — сделали Swagger. Но вскоре заметили, что даже мы сами, используя свой API, изобретаем велосипеды по два раза в день. Каждый разработчик внутри проекта создал свой враппер, чтобы обращаться к Vulners из своих утилит. В конце концов нас самих достал такой зоопарк, и мы решили унифицировать работу с API хотя бы для 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. Теперь можно попробовать решить твои задачи, используя этот инструмент.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии