Найти:

- Взлом
- Приватность
- Трюки
- Кодинг
- Админ
- Geek
- Обучение
- Магазин

- Windows
- Linux
- Android
- Железо
- Мессенджеры
- Утечки
- Коронавирус
- Все выпуски «Хакера»

### Содержание статьи

- Получаем API Key
- Версии API
- API VirusTotal. Версия 2
- API VirusTotal. Версия 3
- Заключение

Ты наверняка не раз пользовался услугами сайта virustotal.com, чтобы проверить, не содержат ли бинарники вредоносных функций, либо протестировать собственные наработки. У этого сервиса есть бесплатный API, работу с которым на Python мы и разберем в этой статье.
Сайт virustotal.com
Другие статьи в выпуске:

### Xakep #250. Погружение в AD

- Содержание выпуска
- Подписка на «Хакер»

Чтобы пользоваться программными интерфейсами VirusTotal без ограничений, нужно получить ключ, который обходится в серьезную сумму — цены начинаются с 700 евро в месяц. Причем частному лицу даже при готовности платить ключ не дадут.

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

## WARNING

API VirusTotal нельзя использовать в коммерческих продуктах или услугах и в проектах, которые могут нанести прямой либо косвенный ущерб антивирусной индустрии.

## Получаем API Key

Итак, первым делом нам нужна регистрация на сайте. Тут проблем никаких — я уверен, что ты справишься. После регистрации берем ключ доступа, перейдя в пункт меню API key.

Вот здесь лежит ключ доступа к API VirusTotal

## Версии API

Сейчас актуальная версия API имеет номер 2. Но при этом уже существует и новый вариант — номер 3. Эта версия API пока еще находится в стадии беты, но ее уже вполне можно использовать, тем более что возможности, которые она предоставляет, гораздо шире.

Разработчики пока что рекомендуют применять третью версию только для экспериментов либо для некритичных проектов. Мы же разберем обе версии. Ключ доступа для них одинаков.

### API VirusTotal. Версия 2

Как и в случае с другими популярными веб-сервисами, работа с API заключается в пересылке запросов по HTTP и получении ответов.

API второй версии позволяет:

- отправлять файлы на проверку;
- получать отчет по проверенным ранее файлам, с использованием идентификатора файла (хеш файла SHA-256, SHA-1 или MD5 либо значение `scan_id` из ответа, полученного после отправки файла);
- отправлять URL для сканирования на сервер;
- получать отчет по проверенным ранее адресам с использованием либо непосредственно URL, либо значения `scan_id` из ответа, полученного после отправки URL на сервер;
- получать отчет по IP-адресу;
- получать отчет по доменному имени.

#### Ошибки

Если запрос был правильно обработан и ошибок не возникло, будет возвращен код 200 (OK).

Если же произошла ошибка, то могут быть такие варианты:

- 204 — ошибка типа Request rate limit exceeded. Возникает, когда превышена квота допустимого количества запросов (для бесплатного ключа квота составляет четыре запроса в минуту);
- 400 — ошибка типа Bad request. Возникает, когда некорректно сформирован запрос, например если нет нужных аргументов или у них недопустимые значения;
- 403 — ошибка типа Forbidden. Возникает, если пытаться использовать функции API, доступные только с платным ключом, когда его нет.

При правильном формировании запроса (код состояния HTTP — 200) ответ будет представлять собой объект JSON, в теле которого присутствуют как минимум два поля:

- response_code — если запрашиваемый объект (файл, URL, IP-адрес или имя домена) есть в базе VirusTotal (то есть проверялся раньше) и информация об этом объекте может быть получена, то значение этого поля будет равно единице; если запрашиваемый объект находится в очереди на анализ, значение поля будет `-2`; если запрашиваемый объект отсутствует в базе VirusTotal — равно нулю;
- verbose_msg предоставляет более подробное описание значения `response_code` (например, Scan finished, information embedded после отправки файла на сканирование).

Остальная информация, содержащаяся в ответном объекте JSON, зависит от того, какая функция API была использована.

