Возможности реагирования на инциденты информационной безопасности с помощью KSC Open API

Всем привет! Меня зовут Арсений, я работаю инженером анализа машинных данных в команде разработки программного обеспечения STEP Security Data Lake (SDL). Недавно наша команда разработала новый фреймворк противодействия инцидентам информационной безопасности — адаптивные действия, благодаря которым аналитики центров кибербезопасности (Security Operation Center, SOC) смогут быстрее принимать меры по сдерживанию и ликвидации последствий инцидентов непосредственно через единый графический интерфейс нашего продукта. Я использовал этот фреймворк для взаимодействия через Kaspersky Security Center Open API и хотел бы рассказать об этом в статье.

d48c567599c9b974a565a0c56421d580.png

Немного о STEP SDL

Наша платформа предоставляет руководителям и специалистам центров кибербезопасности набор инструментов анализа больших массивов машинных данных для наблюдения за состоянием защищённости вычислительной сети и управления инцидентами информационной безопасности. SDL реализует принцип единого окна доступа к данным о событиях, активах, угрозах и инцидентах. Он обеспечивает их наглядное представление и корреляцию с использованием единого конструктора визуализаций, языков поисковых запросов и описания алгоритмов. Особенности продукта — полноценная мультитенантность, гибкость и встроенная функциональность сразу нескольких классов решений, таких как SIEM и IRP/SOAR.

Немного о Kaspersky EDR для бизнеса Оптимальный

Kaspersky EDR для бизнеса Оптимальный с расширенными возможностями обнаружения угроз, базового расследования инцидентов и автоматизированного реагирования позволяет идентифицировать, анализировать и нейтрализовывать маскирующиеся угрозы.

Он предоставляет полный обзор происходящего в инфраструктуре, а также управление всеми функциями через единую консоль Kaspersky Security Center c системой отчетов и возможностью распределять зоны ответственности администраторов.

Проблематика

В любой компании есть риск наступления инцидентов информационной безопасности и необходимость применять комплекс мер защиты информации. К ним относятся задачи своевременного обнаружения вредоносной активности и задачи быстрого и эффективного сдерживания угроз, чтобы минимизировать возможный ущерб. Наши заказчики зачастую для этого используют решение Kaspersky EDR для бизнеса Оптимальный, которое обладает функциями по реагированию на инциденты информационной безопасности вручную, например, для помещения подозрительного файла на карантин или сетевой изоляции хоста. Но делают это только в рамках контекста событий сервера Kaspersky Security Center (KSC), в котором он развернут, и только в ручном режиме. Для обнаружения широкого круга инцидентов информационной безопасности и автоматического реагирования на них заказчики используют STEP Security Data Lake, обладающий функциональностью решений класса Security Information and Event Management (SIEM) и Incident Response Platform (IRP). Чтобы автоматизировать реагирование на инциденты в SOC, и за счёт этого повысить скорость и удобство работы, мы реализовали интеграцию наших решений с использованием открытого API.

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

API Kaspersky EDR Optimum

Архитектура Kaspersky EDR для бизнеса Оптимальный включает в себя агента Kaspersky Endpoint Security (KES) с функциональным модулем EDR, агента администрирования KSC и сервер управления агентами Kaspersky Security Center (KSC). Соответственно, взаимодействие с ними предусмотрено через единый API-интерфейс — KSC Open API  

https://support.kaspersky.com/help/KSC/14/KSCAPI/index.html.

В примерах я использовал KSC Open API 14 версии.

API-запрос имеет следующий общий вид

https://ksc_address:13299/api/v1.0/Instance.Class.MethodName, где:

  1. Class — имя класса

  2. MethodName — имя функции класса

  3. Instance — имя сущности, например, HostTags (тэги хоста) или InventoryTags (тэги ПО). Требуется только для определенных классов, например, ListTags, так что чаще всего применяется запрос https://ksc_address:13299/api/v1.0/Class.MethodName

Классы отвечают за те или иные функции KSC, будь то запуск задач (Task), проставление тэгов, импорт и экспорт политик безопасности и т. д. В данной статье я покажу примеры работы с классами:

  1. Session — создание и прекращение сессии

  2. HostGroup — проведение поиска хоста по его атрибутам

  3. ChunkAccessor — работа с массивами, содержащими данные поисков

  4. Tasks — работа с задачами KSC

  5. ListTags — работа с тэгами

  6. Instance — имя сущности, например, HostTags (тэги хоста) или InventoryTags (тэги ПО)

