Проект 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. Теперь можно попробовать решить твои задачи, используя этот инструмент.

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

Cтатьи из последних выпусков журнала можно покупать отдельно только через два месяца после публикации. Чтобы читать эту статью, необходимо купить подписку.

Подпишись на журнал «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Комментарии

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Tips’n’Tricks из арсенала андроидовода. Самые интересные, полезные и нестандартные трюки с Android

Многие годы мы рассказывали про самые разные способы оптимизировать, модифицировать и твик…