#### Отправка файла на сервер для сканирования

Для отправки файла на сканирование необходимо сформировать POST-запрос на адрес `https://www.virustotal.com/vtapi/v2`, при этом в запросе нужно указать ключ доступа к API и передать сам файл (здесь есть ограничение на размер файла — не более 32 Мбайт). Это может выглядеть следующим образом (используем Python):

    import json
    import requests
    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/file/scan'
    params = dict(apikey='<ключ доступа>')
    with open('<путь к файлу>', 'rb') as file:
      files = dict(file=('<путь к файлу>', file))
      response = requests.post(api_url, files=files, params=params)
    if response.status_code == 200:
      result=response.json()
      print(json.dumps(result, sort_keys=False, indent=4))
    ...

Здесь вместо строки `<ключ доступа>` необходимо вставить свой ключ доступа к API, а вместо `<путь к файлу>` — путь к файлу, который ты будешь отправлять в VirusTotal. Если у тебя нет библиотеки requests, то поставь ее командой `pip install requests`.

В ответ, если все прошло успешно и код состояния HTTP равен 200, мы получим примерно вот такую картину:

    {
      "response_code": 1,
      "verbose_msg": "Scan request successfully queued, come back later for the report",
      "scan_id": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276",
      "resource": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
      "sha1": "3395856ce81f2b7382dee72602f798b642f14140",
      "md5": "44d88612fea8a8f36de82e1278abb02f",
      "sha256": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
      "permalink": "https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1577043276/"
    }

Здесь мы видим значения `response_code` и `verbose_msg`, а также хеши файла SHA-256, SHA-1 и MD5, ссылку на результаты сканирования файла на сайте `permalink` и идентификатор файла `scan_id`.

## INFO

В приведенных в статье примерах кода опущена обработка ошибок. Помни, что в ходе открытия файла или отправки запросов на сервер могут возникать исключения: `FileNotFoundError`, если файла нет, `requests.ConnectionError`, `requests.Timeout` при ошибках соединения и так далее.

#### Получение отчета о последнем сканировании файла

Используя какой-либо из хешей или значение `scan_id` из ответа, можно получить отчет по последнему сканированию файла (если файл уже загружался на VirusTotal). Для этого нужно сформировать GET-запрос и в запросе указать ключ доступа и идентификатор файла. Например, если у нас есть `scan_id` из предыдущего примера, то запрос будет выглядеть так:

    import json
    import requests
    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/file/report'
    params = dict(apikey='<ключ доступа>', resource='275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276')
    response = requests.get(api_url, params=params)
    if response.status_code == 200:
      result=response.json()
      print(json.dumps(result, sort_keys=False, indent=4))
    ...