Взаимодействие всегда начинается с создания сессии, ID которой потом постоянно необходимо добавлять в заголовок при последующих запросах. Желательно предварительно создать отдельную внутреннюю учетную запись в KSC, через которую затем будет осуществляться взаимодействие с API.

Далее пойдут примеры без использования Python и прочих языков программирования (у «Лаборатории Касперского» есть python-модуль для упрощения работы с API). Я буду использовать только API-вебхуки как наиболее универсальный вариант.

Я рассмотрю два варианта реагирования:

  • помещение файла на карантин;

  • сетевая изоляция хоста с помощью проставления тэгов.

Помещение файла на карантин

Суть этого действия заключается в запуске специализированной Задачи (Task) на выбранном узле сети с установленным KES, который поместит выбранный файл на карантин. Подробная инструкция по созданию задачи через Веб-консоль KSC находится на сайте вендора —

https://support.kaspersky.com/help/KSC/14.2/ru-RU/175983.htm

1. Предварительная настройка KSC

Для реализации нам потребуется предварительно провести небольшую настройку KSC под нужды каждой отдельной задачи.

  • Необходимо создать внутреннюю учетную запись для API-запросов в KSC и выдать ей права для возможности запуска Задач (Tasks)

  • Создать отдельную задачу на помещение файла на карантин. Необходимо включить следующую настройку для «Устройства, которым будет назначена задача» — «Задать адреса устройств вручную или импортировать из списка»

  • Зафиксировать идентификатор задачи, который отображается в адресной строке Веб-интерфейса KSC в виде десятичного числа (например, 145)

2. Создание удаленной сессии

curl -X POST \
  https://ksc_address:13299/api/v1.0/Session.StartSession \
  -H 'Authorization: KSCBasic user="",pass="",internal="1”'
  • user — имя пользователя API в кодировке Base64

  • pass — пароль пользователя API в кодировке Base64

  • internal — число, где 0 — это учетная запись хоста, на котором установлен KSC, а 1 — это учетная запись самого KSC

Response:

{
	PxgRetVal: 
}

Полученный ID указывается каждый раз при последующих обращениях к KSC в заголовке X-KSC-Session.

3. Получение ссылки на массив, хранящий ID выбранного хоста

curl -X POST \
 https://ksc_address:13299/api/v1.0/HostGroup.FindHosts \
  -H ' X-KSC-Session:  ' \
  -d '{
	"wstrFilter": "(| (KLHST_WKS_FQDN=\"\")  (KLHST_WKS_DN=\"\") 	(KLHST_WKS_WINHOSTNAME=\"\")  (KLHST_WKS_DNSNAME=\"\") 	(KLHST_WKS_IP_LONG=) )",
	"vecFieldsToReturn": [
		"KLHST_WKS_HOSTNAME",
		"KLHST_WKS_DN"
	],
	"pParams": {
		"KLGRP_FIND_FROM_CUR_VS_ONLY": true
	},
	"lMaxLifeTime": 120
}
'

1.  wstrFilter — содержит фильтр с атрибутами хоста, по которому будет производиться его поиск: KLHST_WKS_FQDN — полное доменное имя узла, KLHST_WKS_DN — имя, присвоенное узлу в KSC, KLHST_WKS_WINHOSTNAME — netBIOS — имя узла, KLHST_WKS_DNSNAME — DNS — имя узла, KLHST_WKS_IP_LONG — IP узла в байтах в порядке little endian

2.  vecFieldsToReturn — содержит список полей, которые будут возвращены в одном элементе массива. Нас в основном интересуют поля KLHST_WKS_HOSTNAME, которое содержит ID нашего узла, а также KLHST_WKS_DN

3.  pParams — содержит один единственный параметр KLGRP_FIND_FROM_CUR_VS_ONLY, который принимает значение true, если необходимо вернуть данные только с текущего сервера KSC, false — со всех доступных серверов

4.  lMaxLifeTime — время жизни запрашиваемого массива в секундах

 Response:

{
	strAccessor: ,
	"PxgRetVal": 1
}

1.  strAccessor — ссылка на массив, содержащий запрошенные нами данные

