Контроль изменений параметров UAC

В данной статье я хочу рассмотреть реализацию детектирования следующего сценария с помощью системы сбора и обработки событий ИБ OSSIM:

Выявлять инцидент ИБ, которым является включение параметра «password never expires» для учетных записей (далее — УЗ) пользователей, находящихся в определенном Organizational Unit (далее — OU).

Для этого я буду использовать функционал custom functions. Постараюсь быть краток и не останавливаться подробно на вопросах сравнения по спискам (active lists) в OSSIM, благо эта тема уже рассмотрена в статье.

Одна из написанных мной для реализации данного сценария функций будет искать совпадение имени пользователя со списком УЗ целевого OU (список представляет собой текстовый файл). Другая функция будет получать значение параметра «Password Never Expires» из событий изменения UAC приходящих от Microsoft Windows Active Directory. Список УЗ целевого OU формируется посредством ежедневной выгрузки из AD. Подробная схема работы сценария приведена на рисунке ниже.

Рисунок 1 — Схема работы сценария

Рассмотрим подробнее этапы работы сценария:

1. Скрипт ldap_search.sh запускается на ежедневной основе с использованием планировщика cron и создает файл со списком всех УЗ, входящих в целевой OU (задается в теле скрипта).

Листинг скрипта приведен ниже.

#!/bin/bash
AD_HOST=10.0.0.240
USER="Administrator@domain.test"
PWD_FILE="pwd.txt"
OU="ou=test_ou,dc=domain,dc=test"
OUTPUT_FILE="/root/test_new.txt"
ldapsearch -D $USER -y $PWD_FILE -h $AD_HOST -b $OU "(objectclass=*)"|grep sAMAccountName|awk -F " " {'print $2'}|grep -v \\$ > $OUTPUT_FILE

Файл, в котором хранится пароль УЗ пользователя, под которой выполняется подключение к LDAP хранится в отдельном файле. Обратите внимание, что заполнять этот файл нужно следующим образом:

echo –n [YOUR_STRONG_PASSWORD] > pwd.txt

чтобы в него не попало символов новой строки. Ну и, чтобы обезопасить себя:

chmod 600 pwd.txt
2. Когда в OSSIM приходит событие MS AD об изменении UAC (Windows ID 4738), его обрабатывают 3 функции: ou_check, win_account, win_uac

События MS AD собираются системой OSSIM посредством WMI плагина. Это не лучший вариант, но в данном сценарии был использован именно он. Перенастроить функции для обработки событий, собираемых с MS AD с помощью OSSEC не составит труда. Да и, тем более, OSSEC разбирает события лучше, чем WMI плагин, и в этом случае часть функций (например, которые получают имена пользователей) будут не нужны, т.к. плагин для OSSEC уже это делает.

Пример события в «сыром» виде (RAW LOG), как оно выглядит в интерфейсе OSSIM:

nsrv_WinSRV-DC.domain.test|4738|Security|A user account was changed.\r\n\r\nSubject:\r\n\tSecurity
ID:\t\tS-1-5-21-2827692199-2880599349-568663292-500\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDOMAIN\r\n\tLogon
ID:\t\t0x2E6325\r\n\r\nTarget Account:\r\n\tSecurity ID:\t\tS-1-5-21-2827692199-2880599349-568663292-1117\r\n\tAccount
Name:\t\tuser2\r\n\tAccount Domain:\t\tDOMAIN\r\n\r\nChanged Attributes:\r\n\tSAM Account Name:\t-\r\n\tDisplay Name:\t\t-\r\n\tUser Principal Name:\t-\r\n\tHome Directory:\t\t-\r\n\tHome Drive:\t\t-\r\n\tScript Path:\t\t-\r\n\tProfile Path:\t\t-\r\n\tUser Workstations:\t-\r\n\tPassword Last Set:\t-\r\n\tAccount Expires:\t\t-\r\n\tPrimary Group ID:\t-\r\n\tAllowedToDelegateTo:\t-\r\n\tOld UAC Value:\t\t0x10\r\n\tNew UAC Value:\t\t0x210\r\n\tUser Account Control:\t\r\n\t\t\'Don\'t Expire Password\' - Enabled\r\n\tUser Parameters:\t-\r\n\tSID History:\t\t-\r\n\tLogon Hours:\t\t-\r\n\r\nAdditional Information:\r\n\tPrivileges:\t\t-|23878898|Microsoft-Windows-Security-Auditing|20170508132149.835240-000|(null)
3. Функция ou_check выполняет проверку вхождения УЗ пользователя, полученной в сыром событии, в список, составляемый скриптом ldap_search.sh. В случае успеха проверки, возвращает строку «OU_matched»