В случае успеха в ответ мы увидим следующее:

    {
      "response_code": 1,
      "verbose_msg": "Scan finished, information embedded",
      "resource": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
      "sha1": "3395856ce81f2b7382dee72602f798b642f14140",
      "md5": "44d88612fea8a8f36de82e1278abb02f",
      "sha256": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
      "scan_date": "2019-11-27 08:06:03",
      "permalink": "https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1577043276/",
      "positives": 59,
      "total": 69,
      "scans": {
        "Bkav": {
          "detected": true,
          "version": "1.3.0.9899",
          "result": "DOS.EiracA.Trojan",
          "update": "20191220"
        },
        "DrWeb": {
          "detected": true,
          "version": "7.0.42.9300",
          "result": "EICAR Test File (NOT a Virus!)",
           "update": "20191222"
        },
        "MicroWorld-eScan": {
          "detected": true,
          "version": "14.0.297.0",
          "result": "EICAR-Test-File",
          "update": "20191222"
        },
        ...
      ...
      "Panda": {
        "detected": true,
        "version": "4.6.4.2",
        "result": "EICAR-AV-TEST-FILE",
        "update": "20191222"
      },
      "Qihoo-360": {
        "detected": true,
        "version": "1.0.0.1120",
        "result": "qex.eicar.gen.gen",
        "update": "20191222"
      }
    }

Здесь, как и в первом примере, получаем значения хешей файла, `scan_id`, `permalink`, значения `response_code` и `verbose_msg`. Также видим результаты сканирования файла антивирусами и общие результаты оценки `total` — сколько всего антивирусных движков было задействовано в проверке и `positives` — сколько антивирусов дали положительный вердикт.

Чтобы вывести результаты сканирования всеми антивирусами в удобоваримом виде, можно, например, написать что-то в таком роде:

    import requests
    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/file/report'
    params = dict(apikey='<ключ доступа>', resource='275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276')
    response = requests.get(api_url, params=params)
    if response.status_code == 200:
      result=response.json()
      for key in result['scans']:
        print(key)
        print('  Detected: ', result['scans'][key]['detected'])
        print('  Version: ', result['scans'][key]['version'])
        print('  Update: ', result['scans'][key]['update'])
        print('  Result: ', 'result['scans'][key]['result'])
    ...

Вывод на экран информации о результатах сканирования файла на VirusTotal с использованием разных антивирусных движков

#### Отправка URL на сервер для сканирования

Чтобы отправить URL для сканирования, нам необходимо сформировать и послать POST-запрос, содержащий ключ доступа и сам URL:

    import json
    import requests
    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/url/scan'
    params = dict(apikey='<ключ доступа>', url='https://xakep.ru/author/drobotun/')
    response = requests.post(api_url, data=params)
    if response.status_code == 200:
      result=response.json()
      print(json.dumps(result, sort_keys=False, indent=4))
    ...

В ответ мы получим примерно то же, что и при отправке файла, за исключением значений хеша. Содержимое поля `scan_id` можно использовать для получения отчета о сканировании данного URL.

#### Получение отчета о результатах сканирования URL-адреса

Сформируем GET-запрос с ключом доступа и укажем либо непосредственно сам URL в виде строки, либо значение `scan_id`, полученное с помощью предыдущей функции. Это будет выглядеть следующим образом:

    import json
    import requests
    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/url/report'
    params = dict(apikey='<ключ доступа>', resource='https://xakep.ru/author/drobotun/', scan=0)
    response = requests.get(api_url, params=params)
    if response.status_code == 200:
      result=response.json()
      print(json.dumps(result, sort_keys=False, indent=4))
    ...

Помимо ключа доступа и строки с URL, здесь присутствует опциональный параметр `scan` — по умолчанию он равен нулю. Если же его значение равно единице, то, когда информации о запрашиваемом URL в базе VirusTotal нет (URL ранее не проверялся), этот URL будет автоматически отправлен на сервер для проверки, после чего в ответ мы получим ту же информацию, что и при отправке URL на сервер. Если этот параметр равен нулю (или не задавался), мы получим отчет об этом URL либо (если информация о нем в базе VirusTotal отсутствует) ответ такого вида:

    {
      "response_code": 0,
      "resource": "<запрашиваемый URL>",
      "verbose_msg": "Resource does not exist in the dataset"
    }

#### Получение информации об IP-адресах и доменах

Чтобы проверить IP-адреса и домены, нужно сформировать и отправить GET-запрос с ключом, именем проверяемого домена либо IP в виде строки. Для проверки домена это выглядит так:

    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/domain/report'
    params = dict(apikey='<ключ доступа>', domain=<'имя домена'>)
    response = requests.get(api_url, params=params)
    ...

Для проверки IP-адреса:

    ...
    api_url = 'https://www.virustotal.com/vtapi/v2/ip-address/report'
    params = dict(apikey='<ключ доступа>', ip=<'IP-адрес'>)
    response = requests.get(api_url, params=params)
    ...

Ответы на такие запросы объемны и содержат много информации. Например, для IP `178.248.232.27` (это IP «Хакера») начало отчета, полученного с сервера VirusTotal, выглядит так:

    {
      "country": "RU",
      "response_code": 1,
      "as_owner": "HLL LLC",
      "verbose_msg": "IP address in dataset",
      "continent": "EU",
      "detected_urls": [
        {
        "url": "https://xakep.ru/author/drobotun/",
        "positives": 1,
        "total": 72,
        "scan_date": "2019-12-18 19:45:02"
        },
        {
        "url": "https://xakep.ru/2019/12/18/linux-backup/",
        "positives": 1,
        "total": 72,
        "scan_date": "2019-12-18 16:35:25"
        },
        ...
      ]
    }

### API VirusTotal. Версия 3

В третьей версии API намного больше возможностей по сравнению со второй — даже с использованием бесплатного ключа. Более того, при экспериментах с третьей версией я не заметил, чтобы ограничивалось число загружаемых объектов (файлов или адресов) на сервер в течение минуты. Похоже, ограничения в бете пока вообще не действуют.

Функции третьей версии API спроектированы с использованием принципов REST и просты для понимания. Ключ доступа здесь передается в заголовке запроса.

#### Ошибки

В третьей версии API список ошибок (и, соответственно, кодов состояния HTTP) расширился. Были добавлены:

- 401 — ошибка типа User Not Active Error, она возникает, когда учетная запись пользователя неактивна;
- 401 — ошибка типа Wrong Credentials Error, возникает, если в запросе использован неверный ключ доступа;
- 404 Not Found Error возникает, когда запрашиваемый объект анализа не найден;
- 409 — ошибка типа Already Exists Error, возникает, когда ресурс уже существует;
- 429 — ошибка типа Quota Exceeded Error, возникает при превышении одной из квот на число запросов (минутной, ежедневной или ежемесячной). Как я уже говорил, во время моих экспериментов никаких ограничений по количеству запросов в минуту не наблюдалось, хотя я использовал бесплатный ключ;
- 429 — ошибка типа Too Many Requests Error, возникает при большом числе запросов за короткое время (может быть вызвана загруженностью сервера);
- 503 — ошибка типа Transient Error, временная ошибка сервера, при которой повторная попытка запроса может сработать.

В случае ошибки, помимо кода состояния, сервер возвращает дополнительную информацию в форме JSON. Правда, как выяснилось, не для всех кодов состояния HTTP: к примеру, для ошибки 404 дополнительная информация представляет собой обычную строку.

Формат JSON для ошибки следующий:

    {
      "error": {
        "code": "<код состояния HTTP>",
        "message": "<сообщение с описанием ошибки>"
      }
    }

#### Функции работы с файлами

Третья версия API позволяет:

- загрузить файлы для анализа на сервер;
- получить URL для загрузки на сервер файла размером больше 32 Мбайт;
- получить отчеты о результатах анализа файлов;
- повторно проанализировать файл;
- получить комментарии пользователей VirusTotal к нужному файлу;
- отправить свой комментарий к определенному файлу;
- посмотреть результаты голосования по определенному файлу;
- проголосовать за файл;
- получить расширенную информацию о файле.

Для загрузки файла на сервер нужно его отправить через POST-запрос. Это можно сделать так:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    with open('<путь к файлу>', 'rb') as file:
      files = {'file': ('<путь к файлу>', file)}
      response = requests.post(api_url, headers=headers, files=files)
    ...

В ответ мы получим следующее:

    {
      "data": {
        "id": "ZTRiNjgxZmJmZmRkZTNlM2YyODlkMzk5MTZhZjYwNDI6MTU3NzIxOTQ1Mg==",
        "type": "analysis"
      }
    }

Здесь мы видим значение `id`, которое служит идентификатором файла. Этот идентификатор нужно использовать для получения информации об анализе файла в GET-запросах типа `/analyses` (об этом мы поговорим чуть позже).

Чтобы получить URL для загрузки большого файла (более 32 Мбайт), нужно отправить GET-запрос, в котором в качестве URL указывается `https://www.virustotal.com/api/v3/files/upload_url`. В заголовок вставляем ключ доступа:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files/upload_url'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)
    ...

В ответ получим JSON с адресом, по которому следует загрузить файл для анализа. Полученный URL при этом можно использовать только один раз.

Чтобы получить информацию о файле, который сервис уже анализировал, нужно сделать GET-запрос с идентификатором файла в URL (им может быть хеш SHA-256, SHA-1 или MD5). Так же как и в предыдущих случаях, указываем в заголовке ключ доступа:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)
    ...

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

    {
      "attributes": {
        "authentihash": "8fcc2f670a166ea78ca239375ed312055c74efdc1f47e79d69966461dd1b2fb6",
        "creation_date": 1270596357,
        "exiftool": {
          "CharacterSet": "Unicode",
          "CodeSize": 20480,
          "CompanyName": "TYV",
          "EntryPoint": "0x109c",
          "FileFlagsMask": "0x0000",
          "FileOS": "Win32",
          "FileSubtype": 0,
          "FileType": "Win32 EXE",
          "FileTypeExtension": "exe",
          "FileVersion": 1.0,
          "FileVersionNumber": "1.0.0.0",
          "ImageFileCharacteristics": "No relocs, Executable, No line numbers, No symbols, 32-bit",
          ...
          ...
          "SubsystemVersion": 4.0,
          "TimeStamp": "2010:04:07 00:25:57+01:00",
          "UninitializedDataSize": 0
        },
        ...
      }
    }

Или, например, информацию о секциях исполняемого файла:

    {
      "sections": [
        {
          "entropy": 3.94,
          "md5": "681b80f1ee0eb1531df11c6ae115d711",
          "name": ".text",
          "raw_size": 20480,
          "virtual_address": 4096,
          "virtual_size": 16588
        },
        {
          "entropy": 0.0,
          "md5": "d41d8cd98f00b204e9800998ecf8427e",
          "name": ".data",
          "raw_size": 0,
          "virtual_address": 24576,
          "virtual_size": 2640
        },
        ...
      }
    }

Если файл ранее не загружался на сервер и еще не анализировался, то в ответ мы получим ошибку типа Not Found Error с HTTP-кодом состояния, равным 404:

    {
      "error": {
        "code": "NotFoundError",
        "message": "File \"<идентификатор файла>" not found"
      }
    }

Чтобы повторно проанализировать файл, нужно также отправить на сервер GET-запрос, в котором в URL помещаем идентификатор файла, а в конце добавляем `/analyse`:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/analyse'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)
    ...

Ответ будет включать в себя такой же дескриптор файла, как и в первом случае — при загрузке файла на сервер. И так же, как и в первом случае, идентификатор из дескриптора можно использовать для получения информации об анализе файла через GET-запрос типа `/analyses`.

Просмотреть комментарии пользователей сервиса, а также результаты голосования по файлу можно, отправив на сервер соответствующий GET-запрос. Для получения комментариев:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/comments'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)
    ...

Для получения результатов голосования:

    ...
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/votes'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)
    ...

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

    ...
    limit = {'limit': str(<число голосов в ответе>)}
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/votes'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers, params=limit)
    ...

Чтобы разместить свой комментарий или проголосовать за файл, создаем POST-запрос, а комментарий или голос передаем как объект JSON:

    ...
    ## Для отправки результатов голосования
    votes = {'data': {'type': 'vote', 'attributes': {'verdict': <'malicious' или 'harmless'>}}}
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/votes'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.post(api_url, headers=headers, json=votes)
    ...
    ## Для отправки комментария
    comments = {'data': {'type': 'vote', 'attributes': {'text': <текст комментария>}}}
    headers = {'x-apikey' : '<ключ доступа к API>'}
    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/comments'
    response = requests.post(api_url, headers=headers, json=comments)
    ...

Чтобы получить дополнительную информацию о файле, можно запросить подробности о связанных с ним объектах. В данном случае объекты могут характеризовать, например, поведение файла (объект `behaviours`) или URL, IP-адреса, доменные имена (объекты `contacted_urls`, `contacted_ips`, `contacted_domains`).

Интереснее всего объект `behaviours`. К примеру, для исполняемых файлов он будет включать в себя информацию о загружаемых модулях, создаваемых и запускаемых процессах, операциях с файловой системой и реестром, сетевых операциях.

Чтобы получить эту информацию, отправляем GET-запрос:

    api_url = 'https://www.virustotal.com/api/v3/files/<значение идентификатора файла>/behaviours'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)