2.   PxgRetVal — размер массива

4. Обращение к массиву с ID хоста

curl -X POST \
 https://ksc_address:13299/api/v1.0/ChunkAccessor.GetItemsChunk \
  -H ' X-KSC-Session:  ' \
  -d '{
	"strAccessor": "",
	"nStart": 0,
	"nCount": 1
}
'

1.  strAccessor — ID массива, в котором находится результат наших поисков

2.  nStart — номер элемента массива, к которому мы хотим обратиться

3.  nCount — количество элементов в массиве, то есть количество найденных значений, удовлетворяющим фильтру

Response:

{
	"pChunk": {
	"KLCSP_ITERATOR_ARRAY": [
	{
	"type": "params",
                "value": {
                    "KLHST_WKS_DN": "WIN-TEST-2",
                    "KLHST_WKS_HOSTNAME": "h6116814-adc1-1fab-9ded-6e219356027a"
                }
            }
        ]
    },
    "PxgRetVal": 1
}

В ответе нас интересуют поля KLHST_WKS_DN и KLHST_WKS_HOSTNAME, которые мы будем использовать на 6 шаге.

5. Получаем данные задачи

curl -X POST \
 https://ksc_address:13299/api/v1.0/Tasks.GetTaskData \
  -H ' X-KSC-Session:  ' \
  -d '{
	"strTask": "145"
}
'

1.  strTask — номер задачи в десятичном формате, которую можно узнать из адресной строки веб интерфейса KSC

Response:

{
  "PxgRetVal": {
    "EVENT_BODY_FILTER": {
      "type": "params",
      "value": {}
    },
    "EVENT_TYPE": "PRTS_EVENT_NONE",
    "FILTER_EVENTS_COMPONENT_NAME": "",
    "FILTER_EVENTS_INSTANCE_ID": "",
    "FILTER_EVENTS_PRODUCT_NAME": "",
    "FILTER_EVENTS_VERSION": "",
    "TASKID_COMPONENT_NAME": "Connector",
    "TASKID_INSTANCE_ID": "",
    "TASKID_PRODUCT_NAME": "KES",
    "TASKID_VERSION": "11.0.0.0",
    "TASKSCH_FIRST_EXECUTION_TIME": {
      "type": "datetime",
      "value": "1970-01-01T00:00:00Z"
    },
    "TASKSCH_FIRST_EXECUTION_TIME_SEC": 0,
    "TASKSCH_LIFETIME": {
      "type": "datetime",
      "value": ""
    },
    "TASKSCH_MS_PERIOD": 0,
    "TASKSCH_RUN_MISSED_FLAG": false,
    "TASKSCH_TYPE": 0,
    "TASK_ADDITIONAL_PARAMS": {
      "type": "params",
      "value": {
        "CompatibilityInfo": {
          "type": "params",
          "value": {
            "MinimalPluginVersion": "12.7.0.533"
          }
        },
        "PRTS_TASK_EXT_SHEDULE_FLAGS": 0,
        "files": [],
        "initiator": 0,
        "klprts-TaskAccountPassword": {
          "type": "binary",
          "value": ""
        },
        "klprts-TaskAccountUser": "",
        "klprts-TaskAccounts": [],
        "klprts-TaskStorageId": "27cc1e8d-22dd-4283-b6e6-32dc4f3385b2",
        "objectAddedBy": 1,
        "responseId": {
          "type": "long",
          "value": 0
        }
      }
    },
    "TASK_CLASS_ID": 0,
    "TASK_DEL_AFTER_RUN_FLAG": false,
    "TASK_INFO_PARAMS": {
      "type": "params",
      "value": {
        "DisplayName": "Move file to Quarantine",
        "KLPRSS_EVPNotifications": {
          "type": "params",
          "value": {
            "ERR": [
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLPRCI_TaskState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              }
            ],
            "INF": [
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_BODY_FILTER": {
                    "type": "params",
                    "value": {
                      "KLPRCI_newState": 2
                    }
                  },
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLPRCI_TaskState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              },
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLEVP_GroupTaskSyncState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              },
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_BODY_FILTER": {
                    "type": "params",
                    "value": {
                      "KLPRCI_newState": 4
                    }
                  },
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLPRCI_TaskState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              },
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_BODY_FILTER": {
                    "type": "params",
                    "value": {
                      "KLPRCI_newState": 1
                    }
                  },
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLPRCI_TaskState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              }
            ],
            "WRN": [
              {
                "type": "params",
                "value": {
                  "KLEVP_ND_DAYS_TO_STORE_EVENT": 7,
                  "KLEVP_ND_EVETN_TYPE": "KLPRCI_TaskState",
                  "KLEVP_ND_STORE_AT_CLIENT_LOG": false,
                  "KLEVP_ND_STORE_AT_CLIENT_PRES": false,
                  "KLEVP_ND_STORE_AT_SERVER_LOG": false
                }
              }
            ]
          }
        },
        "KLSRV_PRTS_TASK_ENABLED_FLAG": true,
        "KLTSK_ALLOW_AUTO_RANDOMIZATION": false,
        "PRTS_TASK_CREATION_DATE": {
          "type": "datetime",
          "value": "2025-02-26T14:41:13Z"
        },
        "PRTS_TASK_GROUPID": 0,
        "PRTS_TASK_GROUPNAME": "Управляемые устройства",
        "PRTS_TASK_TARGET_COMPUTERS_TYPE": 3,
        "klprts-DontApplyToSlaveServers": true,
        "klprts-TaskScheduleSubtype": 256,
        "klprts-TaskScheduleSubtypeEx": 0
      }
    },
    "TASK_LAST_EXEC_TIME": {
      "type": "datetime",
      "value": "1970-01-01T00:00:00Z"
    },
    "TASK_LAST_EXEC_TIME_SEC": 0,
    "TASK_MAX_EXEC_TIME": 0,
    "TASK_NAME": "xdr_response_task_type_quarantine_file",
    "TASK_PREP_START": 0,
    "TASK_PRIORITY": 1,
    "TASK_START_DELTA": 0,
    "TASK_UNIQUE_ID": "145"
  }
}

