def get_rule_name_for_allowed_accounts_windows(self, events: list,
                                                   _self_params,
                                                   correlation_rule_name):
        """Генерирует новое имя для правила корреляции, с целью определения,
        разрешена ли авторизация конкретной УЗ на критичном хосте"""
        rule_name = self.get_rule_name_for_crit_hosts(events, _self_params,
                                                      correlation_rule_name)
        if '-ON-CRITICAL-HOST' in rule_name:
            with open('./lists/allowed_accounts_windows.txt', 'r') as f:
                file = f.read().splitlines()
            file_set = set(file)

            for event in events:
                _organization = getval(_self_params, event,
                                       "collector.organization")
                _host_ip = getval(_self_params, event,
                                  "eventSource.location.ip")
                _user_domain = getval(_self_params, event, "subject.domain")
                _username = getval(_self_params, event, "subject.name")
                _logon_type = getval(_self_params, event,
                                     "interaction.logonType")
                _composite = f'{_organization}{_host_ip}{_user_domain}{_username}{_logon_type}'.lower(
                )
                if _composite not in file_set:
                    _new_corr_rule_name = correlation_rule_name + '-UNAUTHORIZED-ACCOUNT'
                    return _new_corr_rule_name
        else:
            return
 def filtering_authorized_unix_account(_selfParams, _eventsList: list):
     """Удалеяет предварительно сагрегированные по subject.id события, если для subject.id указано соответсвие
     eventSource.location.host в индексе unix_authorization
     """
     _filteredEventList = []
     if len(_eventsList) < 1:
         return _filteredEventList
     _ES = _selfParams.ESInstance
     _firstEvent = _eventsList[0]
     _organization = getval(_selfParams, _firstEvent, "collector.organization").lower()
     _host = getval(_selfParams, _firstEvent, "eventSource.location.host").lower()
     _subjectID = getval(_selfParams, _firstEvent, "subject.id")
     _docCount = 0
     _uidList = []
     _searchQuery = {
         "query": {
             "query_string": {
                 "query": f'organization: "{_organization}" AND (hostname: "{_host}" OR ipaddr: "{_host}")'
             }
         }
     }
     _searchResult = _ES.search(index='unix_authorization', body=_searchQuery)
     if isinstance(_searchResult['hits']['total'], dict):
         if 'value' in _searchResult['hits']['total']:
             _docCount = _searchResult['hits']['total']['value']
     elif isinstance(_searchResult['hits']['total'], int):
         _docCount = _searchResult['hits']['total']
     if _docCount > 0:
         for doc in _searchResult['hits']['hits']:
             _uidList.append(doc['_source']['uid'])
     if not _subjectID in _uidList:
         _filteredEventList = _eventsList
     return _filteredEventList
    def get_rule_name_for_crit_hosts(events: list, _selfParams,
                                     original_corr_rule_name) -> str:
        """Генерирует новое имя для правила корреляции, с целью определения,
        является ли хост критичным или нет"""
        _is_included = False
        with open('./lists/critical_hosts.txt', 'r') as f:
            _file = f.read().splitlines()
        _file_set = set(_file)
        for event in events:
            _organization = getval(_selfParams, event,
                                   "collector.organization")
            _host_ip = getval(_selfParams, event, "eventSource.location.ip")
            _hostname = getval(_selfParams, event,
                               "eventSource.location.hostname")
            _composite_ip = _organization + _host_ip
            _composite_hostname = _organization + _hostname

            if _composite_hostname in _file_set:
                _is_included = True
            elif _composite_ip in _file_set:
                _is_included = True

        if _is_included:
            _new_corr_rule_name = original_corr_rule_name + '-ON-CRITICAL-HOST'
        else:
            _new_corr_rule_name = original_corr_rule_name + '-ON-NON-CRITICAL-HOST'
        return _new_corr_rule_name
 def filtering_not_different_subject_and_object(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в которых subject.name и object.name - одинаковы"""
     _filteredEventList = []
     for event in event_list:
         if not getval(_selfParams, event, "subject.name") == getval(_selfParams, event, "object.name"):
             _filteredEventList.append(event)
     return _filteredEventList
 def filtering_legal_admin_activity_on_fortigate(_selfParams,
                                                 event_list: list):
     """Из массива со скорелированными событиями удаляет события
     с легитимной активностью админ. УЗ при выполнении команд на Fortigate"""
     _filteredEventList = []
     _eventIdWithObjectList = [
         "0100044544", "0100044545", "0100044546", "0100044547",
         "0100044548", "0100044549", "0100044550", "0100044551",
         "0100044552"
     ]
     # 0100044544 - Path configured
     # 0100044545 - Object configured
     # 0100044546 - Attribute configured
     # 0100044547 - Object attribute configured
     # 0100044548 - Action performed
     # 0100044549 - Object attribute configured by maintainer
     # 0100044550 - Object configured by maintainer
     # 0100044551 - Attribute configured by maintainer
     # 0100044552 - Path configured by maintainer
     with open('./lists/fortigate_superadmins.txt', 'r') as _fSuper:
         _fileSuper = _fSuper.read()
     _fileSetSuper = set(_fileSuper.splitlines())
     with open('./lists/fortigate_admin_forbidden_actions.txt',
               'r') as _fForbidden:
         _fileForbidden = _fForbidden.read()
     _fileSetForbidden = set(_fileForbidden.splitlines())
     with open('./lists/fortigate_admin_allowed_actions.txt',
               'r') as _fAllowed:
         _fileAllowed = _fAllowed.read()
     _fileSetAllowed = set(_fileAllowed.splitlines())
     for event in event_list:
         _organization = getval(_selfParams, event,
                                "collector.organization")
         _device = getval(_selfParams, event, "eventSource.location.ip")
         _userName = getval(_selfParams, event, "subject.name")
         _eventId = getval(_selfParams, event, "data.msgId")
         _compositeSuperAdmin = f'\'{_organization}\'|\'{_device}\'|\'{_userName}\''.lower(
         )
         if _compositeSuperAdmin not in _fileSetSuper:
             if _eventId in _eventIdWithObjectList:
                 _object = event['data']['aux1'].split(' ')[1]
                 _compositeWithObject = f'\'{_organization}\'|\'{_device}\'|\'{_userName}\'|\'{_eventId}\'|\'{_object}\''.lower(
                 )
                 if (_compositeWithObject in _fileSetForbidden
                         or _compositeWithObject not in _fileSetAllowed):
                     _filteredEventList.append(event)
             else:
                 _compositeWithoutObject = f'\'{_organization}\'|\'{_device}\'|\'{_userName}\'|\'{_eventId}\'|\'\''.lower(
                 )
                 if (_compositeWithoutObject in _fileSetForbidden
                         or _compositeWithoutObject not in _fileSetAllowed):
                     _filteredEventList.append(event)
     return _filteredEventList
    def filtering_unix_account_in_allowed_time(_selfParams, _eventsList: list):
        """Удалеяет предварительно сагрегированные по субъекту события,
        если сейчас для субъекта разрешенное время
        """
        def is_time_in_middle(_firstTime, _secondTime, _comparableTime):
            _isTimeInMiddle = False
            _midnightTimeMin = datetime.time(hour=0, minute=0, second=0)
            _midnightTimeMax = datetime.time(hour=23, minute=59, second=59)
            if _firstTime < _secondTime:
                if _firstTime < _comparableTime < _secondTime:
                    _isTimeInMiddle = True
            else:
                if _firstTime < _comparableTime <= _midnightTimeMax or _midnightTimeMin <= _comparableTime < _secondTime:
                    _isTimeInMiddle = True
            return _isTimeInMiddle

        _filteredEventList = []
        if len(_eventsList) < 1:
            return _filteredEventList
        _toAlert = True
        _ES = _selfParams.ESInstance
        _firstEvent = _eventsList[0]
        _organization = getval(_selfParams, _firstEvent, "collector.organization").lower()
        _host = getval(_selfParams, _firstEvent, "eventSource.location.host").lower()
        _subjectID = getval(_selfParams, _firstEvent, "subject.id")
        _fromZone = tz.gettz('UTC')
        _toZone = tz.gettz('Europe/Moscow')
        _eventTime = parser.parse(_firstEvent['@timestamp']).replace(tzinfo=_fromZone).astimezone(_toZone).time()
        _docCount = 0
        _searchQuery = {
            "query": {
                "query_string": {
                    "query": f'organization: "{_organization}" AND (hostname: "{_host}" OR ipaddr: "{_host}") AND uid: "{_subjectID}"'
                }
            }
        }
        _searchResult = _ES.search(index='unix_authorization', body=_searchQuery)
        if isinstance(_searchResult['hits']['total'], dict):
            if 'value' in _searchResult['hits']['total']:
                _docCount = _searchResult['hits']['total']['value']
        elif isinstance(_searchResult['hits']['total'], int):
            _docCount = _searchResult['hits']['total']
        if _docCount > 0:
            _firstDoc = _searchResult['hits']['hits'][0]
            _startTime = datetime.datetime.strptime(_firstDoc['_source']['hour_start'], '%H:%M:%S').replace(tzinfo=_toZone).time()
            _endTime = datetime.datetime.strptime(_firstDoc['_source']['hour_end'], '%H:%M:%S').replace(tzinfo=_toZone).time()
            if is_time_in_middle(_startTime, _endTime, _eventTime):
                _toAlert = False
        if _toAlert:
            _filteredEventList = _eventsList
        return _filteredEventList
 def filtering_not_in_list_process(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в которых имя процесса не прописан в списке"""
     _filteredEventList = []
     with open('./lists/monitored_app_list.txt', 'r') as _f:
         _file = _f.read()
     _fileSet = set(_file.splitlines())
     for event in event_list:
         _organization = getval(_selfParams, event, "collector.organization")
         _newProcessFileName = getval(_selfParams, event, "object.path")
         _compositeProcessName = f'\'{_organization}\'|\'{_newProcessFileName}\''.lower()
         if _compositeProcessName in _fileSet:
             _filteredEventList.append(event)
     return _filteredEventList
 def filtering_not_critical_unix_host(_selfParams, _eventsList: list):
     """
     Фильтрует те события, в которых eventSource.location.host не указан в списке unix_critical_hosts
     """
     _filteredEventList = []
     with open('./lists/unix_critical_hosts.txt', 'r') as _f:
         _file = _f.read().splitlines()
     _fileSet = set(_file)
     for event in _eventsList:
         _organization = getval(_selfParams, event, "collector.organization")
         _host = getval(_selfParams, event, "eventSource.location.host")
         _composite = f"'{_organization}'|'{_host}'".lower()
         if _composite in _fileSet:
             _filteredEventList.append(event)
     return _filteredEventList
 def filtering_not_in_list_gpo(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     если GUID или DN GPO в которых не прописаны в списке"""
     _filteredEventList = []
     with open('./lists/controlled_gpo_list.txt', 'r') as _f:
         _file = _f.read()
     _fileSet = set(_file.splitlines())
     for event in event_list:
         _organization = getval(_selfParams, event, "collector.organization")
         _GPOGUID = getval(_selfParams, event, "object.id")
         _GPODN = getval(_selfParams, event, "object.path")
         _compositeGUID = f'\'{_organization}\'|\'{_GPOGUID}\''.lower()
         _compositeDN = f'\'{_organization}\'|\'{_GPODN}\''.lower()
         if _compositeGUID in _fileSet or _compositeDN in _fileSet:
             _filteredEventList.append(event)
     return _filteredEventList
 def filtering_not_hidden_shared_folder(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в object.name которых не указана скрытая расшаренная сетевая папка"""
     _hiddenSharedFolderPattern = re.compile("^\\\\\\\\\*\\\\[\w]+\$$")
     _filteredEventList = []
     for event in event_list:
         if _hiddenSharedFolderPattern.match(getval(_selfParams, event, "object.name")):
             _filteredEventList.append(event)
     return _filteredEventList
 def filtering_subject_system_accounts(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в которых subject.name - системное УЗ"""
     _filteredEventList = []
     for event in event_list:
         _subject_name = getval(_selfParams, event, "subject.name")
         if not _subject_name.endswith('$'):
             _filteredEventList.append(event)
     return _filteredEventList
    def get_rule_name_for_critical_groups_windows(
            events: list, _selfParams, original_corr_rule_name) -> str:
        """Генерирует новое имя для правила корреляции, с целью определения,
        критичная ли это windows группа"""
        with open('./lists/critical_groups_windows.txt', 'r') as f:
            _file = f.read().splitlines()
        _file_set = set(_file)
        for event in events:
            _organization = getval(_selfParams, event,
                                   "collector.organization")
            _domain = getval(_selfParams, event, "object.domain")
            _group_name = getval(_selfParams, event, "object.name")
            _composite = f'{_organization}{_domain}{_group_name}'.lower()
            if _composite in _file_set:
                _new_corr_rule_name = original_corr_rule_name + '-FROM-CRITICAL-LIST'
                return _new_corr_rule_name

        return original_corr_rule_name
    def get_rule_name_for_allowed_accounts_network(events: list, _selfParams,
                                                   correlation_rule_name):
        """Генерирует новое имя для правила корреляции, с целью определения,
        разрешена ли авторизация конкретной УЗ на критичном хосте сетевого оборудования"""
        with open('./lists/allowed_accounts_network.txt', 'r') as f:
            _file = f.read()
        _file_set = set(_file.splitlines())

        for event in events:
            _organization = getval(_selfParams, event,
                                   "collector.organization")
            _host_ip = getval(_selfParams, event, "eventSource.location.ip")
            _username = getval(_selfParams, event, "subject.name")
            _composite_host = f'{_organization}{_host_ip}'.lower()
            _composite_user = f'{_organization}{_host_ip}{_username}'.lower()
            if _composite_host in _file:
                if _composite_user not in _file_set:
                    _new_corr_rule_name = correlation_rule_name + '-UNAUTHORIZED-ACCOUNT'
                    # Инцидент, т.к. данному пользователю не разрешена авторизация на данный хост
                    return _new_corr_rule_name
        return  # Данный хост не критичный или пользователю разрешена атворизация на данный хост
 def filtering_not_psexec_filenames(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в которых имя файла не содержит PsExec и ее аналогов"""
     _filteredEventList = []
     _PsExecProcessPatternList = ["psexec.*", "winexec.*", "csexec.*", "paexec.*"]
     _PsExecServicePatternList = ["psexe.*", "winexe.*", "csexe.*", "paexe.*"]
     for event in event_list:
         # Event ID: "4688" - A new process has been created
         msg_id = getval(_selfParams, event, "data.msgId")
         if msg_id == "4688":
             _newProcessFileName = ntpath.basename(getval(_selfParams, event, "object.path")).lower()
             for _PsExecProcessPattern in _PsExecProcessPatternList:
                 if re.compile(_PsExecProcessPattern).match(_newProcessFileName):
                     _filteredEventList.append(event)
         # Event ID: "7045" - New Service was installed
         elif msg_id == "7045":
             _newServiceFileName = ntpath.basename(getval(_selfParams, event, "object.path")).lower()
             for _PsExecServicePattern in _PsExecServicePatternList:
                 if re.compile(_PsExecServicePattern).match(_newServiceFileName):
                     _filteredEventList.append(event)
     return _filteredEventList
 def filtering_dwm_umfd_accounts(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в subject.name которых указаны DWM-x и UMFD-x"""
     # DWM-x Desktop Window Manager
     _DWMPattern = re.compile("^DWM-[0-9]+$")
     # UMFD-x User Mode Driver Framework
     _UMFDPattern = re.compile("^UMFD-[0-9]+$")
     _filteredEventList = []
     for event in event_list:
         _subject_name = getval(_selfParams, event, "subject.name")
         if not (_DWMPattern.match(_subject_name) or _UMFDPattern.match(_subject_name)):
             _filteredEventList.append(event)
     return _filteredEventList
Beispiel #16
0
    def get_windows_chang_time_corr_rule_name(events: list, _selfParams,
                                              corr_rule_name_in) -> str:
        """Генерирует новое имя для правила корреляции, с целью выявления,
        изменилось ли время на узле более чем на 5 минут
        """
        _corrRuleName = ""
        _is_more = False
        for event in events:
            # raw_date_format: '2020-11-02T10:36:06.474026900Z'
            previous_time = datetime.fromisoformat(
                getval(_selfParams, event, "object.property").split('.')[0])
            new_time = datetime.fromisoformat(
                getval(_selfParams, event, "object.value").split('.')[0])

            delta = abs((new_time - previous_time).total_seconds())
            if delta > 300:
                _is_more = True

        if _is_more:
            _corrRuleName = corr_rule_name_in + '-OVER-FIVE-MINUTES'
        else:
            _corrRuleName = corr_rule_name_in + '-LESS-FIVE-MINUTES'
        return _corrRuleName
    def filtering_malicious_service_installations(_selfParams, event_list: list):
        """
        Оставляет только те события, которые подходят под условие правила Malicious Service Installations.
        """
        _filteredEventList = []
        for event in event_list:
            _service_name = getval(_selfParams, event, "object.name").lower()
            _service_file_name = getval(_selfParams, event, "object.path").lower()

            if _service_name in ['wceservice', 'wce service', 'mssecsvc2.0']:
                _filteredEventList.append(event)
            elif (_service_name.startswith('pwdump')
                    or _service_name.startswith('gsecdump')
                    or _service_name.startswith('cachedump')):
                _filteredEventList.append(event)
            elif r'\paexec' in _service_file_name:
                _filteredEventList.append(event)
            elif _service_file_name.startswith('winexesvc.exe'):
                _filteredEventList.append(event)
            elif _service_file_name.endswith(r'\dumpsvc.exe'):
                _filteredEventList.append(event)
            elif ' net user ' in _service_file_name:
                _filteredEventList.append(event)
        return _filteredEventList
 def filtering_not_cmd_password_search(_selfParams, event_list: list):
     """Из массива со скорелированными событиями удаляет события,
     в которых CommandLine в data.aux7 не содержит CMD комманд поиска паролей"""
     _filteredEventList = []
     _passwordSearchCMDProcessPatternList = [
         "find.*password.*", "dir.*pass.*", "dir.*vnc\.ini.*", "dir.*unattend\.xml.*",
         "dir.*sysprep\.xml.*", "dir.*sysprep\.inf.*", "reg.*query.*password.*",
         "reg.*query.*putty.*", ".*get-unattendedinstallfile.*", ".*get-webconfig.*",
         ".*get-applicationhost.*", ".*get-sitelistpassword.*", ".*get-cachedgpppassword.*",
         ".*get-registryautologon.*"
     ]
     for event in event_list:
         _newProcessCommandLine = getval(_selfParams, event, "data.aux7").lower()
         for _passwordSearchCMDProcessPattern in _passwordSearchCMDProcessPatternList:
             if re.compile(_passwordSearchCMDProcessPattern).match(_newProcessCommandLine):
                 _filteredEventList.append(event)
     return _filteredEventList
    def filtering_detects_rubeus_hack_tool(_selfParams, event_list: list):
        """
        Оставляет только те события, которые подходят под условие правила Detects Rubeus Hack Tool.
        """
        _filteredEventList = []
        _indicators_list = [r' asreproast ',
                            r' dump /service:krbtgt ',
                            r' kerberoast ',
                            r' createnetonly /program:',
                            r' ptt /ticket:',
                            r' /impersonateuser:'******' renew /ticket:',
                            r' asktgt /user:'******' harvest /interval:'
                            ]
        for event in event_list:
            _new_process_name = getval(_selfParams, event, "object.path").lower()

            for _indicator in _indicators_list:
                if _indicator in _new_process_name:
                    _filteredEventList.append(event)
        return _filteredEventList