В ответе будет объект JSON с информацией о поведении файла:

    {
      "data": [
        {
          "attributes": {
            "analysis_date": 1548112224,
            "command_executions": [
              "C:\\WINDOWS\\system32\\ntvdm.exe -f -i1",
              "/bin/bash /private/tmp/eicar.com.sh"
            ],
            "has_html_report": false,
            "has_pcap": false,
            "last_modification_date": 1577880343,
            "modules_loaded": [
              "c:\\windows\\system32\\user32.dll",
              "c:\\windows\\system32\\imm32.dll",
              "c:\\windows\\system32\\ntdll.dll"
            ]
          },
          ...
        }
      ]
    }

#### Функции для работы с URL

В список возможных операций с URL входят:

- отправка URL на сервер для анализа;
- получение информации об URL;
- анализ URL;
- получение комментариев пользователей VirusTotal по нужному URL;
- отправка своих комментариев по определенному URL;
- получение результатов голосования по определенному URL;
- отправка своего голоса за какой-либо URL;
- получение расширенной информации о URL;
- получение информации о домене или IP-адресе нужного URL.

Большая часть указанных операций (за исключением последней) выполняется аналогично таким же операциям с файлами. При этом в качестве идентификатора URL могут выступать либо строка с URL, закодированная в Base64 без добавочных знаков «равно», либо хеш SHA-256 от URL. Реализовать это можно так:

    ## Для Base64
    import base64
    ...
    id_url = base64.urlsafe_b64encode(url.encode('utf-8')).decode('utf-8').rstrip('=')
    ...
    ## Для SHA-256
    import hashlib
    ...
    id_url = hashlib.sha256(url.encode()).hexdigest()