6. Обновляем задачу

curl -X POST \
 https://ksc_address:13299/api/v1.0/Tasks.UpdateTask \
  -H ' X-KSC-Session:  ' \
  -d '{
	"pData": {
    "TASK_ADDITIONAL_PARAMS": {
      "type": "params",
      "value": {
        "files": [
          {
            "type": "params",
            "value": {
              "fileId": {
                "type": "params",
                "value": {
                  "filePath": "<путь_к_файлу>"
                }
              }
            }
          }
        ]
      }
    },
    "TASK_INFO_PARAMS": {
      "type": "params",
      "value": {
        "HostList": [
          {
            "type": "params",
            "value": {
              "HostDispName": "",
              "HostName": "",
              "Preliminary": false
            }
          }
        ]
      }
    }
  },
  "strTask": "145"
}
'

Response:

{ }

Здесь я не привел все тело запроса, а указал только лишь те параметры, на которых стоит сфокусироваться в первую очередь. Я рекомендую копировать все остальные параметры при обновлении задачи на всякий случай, так как мне не удалось найти в документации информации, что можно обновлять настройки той или иной задачи выборочно.

7. Запускаем задачу

curl -X POST \
 https://ksc_address:13299/api/v1.0/Tasks.RunTask \
  -H ' X-KSC-Session:  ' \
  -d '{
	"strTask": "145"
}
'

1.   strTask — номер задачи

Response:

{ }

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

8. Получение статистики запуска задачи

curl -X POST \
 https://ksc_address:13299/api/v1.0/Tasks.GetTaskStatistics \
  -H ' X-KSC-Session:  ' \
  -d '{
	"strTask": "145"
}
'

1.  strTask — номер задачи

Response:

{
	"1": "0"
	"2": "0"
	"4": "1"
	"8": "0"
	"16": "0"
	"32": "0"
	"64": "0"
	"KLTSK_NEED_RBT_CNT": "0"
	"GNRL_COMPLETED_PERCENT": "100"

}

1 — количество хостов, на которых задача еще не обновилась

2 — количество хостов, на которых задача запущена

4 — количество хостов, на которых задача завершена успешно

8 — количество хостов, на которых задача завершена с предупреждением

16 — количество хостов, на которых задача завершена с ошибкой

32 — количество хостов, на которых запланирован запуск задачи

64 — количество хостов, на которых выполнение задачи поставлено на паузу