В конфигурационный файл штатного плагина WMI-security-logger добавлена строка userdata7={:ou_check($3)}, благодаря которой результат сверки попадает в поле userdata7.
Тело функции ou_check (для файла кастомных функций):

Start Function ou_check
   import re
   def ou_check(self,input=''):
      try:
         uname = re.findall( 'Account Name:[^\w]t[^\w]t(\S+)[^\w]r[^\w]', input )[1]
         f = open('/etc/ossim/agent/plugins/custom_functions/ou_users.txt')
         for line in f:
            linen = line.strip('\n')
            if uname == linen:
               return 'OU_matched'
      except:
         return None
End Function
4. Функция win_account получает из сырого события имя УЗ пользователя, которая была модифицирована.

В конфигурационный файл штатного плагина WMI-security-logger добавлена строка username={:win_account($3)}, благодаря которой имя УЗ попадает в поле username. Тело функции win_account:

Start Function win_account
   import re
   def win_account(self, input=''):
      try:
         try:
            res = re.search( 'Logon Account:[^\w]t(\S+)[^\w]r[^\w]', input ).group(1)
            return res
         except:
            res = re.findall( 'Account Name:[^\w]t[^\w]t(\S+)[^\w]r[^\w]', input )
            if len(res) > 1:
               return res[1]
            else:
               return res[0]
      except:
         return None
End Function
5. Функция win_uac получает из сырого сообщения информацию о включении или выключении флага «Don’t expire password».

Это значение может быть «Enabled» или «Disabled». В конфигурационный файл штатного плагина WMI-security-logger добавлена строка userdata8={:win_uac($3)}, благодаря которой значение флага попадает в поле userdata8. Тело функции win_uac:

Start Function win_uac
   import re
   def win_uac(self, input=''):
      try:
         res = re.search( 'Don[^\w]\'t Expire Password[^\w]\' \- (\S+)[^\w]r[^\w]', input ).group(1)
         return res
      except:
         return None
End Function
6. Последним этапом является создание директивы, срабатывающей при одновременном выполнении условий:
  • Datasource=1518;
  • Event type=4738;
  • userdata7=OU_matched;
  • userdata8=Enabled.

Выполнение условий означает, что УЗ пользователя, состоящей в целевом OU был установлен флаг «Don’t expire password». Пример вида директивы на рисунке ниже. Ключевые условия выделены красным цветом.


Рисунок 2 – Пример директивы

Осталось только отметить, что все функции должны быть помещены в файл кастомных функций и на него должна быть ссылка из конфигурационного файла плагина, например так: custom_functions_file=/etc/ossim/agent/plugins/custom_functions/wmi_funcs.cfg.
Получившийся в итоге конфигурационный файл плагина:

[DEFAULT]
plugin_id=1518
[config]
type=detector
enable=yes
source=wmi
credentials_file=/etc/ossim/agent/wmi_credentials.csv
sleep=10
process=
start=no
stop=no
custom_functions_file=/etc/ossim/agent/plugins/custom_functions/wmi_funcs.cfg
[start_cmd]
cmd=wmic -U OSS_WMI_USER%OSS_WMI_PASS //OSS_WMI_HOST "Select LogFile,RecordNumber from Win32_NTLogEvent Where Logfile = 'Security'" | head -n 3 | tail -n 1 | cut -f 2 -d \|
regexp=
[cmd]
cmd = wmic -U OSS_WMI_USER%OSS_WMI_PASS //OSS_WMI_HOST "Select ComputerName,EventCode,Logfile,Message,RecordNumber,SourceName,TimeWritten,User from Win32_NTLogEvent Where Logfile = 'Security' and RecordNumber > OSS_COUNTER" | cat
start_regexp=^([^\|]+)\|(\d+)\|([^\|]+)\|
regexp="^(?P[^\|]+)\|(?P\d+)\|(?P[^\|]+)\|(?P[^\|]+)\|(?P[^\|]+)\|(?P[^\|]+)\|(?P[^\|]+)\|(?P.*)$"
src_ip={resolv($0)}
plugin_sid={$1}
userdata2={$2}
userdata3={$3}
userdata4={$4}
userdata5={$5}
userdata6={$6}
username={:win_account($3)}
userdata7={:ou_check($3)}
userdata8={:win_uac($3)}
userdata9={:win_initiator($3)}