Чтобы отправить URL для анализа, нужно использовать POST-запрос:

    data = {'url': '<строка с именем URL>'}
    api_url = 'https://www.virustotal.com/api/v3/urls'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.post(api_url, headers=headers, data=data)

В ответ мы увидим дескриптор URL (по аналогии с дескриптором файла):

    {
      "data": {
        "id": "u-1a565d28f8412c3e4b65ec8267ff8e77eb00a2c76367e653be774169ca9d09a6-1577904977",
        "type": "analysis"
      }
    }

Идентификатор `id` из этого дескриптора используем для получения информации об анализе файла через GET-запрос типа `/analyses` (об этом запросе ближе к концу статьи).

Получить информацию о доменах или IP-адресах, связанных с каким-либо URL, можно, применив GET-запрос типа `/network_location` (здесь используем Base64 или SHA-256 идентификатор URL):

    api_url = 'https://www.virustotal.com/api/v3/urls/<идентификатор URL (Base64 или SHA-256)>/network_location'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.post(api_url, headers=headers)

Остальные операции с URL выполняются так же, как и аналогичные операции работы с файлами.

#### Функции работы с доменами и IP-адресами

Этот список функций включает в себя:

- получение информации о домене или IP-адресе;
- получение комментариев пользователей VirusTotal по нужному домену или IP-адресу;
- отправку своих комментариев по определенному домену или IP-адресу;
- получение результатов голосования по определенному домену или IP-адресу;
- отправку голоса за домен или IP-адрес;
- получение расширенной информации о домене или IP-адресе.

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