KLTSK_NEED_RBT_CNT — количество хостов, на которых задача запросила перезапуск ОС

GNRL_COMPLETED_PERCENT — общий процент успешности запуска задачи

К сожалению, я не смог найти в документации информации, за какой временной период происходит получение статистики запуска по итогам тестирования. Я пришел к выводу, что берется общая статистка за все время, поэтому альтернативной командой для получения результатов запуска может послужить https://ksc_address:13299/api/v1.0/Tasks.GetTaskHistory

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

1.  task_old_state — предыдущее состояние выполнения задачи

2.  task_new_state — новое состояние выполнения задачи. Тут мы ожидаем увидеть значение 4 (completed successfully)

3.  rise_time — время публикации события в формате UTC

4.  registration_time — время регистрации события сервером администрирования в UTC формате

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

9. Завершаем сессию

curl -X POST \
 https://ksc_address:13299/api/v1.0/Session.EndSession \
  -H ' X-KSC-Session:  '

 Таким образом, если все выполнено без ошибок, то мы сможем добиться помещения выбранного нами файла на карантин.

Сетевая изоляция хоста

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

Как и в первом примере, нам потребуется сначала провести небольшую настройку KSC и получить ID хоста.

Повторяем первые четыре этапа из первого варианта:

1. Предварительная настройка KSC

В действующей на устройствах политике KSC создаем профиль политики. Во вкладке «Правила активации» создаем «Правило для использования тега». Добавляем тег, который будет отражать применение сетевой изоляции хоста, например, Network Isolation. Сохраняем правило активации. В созданном профиле политики во вкладке «Параметры программы» → «Базовая защита» → «Сетевой экран» включаем «Сетевой экран» и «Настройки сетевого экрана». Во вкладках «Сетевые правила приложений» и «Сетевые пакетные правила» указываем желаемые настройки, которые будут применяться во время изоляции хоста, например, будем блокировать весь трафик для протоколов TCP и UDP.

Подробная инструкция предусмотрена на сайте вендора — https://support.kaspersky.com/KSC/14.2/ru-ru/144953.htm.

2. Создание удаленной сессии

3. Получение ссылки на объект, хранящий ID выбранного хоста

4. Обращение к объекту с ID хоста

5. Добавление тэгов

curl -X POST \
 https://ksc_address:13299/api/v1.0/HostTags.ListTags.SetTags \
  -H ' X-KSC-Session:  ' \
  -d '{
	"pListItemsTags": [
    {
      "type": "params",
      "value": {
        "KLTAGS_ITEM_ID": "",
        "KLTAGS_TAGS": [
          {
            "type": "params",
            "value": {
              "KLTAGS_SET": true,
              "KLTAGS_VALUE": "tag1"
            }
          },
          {
            "type": "params",
            "value": {
              "KLTAGS_SET": true,
              "KLTAGS_VALUE": "tag2"
            }
          }
        ]
      }
    }
  ],
  "pParams": {
    "KLTAGS_FULL_REPLACE": true
  }
}
'
  • pListItemsTags — список, содержащий в себе параметры, простановки тэгов;

  • KLTAGS_ITEM_ID — ID элемента (в данном случае ID хоста), для которого будут проставлены тэги;

  • KLTAGS_TAGS — список тэгов, которые содержат следующие параметры: KLTAGS_VALUE — название тэга, KLTAGS_SET — true для проставления тэга и false для его удаления;

  • KLTAGS_FULL_REPLACE — флаг, принимающий значение true, если требуется полностью перезаписать все тэги на узле, false — не требуется.

Response:

{ }

6. Завершаем сессию

Заключение

KSC Open API предоставляет достаточно широкий спектр возможностей реагирования, который напрямую зависит от типов продуктов «Лаборатории Касперского», подключенных к KSC. Документация у API подробная, однако начинающему разработчику сразу разобраться в тонкостях ее работы будет нелегко. Причина — неоднозначные названия аргументов, которые могут быть не задокументированными, а также неочевидные требования к структуре самих запросов, как, например, тот же тип params. Помочь в решении данной проблемы может приведение примеров напрямую с использованием вебхук-запросов для каждой функции класса, которые содержали бы в себе также примеры ответов со ссылками на объяснение возвращаемых атрибутов.

© Habrahabr.ru