Например, получить информацию о домене `www.xakep.ru` можно таким образом:

    api_url = 'https://www.virustotal.com/api/v3/domains/www.xakep.ru'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)

А, к примеру, посмотреть комментарии по IP-адресу 178.248.232.27 — вот так:

    api_url = 'https://www.virustotal.com/api/v3/ip_addresses/178.248.232.27/comments'
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)

#### GET-запрос типа /analyses

Такой запрос позволяет получить информацию о результатах анализа файлов или URL после их загрузки на сервер или после повторного анализа. При этом необходимо использовать идентификатор, содержащийся в поле `id` дескриптора файла, или URL, полученные в результате отправки запросов на загрузку файла или URL на сервер либо в результате повторного анализа файла или URL.

Например, сформировать подобный запрос для файла можно вот так:

    TEST_FILE_ID = 'ZTRiNjgxZmJmZmRkZTNlM2YyODlkMzk5MTZhZjYwNDI6MTU3NjYwMTE1Ng=='
    ...
    api_url = 'https://www.virustotal.com/api/v3//analyses/' + TEST_FILE_ID
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)

И вариант для URL:

    TEST_URL_ID = 'u-dce9e8fbe86b145e18f9dcd4aba6bba9959fdff55447a8f9914eb9c4fc1931f9-1576610003'
    ...
    api_url = 'https://www.virustotal.com/api/v3//analyses/' + TEST_URL_ID
    headers = {'x-apikey' : '<ключ доступа к API>'}
    response = requests.get(api_url, headers=headers)

## Заключение

Мы прошлись по всем основным функциям API сервиса VirusTotal. Ты можешь позаимствовать приведенный код для своих проектов. Если используешь вторую версию, понадобится следить за тем, чтобы не отправлять запросы слишком часто, но в третьей версии такого ограничения пока что нет. Рекомендую выбрать именно ее, поскольку и возможности здесь тоже намного шире. К тому же рано или поздно она станет основной.

## WWW

- Подробное описание второй версии API
- Справка по API v3
- Исходники из статьи для второй версии API
- Вариант примеров для третьей версии

#### Оцени статью:

###### Что тебе понравилось больше всего?

Статья легкая и понятная Статья глубокая и подробная Интересуюсь этой темой Данные новые и актуальные Приятный стиль изложения

###### Что тебе не понравилось больше всего?

Статья поверхностная Статья слишком сложная Тема мне не интересна Данные устарели Неприятный стиль изложения
← Ранее Исследователи продемонстрировали, как взломать TikTok при помощи SMS
Далее → Из-за проблем с приватностью камер Xiaomi стало нельзя интегрировать с Google Nest Hub
1 комментарий

#### Последние взломы

### HTB EarlyAccess. Эксплуатируем веб-уязвимости и мисконфиги Docker

### HTB Horizontall. Захватываем веб-сервер через уязвимости в Strapi и Laravel

### Препарируем P-Code. Как реверсить старый софт на Visual Basic

### HTB Anubis. Захватываем домен через сертификаты Active Directory

#### Компьютерные трюки

### Анатомия терминала. Осваиваем текстуальную графику

### Змей-стражник. Сигнализация для велосипеда из старого смартфона на Android

### M1 для хакера. Тестируем Homebrew, виртуалки, Docker и Node на новой архитектуре Apple

### Отключить всё! Ускоряем работу Windows 11 на старом железе

#### Свежие новости

- 12 часов назад

  ### Неизвестная хак-группа годами атаковала авиационный и транспортный секторы

- 14 часов назад

  ### Конференция ZeroNights 2022 состоится 23 июня 2022 года

- 15 часов назад

  ### Участник Team Xecuter получил 40 месяцев тюрьмы

- 16 часов назад

  ### Google выпустила срочное исправление для 0-day уязвимости в Chrome

- 2 дня назад

  ### Накануне Супербоула клуб «Сан-Франциско Форти Найнерс» подвергся атаке шифровальщика

Вопросы по материалам и подписке: support@glc.ru
Отдел рекламы и спецпроектов: yakovleva.a@glc.ru
Контент 18+
Сайт защищен Qrator —
самой забойной защитой от DDoS в мире
Подписка для физлиц
Подписка для юрлиц
Реклама на «Хакере»
Контакты
Posting....
wpDiscuz
FooBox
…
FooBox
…
FooBox
…