class TimeCorrelationDetectorTest(TestBase):
    __expected_string = '%s Correlation report\nTimeCorrelationDetector: "%s" (%d lines)\n  '

    string = b'25537 uid=2'
    datetime_format_string = '%Y-%m-%d %H:%M:%S'

    fixed_dme = FixedDataModelElement('s1', string)
    decimal_integer_value_me = DecimalIntegerValueModelElement('d1', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                                                               DecimalIntegerValueModelElement.PAD_TYPE_NONE)

    match_context_first_match_me = MatchContext(string)
    first_match_me = FirstMatchModelElement('f1', [fixed_dme, decimal_integer_value_me])
    match_element_first_match_me = first_match_me.get_match_element('first', match_context_first_match_me)

    match_context_first_match_me2 = MatchContext(string)
    first_match_me2 = FirstMatchModelElement('f2', [decimal_integer_value_me, fixed_dme])
    match_element_first_match_me2 = first_match_me2.get_match_element('second', match_context_first_match_me2)

    def test1_normal_report(self):
        """This test case unit the creation of a report. As the rules are chosen randomly this test can not be very specific in checking
        the actual values of the report."""
        description = "Test1TimeCorrelationDetector"
        time_correlation_detector = TimeCorrelationDetector(self.aminer_config, 2, 1, 0, [self.stream_printer_event_handler],
                                                            record_count_before_event=10)
        self.analysis_context.register_component(time_correlation_detector, component_name=description)

        t = time.time()
        for i in range(0, 10):
            logAtomSequenceME = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_first_match_me), t,
                                        time_correlation_detector)
            time_correlation_detector.receive_atom(logAtomSequenceME)
        self.assertTrue(self.output_stream.getvalue().startswith(
            self.__expected_string % (datetime.fromtimestamp(t).strftime(self.datetime_format_string), description, 10)))
        self.reset_output_stream()

        for i in range(0, 10):
            logAtomSequenceME = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_first_match_me), t + i,
                                        time_correlation_detector)
            time_correlation_detector.receive_atom(logAtomSequenceME)
        self.assertTrue(self.output_stream.getvalue().startswith(
            self.__expected_string % (datetime.fromtimestamp(t + 9).strftime(self.datetime_format_string), description, 20)))
        self.reset_output_stream()

        for i in range(10, 15):
            logAtomSequenceME = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_first_match_me), t + i,
                                        time_correlation_detector)
            time_correlation_detector.receive_atom(logAtomSequenceME)
            logAtomSequenceME2 = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_first_match_me2), t + i,
                                         time_correlation_detector)
            time_correlation_detector.receive_atom(logAtomSequenceME2)
        self.assertTrue(self.output_stream.getvalue().startswith(
            self.__expected_string % (datetime.fromtimestamp(t + 14).strftime(self.datetime_format_string), description, 30)))
 def run_time_correlation_detector(self, number_of_rules):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         time_correlation_detector = TimeCorrelationDetector(
             self.aminer_config,
             2,
             number_of_rules,
             0, [self.stream_printer_event_handler],
             record_count_before_event=self.waiting_time * 9000)
         t = time.time()
         seconds = time.time()
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             match_context = MatchContext(str(i % 100).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             log_atom = LogAtom(match_element.match_string,
                                ParserMatch(match_element), t,
                                time_correlation_detector)
             time_correlation_detector.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         time_correlation_detector.__class__.__name__, avg, results,
         'testCount=%d.' % number_of_rules)
 def test2receive_atoms_with_defined_path_list(self):
     """
     In this test case multiple log_atoms are received with default values of the EventTypeDetector.
     path_list is set to a static list of paths and variable_key_list should not be used.
     """
     event_type_detector = EventTypeDetector(
         self.aminer_config, [self.stream_printer_event_handler],
         path_list=['parser/type/path/nametype'])
     results = [
         True, False, True, False, True, False, True, True, False, False,
         True, True, False, True, False, True, False, True, False, False,
         True
     ]
     log_atoms = []
     for line in self.log_lines:
         t = time.time()
         log_atoms.append(
             LogAtom(
                 line,
                 ParserMatch(
                     self.parsing_model.get_match_element(
                         'parser', MatchContext(line))), t,
                 self.__class__.__name__))
     for i, log_atom in enumerate(log_atoms):
         old_vals = (event_type_detector.num_events,
                     event_type_detector.num_eventlines,
                     event_type_detector.total_records,
                     event_type_detector.longest_path)
         self.assertEqual(event_type_detector.receive_atom(log_atom),
                          not results[i], i)
         if results[i]:
             self.assertEqual(old_vals, (event_type_detector.num_events,
                                         event_type_detector.num_eventlines,
                                         event_type_detector.total_records,
                                         event_type_detector.longest_path))
 def run_new_match_path_detector(self, number_of_pathes):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         new_match_path_detector = NewMatchPathDetector(
             self.aminer_config, [self.stream_printer_event_handler],
             'Default', True)
         t = round(time.time(), 3)
         seconds = time.time()
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd' + str(i % number_of_pathes),
                 DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             match_context = MatchContext(str(i).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             log_atom = LogAtom(match_element.match_string,
                                ParserMatch(match_element), t,
                                new_match_path_detector)
             new_match_path_detector.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         new_match_path_detector.__class__.__name__, avg, results,
         self.different_pathes % number_of_pathes)
 def run_match_value_stream_writer(self, number_of_pathes):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         i = 0
         path_list = []
         parsing_model = []
         while i < number_of_pathes / 2:
             path_list.append('match/integer/d' + str(i % number_of_pathes))
             path_list.append('match/integer/s' + str(i % number_of_pathes))
             parsing_model.append(
                 DecimalIntegerValueModelElement(
                     'd' + str(i % number_of_pathes),
                     DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                     DecimalIntegerValueModelElement.PAD_TYPE_NONE))
             parsing_model.append(
                 FixedDataModelElement('s' + str(i % number_of_pathes),
                                       b' Euro '))
             i = i + 1
         sequence_model_element = SequenceModelElement(
             'integer', parsing_model)
         match_value_stream_writer = MatchValueStreamWriter(
             self.output_stream, path_list, b';', b'-')
         t = time.time()
         seconds = time.time()
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             data = b''
             p = process_time()
             for j in range(
                     1,
                     int(number_of_pathes / 2) + number_of_pathes % 2 + 1):
                 data = data + str(j).encode() + b' Euro '
             seconds = seconds + process_time() - p
             match_context = MatchContext(data)
             match_element = sequence_model_element.get_match_element(
                 'match', match_context)
             log_atom = LogAtom(match_element.match_object,
                                ParserMatch(match_element), t,
                                match_value_stream_writer)
             match_value_stream_writer.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         match_value_stream_writer.__class__.__name__, avg, results,
         self.different_pathes % number_of_pathes)
 def run_atom_filters_match_value_filter(self, number_of_pathes):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         new_match_path_detector = NewMatchPathDetector(
             self.aminer_config, [self.stream_printer_event_handler],
             'Default', True)
         subhandler_filter = SubhandlerFilter([],
                                              stop_when_handled_flag=True)
         i = 0
         dictionary = {}
         while i < 1000000:
             dictionary[i] = new_match_path_detector
             i = i + 1
         i = 0
         while i < number_of_pathes:
             match_value_filter = MatchValueFilter(
                 self.integerd + str(i % number_of_pathes), dictionary,
                 None)
             subhandler_filter.add_handler(match_value_filter,
                                           stop_when_handled_flag=True)
             i = i + 1
         t = round(time.time(), 3)
         seconds = time.time()
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd' + str(i % number_of_pathes),
                 DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             match_context = MatchContext(str(i).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             log_atom = LogAtom(match_element.match_string,
                                ParserMatch(match_element), t,
                                match_value_filter)
             subhandler_filter.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         subhandler_filter.__class__.__name__, avg, results,
         '%d different %ss with a dictionary of %ss.' %
         (number_of_pathes, match_value_filter.__class__.__name__,
          new_match_path_detector.__class__.__name__))
 def run_whitelist_violation_detector(self, number_of_pathes,
                                      modulo_factor):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         i = 0
         rules = []
         while i < number_of_pathes:
             rules.append(
                 PathExistsMatchRule(
                     self.integerd + str(i % number_of_pathes), None))
             i = i + 1
         whitelist_violation_detector = WhitelistViolationDetector(
             self.aminer_config, rules, [self.stream_printer_event_handler])
         t = time.time()
         seconds = time.time()
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             p = process_time()
             r = random.randint(1, 100)
             if r >= modulo_factor:
                 r = 2
             else:
                 r = 1
             seconds = seconds + process_time() - p
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd' + str(i % (number_of_pathes * r)),
                 DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             match_context = MatchContext(str(i % 100).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             log_atom = LogAtom(match_element.match_string,
                                ParserMatch(match_element), t,
                                whitelist_violation_detector)
             whitelist_violation_detector.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         whitelist_violation_detector.__class__.__name__, avg, results,
         '%d different PathExistsMatchRules and a moduloFactor of %d.' %
         (number_of_pathes, modulo_factor))
 def run_missing_match_path_value_detector(self, number_of_pathes):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         i = 0
         path_list = []
         while i < number_of_pathes:
             path_list.append(self.integerd + str(i % number_of_pathes))
             i = i + 1
         missing_match_path_list_value_detector = MissingMatchPathListValueDetector(
             self.aminer_config, path_list,
             [self.stream_printer_event_handler], 'Default', True, 3600,
             86400)
         seconds = time.time()
         t = seconds
         i = 0
         while int(time.time() - seconds) < self.waiting_time:
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd' + str(i % number_of_pathes),
                 DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             match_context = MatchContext(str(1).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             p = process_time()
             r = random.randint(0, 100)
             seconds = seconds + process_time() - p
             delta = int(r / 100)
             t = t + 4000 * delta
             log_atom = LogAtom(match_element.match_object,
                                ParserMatch(match_element), t,
                                missing_match_path_list_value_detector)
             missing_match_path_list_value_detector.receive_atom(log_atom)
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         missing_match_path_list_value_detector.__class__.__name__, avg,
         results, self.different_pathes % number_of_pathes)
 def test1receive_atoms_with_default_values(self):
     """
     In this test case multiple log_atoms are received with default values of the EventTypeDetector.
     path_list is empty and all paths are learned dynamically in variable_key_list.
     """
     event_type_detector = EventTypeDetector(
         self.aminer_config, [self.stream_printer_event_handler])
     log_atoms = []
     for line in self.log_lines:
         t = time.time()
         log_atoms.append(
             LogAtom(
                 line,
                 ParserMatch(
                     self.parsing_model.get_match_element(
                         'parser', MatchContext(line))), t,
                 self.__class__.__name__))
     for i, log_atom in enumerate(log_atoms):
         self.assertTrue(event_type_detector.receive_atom(log_atom))
         self.assertEqual(event_type_detector.total_records, i + 1)
 def run_timestamps_unsorted_detector(self, reset_factor):
     results = [None] * self.iterations
     avg = 0
     z = 0
     while z < self.iterations:
         timestamps_unsorted_detector = TimestampsUnsortedDetector(
             self.aminer_config, [self.stream_printer_event_handler])
         seconds = time.time()
         s = seconds
         i = 0
         mini = 100
         while int(time.time() - seconds) < self.waiting_time:
             decimal_integer_value_me = DecimalIntegerValueModelElement(
                 'd', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                 DecimalIntegerValueModelElement.PAD_TYPE_NONE)
             p = process_time()
             r = random.randint(1, 100)
             seconds = seconds + process_time() - p
             match_context = MatchContext(str(i).encode())
             match_element = decimal_integer_value_me.get_match_element(
                 'integer', match_context)
             log_atom = LogAtom(match_element.match_string,
                                ParserMatch(match_element),
                                s + min(r, mini),
                                timestamps_unsorted_detector)
             timestamps_unsorted_detector.receive_atom(log_atom)
             if mini > r:
                 mini = r
             else:
                 mini = mini + reset_factor
             i = i + 1
         results[z] = i
         z = z + 1
         avg = avg + i
     avg = avg / self.iterations
     type(self).result = self.result + self.result_string % (
         timestamps_unsorted_detector.__class__.__name__, avg, results,
         'a resetFactor of %f.' % reset_factor)
    def run_timestamp_correction_filters(self, number_of_pathes):
        results = [None] * self.iterations
        avg = 0
        z = 0
        while z < self.iterations:
            new_match_path_detector = NewMatchPathDetector(
                self.aminer_config, [self.stream_printer_event_handler],
                'Default', True)
            simple_monotonic_timestamp_adjust = SimpleMonotonicTimestampAdjust(
                [new_match_path_detector])

            seconds = time.time()
            i = 0
            while int(time.time() - seconds) < self.waiting_time:
                decimal_integer_value_me = DecimalIntegerValueModelElement(
                    'd' + str(i % number_of_pathes),
                    DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                    DecimalIntegerValueModelElement.PAD_TYPE_NONE)
                p = process_time()
                r = random.randint(1, 1000000)
                seconds = seconds + process_time() - p
                match_context = MatchContext(str(i).encode())
                match_element = decimal_integer_value_me.get_match_element(
                    'integer', match_context)
                log_atom = LogAtom(match_element.match_string,
                                   ParserMatch(match_element), seconds - r,
                                   simple_monotonic_timestamp_adjust)
                simple_monotonic_timestamp_adjust.receive_atom(log_atom)
                i = i + 1
            results[z] = i
            z = z + 1
            avg = avg + i
        avg = avg / self.iterations
        type(self).result = self.result + self.result_string % (
            simple_monotonic_timestamp_adjust.__class__.__name__, avg, results,
            'a %s and %d different path(es).' %
            (new_match_path_detector.__class__.__name__, number_of_pathes))
Esempio n. 12
0
class EnhancedNewMatchPathValueComboDetectorTest(TestBase):
    __expected_string = '%s New value combination(s) detected\n%s: "%s" (%d lines)\n%s\n\n'
    __expected_whitelisting_string = 'Whitelisted path(es) %s with %s in %s'
    fixed_dme = FixedDataModelElement('s1', b'25537 uid=')
    fixed_dme2 = FixedDataModelElement('s2', b' uid=2')

    decimal_integer_value_me = DecimalIntegerValueModelElement(
        'd1', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
        DecimalIntegerValueModelElement.PAD_TYPE_NONE)

    match_context_sequence_me = MatchContext(b'25537 uid=2')
    seq = SequenceModelElement('seq', [fixed_dme, decimal_integer_value_me])
    match_element_sequence_me = seq.get_match_element(
        'first', match_context_sequence_me)

    match_context_sequence_me2 = MatchContext(b'25537 uid=2')
    seq2 = SequenceModelElement('seq2', [decimal_integer_value_me, fixed_dme2])
    match_element_sequence_me2 = seq2.get_match_element(
        'second', match_context_sequence_me2)

    first_seq_s1 = 'first/seq/s1'
    first_seq_d1 = 'first/seq/d1'
    datetime_format_string = '%Y-%m-%d %H:%M:%S'
    exp_str = "  first/seq: b'25537 uid=2'\n  " + first_seq_s1 + ": b'25537 uid='\n  " + first_seq_d1 + \
              ": 2\n{(b'25537 uid=', 2): [%s, %s, 1]}"
    exp_str2 = "  {(b'25537 uid=', 2): [%s, %s, 1]}\nb'25537 uid=2'"

    def test1_log_atom_not_known(self):
        """This test case checks the correct processing of unknown log lines, which in reality means that an anomaly has been found. The
        output is directed to an output stream and compared for accuracy. The auto_include_flag is False and the output must be repeatable
        on second run."""
        description = "Test1EnhancedNewMatchPathValueComboDetector"
        enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, [self.first_seq_s1, self.first_seq_d1],
            [self.stream_printer_event_handler],
            'Default',
            False,
            False,
            output_log_line=False)
        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector, description)

        t = round(time.time(), 3)
        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)

        self.assertTrue(
            enhanced_new_match_path_value_combo_detector.receive_atom(
                log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t).strftime(self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description, 1, self.exp_str2 % (t, t)))
        self.reset_output_stream()

        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t + 2,
            enhanced_new_match_path_value_combo_detector)

        # repeating should produce the same result with new extraData.
        self.assertTrue(
            enhanced_new_match_path_value_combo_detector.receive_atom(
                log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t + 2).strftime(
                self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description, 1,
             "  {(b'25537 uid=', 2): [%s, %s, 2]}\nb'25537 uid=2'" %
             (t, t + 2)))
        self.reset_output_stream()

        enhanced_new_match_path_value_combo_detector2 = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, ['second/seq2/d1', 'second/seq2/s2'],
            [self.stream_printer_event_handler],
            'Default',
            False,
            False,
            output_log_line=False)

        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector2, description + "2")
        log_atom_sequence_me2 = LogAtom(
            self.match_element_sequence_me2.get_match_string(),
            ParserMatch(self.match_element_sequence_me2), t,
            enhanced_new_match_path_value_combo_detector2)

        # other MatchElement
        self.assertTrue(
            enhanced_new_match_path_value_combo_detector2.receive_atom(
                log_atom_sequence_me2))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t).strftime(self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description + "2", 1,
             "  {(25537, b' uid=2'): [%s, %s, 1]}\nb'25537 uid=2'" % (t, t)))

    def test2_log_atom_known(self):
        """This test case checks the functionality of the auto_include_flag. If the same MatchElement is processed a second time and the
        auto_include_flag was True, no event must be triggered."""
        description = "Test2EnhancedNewMatchPathValueComboDetector"
        enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, [self.first_seq_s1, self.first_seq_d1],
            [self.stream_printer_event_handler],
            'Default',
            False,
            True,
            output_log_line=False)
        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector, description)

        t = round(time.time(), 3)
        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)

        self.assertTrue(
            enhanced_new_match_path_value_combo_detector.receive_atom(
                log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t).strftime(self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description, 1, self.exp_str2 % (t, t)))
        self.reset_output_stream()

        t = round(time.time(), 3)
        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)

        # repeating should NOT produce the same result, only persist the new extraData.
        self.assertTrue(
            enhanced_new_match_path_value_combo_detector.receive_atom(
                log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), '')
        self.reset_output_stream()

        enhanced_new_match_path_value_combo_detector2 = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, ['second/seq2/d1', 'second/seq2/s2'],
            [self.stream_printer_event_handler],
            'Default',
            False,
            False,
            output_log_line=False)

        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector2, description + "2")
        log_atom_sequence_me2 = LogAtom(
            self.match_element_sequence_me2.get_match_string(),
            ParserMatch(self.match_element_sequence_me2), t,
            enhanced_new_match_path_value_combo_detector2)

        # other MatchElement
        self.assertTrue(
            enhanced_new_match_path_value_combo_detector2.receive_atom(
                log_atom_sequence_me2))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t).strftime(self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description + "2", 1,
             "  {(25537, b' uid=2'): [%s, %s, 1]}\nb'25537 uid=2'" % (t, t)))

    def test3_log_atom_known_from_persisted_data(self):
        """The persisting and reading of permitted log lines should be checked with this test."""
        description = "Test3EnhancedNewMatchPathValueComboDetector"
        enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, [self.first_seq_s1, self.first_seq_d1],
            [self.stream_printer_event_handler],
            'Default',
            False,
            True,
            output_log_line=False)
        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector, description)

        t = round(time.time(), 3)
        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)

        self.assertTrue(
            enhanced_new_match_path_value_combo_detector.receive_atom(
                log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t).strftime(self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description, 1, self.exp_str2 % (t, t)))
        enhanced_new_match_path_value_combo_detector.do_persist()
        self.reset_output_stream()

        other_enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, [self.first_seq_s1, self.first_seq_d1],
            [self.stream_printer_event_handler],
            'Default',
            False,
            False,
            output_log_line=False)
        self.analysis_context.register_component(
            other_enhanced_new_match_path_value_combo_detector,
            description + "2")
        other_log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t + 2,
            other_enhanced_new_match_path_value_combo_detector)

        self.assertTrue(
            other_enhanced_new_match_path_value_combo_detector.receive_atom(
                other_log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t + 2).strftime(
                self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description + "2", 1,
             "  {(b'25537 uid=', 2): [%s, %s, 2]}\nb'25537 uid=2'" %
             (t, t + 2)))
        self.reset_output_stream()

        other_log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t + 5,
            other_enhanced_new_match_path_value_combo_detector)

        self.assertTrue(
            other_enhanced_new_match_path_value_combo_detector.receive_atom(
                other_log_atom_sequence_me))
        self.assertEqual(
            self.output_stream.getvalue(), self.__expected_string %
            (datetime.fromtimestamp(t + 5).strftime(
                self.datetime_format_string),
             enhanced_new_match_path_value_combo_detector.__class__.__name__,
             description + "2", 1,
             "  {(b'25537 uid=', 2): [%s, %s, 3]}\nb'25537 uid=2'" %
             (t, t + 5)))

    def test4_whitelist_event_with_known_and_unknown_paths(self):
        """This test case checks in which cases an event is triggered and compares with expected results."""
        description = "Test4EnhancedNewMatchPathValueComboDetector"
        enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, [self.first_seq_s1, self.first_seq_d1],
            [self.stream_printer_event_handler],
            'Default',
            False,
            True,
            output_log_line=False)
        self.analysis_context.register_component(
            enhanced_new_match_path_value_combo_detector, description)

        t = time.time()
        log_atom_sequence_me = LogAtom(
            self.match_element_sequence_me.get_match_string(),
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)
        self.assertEqual(
            enhanced_new_match_path_value_combo_detector.whitelist_event(
                'Analysis.%s' % enhanced_new_match_path_value_combo_detector.
                __class__.__name__, [
                    log_atom_sequence_me,
                    [self.match_element_sequence_me.get_path()]
                ], [
                    log_atom_sequence_me,
                    self.match_element_sequence_me.get_path()
                ], None), self.__expected_whitelisting_string %
            (', '.join(
                enhanced_new_match_path_value_combo_detector.target_path_list),
             self.match_element_sequence_me.get_path(), log_atom_sequence_me))

        log_atom_sequence_me2 = LogAtom(
            self.match_element_sequence_me2.get_match_string(),
            ParserMatch(self.match_element_sequence_me2), t,
            enhanced_new_match_path_value_combo_detector)

        enhanced_new_match_path_value_combo_detector.auto_include_flag = False
        self.assertEqual(
            enhanced_new_match_path_value_combo_detector.whitelist_event(
                'Analysis.%s' % enhanced_new_match_path_value_combo_detector.
                __class__.__name__, [
                    log_atom_sequence_me2,
                    [self.match_element_sequence_me2.get_path()]
                ], [
                    log_atom_sequence_me2,
                    self.match_element_sequence_me2.get_path()
                ], None), self.__expected_whitelisting_string %
            (', '.join(
                enhanced_new_match_path_value_combo_detector.target_path_list),
             self.match_element_sequence_me2.path, log_atom_sequence_me2))

    def test5save_metadata(self):
        """This test case checks the correctness of the metadata informations"""
        enhanced_new_match_path_value_combo_detector = EnhancedNewMatchPathValueComboDetector(
            self.aminer_config, ['first/f1/s1'],
            [self.stream_printer_event_handler],
            'Default',
            False,
            True,
            None,
            output_log_line=False)
        t = 1
        log_atom_sequence_me = LogAtom(
            self.fixed_dme.fixed_data,
            ParserMatch(self.match_element_sequence_me), t,
            enhanced_new_match_path_value_combo_detector)

        enhanced_new_match_path_value_combo_detector.receive_atom(
            log_atom_sequence_me)
        self.assertEqual(
            enhanced_new_match_path_value_combo_detector.known_values_dict.get(
                (self.fixed_dme.fixed_data, (t, t, 1))), None)
Esempio n. 13
0
    def consumeData(self, streamData, endOfStreamFlag=False):
        """Consume data from the underlying stream for atomizing.
    @return the number of consumed bytes, 0 if the atomizer would
    need more data for a complete atom or -1 when no data was
    consumed at the moment but data might be consumed later on."""
        # Loop until as much streamData as possible was processed and
        # then return a result. The correct processing of endOfStreamFlag
        # is tricky: by default, even when all data was processed, do
        # one more iteration to handle also the flag.
        consumedLength = 0
        while True:
            if self.lastUnconsumedLogAtom != None:
                # Keep length before dispatching: dispatch will reset the field.
                dataLength = len(self.lastUnconsumedLogAtom.rawData)
                if self.dispatchAtom(self.lastUnconsumedLogAtom):
                    consumedLength += dataLength + 1
                    continue
# Nothing consumed, tell upstream to wait if appropriate.
                if consumedLength == 0:
                    consumedLength = -1
                break

            lineEnd = streamData.find(b'\n', consumedLength)
            if self.inOverlongLineFlag:
                if lineEnd < 0:
                    consumedLength = len(streamData)
                    if endOfStreamFlag:
                        self.dispatchEvent(
                            'Overlong line terminated by end of stream',
                            streamData)
                        self.inOverlongLineFlag = False
                    break
                consumedLength = lineEnd + 1
                self.inOverlongLineFlag = False
                continue

# This is the valid start of a normal/incomplete/overlong line.
            if lineEnd < 0:
                tailLength = len(streamData) - consumedLength
                if tailLength > self.maxLineLength:
                    self.dispatchEvent('Start of overlong line detected',
                                       streamData[consumedLength:])
                    self.inOverlongLineFlag = True
                    consumedLength = len(streamData)
                    # Stay in loop to handle also endOfStreamFlag!
                    continue
                if endOfStreamFlag and (tailLength != 0):
                    self.dispatchEvent('Incomplete last line',
                                       streamData[consumedLength:])
                    consumedLength = len(streamData)
                break

# This is at least a complete/overlong line.
            lineLength = lineEnd + 1 - consumedLength
            if lineLength > self.maxLineLength:
                self.dispatchEvent('Overlong line detected',
                                   streamData[consumedLength:lineEnd])
                consumedLength = lineEnd + 1
                continue


# This is a normal line.
            lineData = streamData[consumedLength:lineEnd]
            logAtom = LogAtom(lineData, None, None, self)
            if self.parsingModel != None:
                matchContext = MatchContext(lineData)
                matchElement = self.parsingModel.getMatchElement(
                    '', matchContext)
                if (matchElement != None) and not matchContext.matchData:
                    logAtom.parserMatch = ParserMatch(matchElement)
                    if self.defaultTimestampPath != None:
                        tsMatch = logAtom.parserMatch.getMatchDictionary().get(
                            self.defaultTimestampPath, None)
                        if tsMatch != None:
                            logAtom.setTimestamp(tsMatch.matchObject[1])
            if self.dispatchAtom(logAtom):
                consumedLength = lineEnd + 1
                continue
            if consumedLength == 0:
                # Downstream did not want the data, so tell upstream to block
                # for a while.
                consumedLength = -1
            break
        return consumedLength
Esempio n. 14
0
class ParserCountTest(TestBase):
    match_context_m1 = MatchContext(b'First string')
    match_context_m2 = MatchContext(b' to match.')
    match_context_m3 = MatchContext(b'some completely other string to match.')
    match_context_seq = MatchContext(b'First string to match.')
    fixed_dme_m1 = FixedDataModelElement('m1', b'First string')
    fixed_dme_m2 = FixedDataModelElement('m2', b' to match.')
    seq = SequenceModelElement('seq', [fixed_dme_m1, fixed_dme_m2])
    fixed_dme_m3 = FixedDataModelElement(
        'm3', b'some completely other string to match.')
    match_element_m1 = fixed_dme_m1.get_match_element('fixed',
                                                      match_context_m1)
    match_element_m2 = fixed_dme_m2.get_match_element('fixed',
                                                      match_context_m2)
    match_element_m3 = fixed_dme_m3.get_match_element('fixed',
                                                      match_context_m3)
    match_element_seq = seq.get_match_element('fixed', match_context_seq)

    def test1log_atom_not_in_path_list(self):
        """This unittest checks if no action happens, when no path in the match_dictionary matches a target_path."""
        parser_count = ParserCount(
            self.aminer_config, ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2'],
            [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.fixed_dme_m3.fixed_data,
                           ParserMatch(self.match_element_m3), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test2log_atom_matches_single_path(self):
        """This unittest tests the receive_atom method with a single path matching."""
        parser_count = ParserCount(
            self.aminer_config,
            ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
            [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.fixed_dme_m3.fixed_data,
                           ParserMatch(self.match_element_m3), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/m3'] = 1
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test3log_atom_matches_multiple_paths(self):
        """This unittest tests the receive_atom method with multiple paths matching."""
        parser_count = ParserCount(
            self.aminer_config,
            ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
            [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.match_context_seq.match_data,
                           ParserMatch(self.match_element_seq), t,
                           parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/seq'] = 1
        old_count_dict['fixed/seq/m1'] = 1
        old_count_dict['fixed/seq/m2'] = 1
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test4do_timer(self):
        """This unittest checks if the do_timer method works properly."""
        parser_count = ParserCount(self.aminer_config, ['fixed/m3'],
                                   [self.stream_printer_event_handler], 600)
        t = time.time()
        self.assertEqual(int(parser_count.do_timer(t + 100)), 600)
        self.assertEqual(self.output_stream.getvalue(), "")
        log_atom = LogAtom(self.match_context_seq.match_data,
                           ParserMatch(self.match_element_seq), t,
                           parser_count)
        parser_count.receive_atom(log_atom)
        self.assertEqual(int(parser_count.do_timer(t + 100)), 500)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.assertEqual(parser_count.do_timer(t + 601), 600)
        self.assertNotEqual(self.output_stream.getvalue(), "")
        self.reset_output_stream()

    def test5reset_after_report_flag(self):
        """This unittest tests the functionality of the reset_after_report flag."""
        parser_count = ParserCount(
            self.aminer_config,
            ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
            [self.stream_printer_event_handler], 600, False)
        parser_count.count_dict['fixed/seq'] = 5
        parser_count.count_dict['fixed/seq/m1'] = 5
        parser_count.count_dict['fixed/seq/m2'] = 5
        parser_count.count_dict['fixed/m3'] = 17
        old_count_dict = dict(parser_count.count_dict)
        parser_count.send_report()
        self.assertEqual(parser_count.count_dict, old_count_dict)
        parser_count.reset_after_report_flag = True
        parser_count.send_report()
        old_count_dict['fixed/seq'] = 0
        old_count_dict['fixed/seq/m1'] = 0
        old_count_dict['fixed/seq/m2'] = 0
        old_count_dict['fixed/m3'] = 0
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test6receive_atom_without_target_paths(self):
        """This unittest tests the receive_atom method with multiple paths matching without having target_paths specified."""
        parser_count = ParserCount(self.aminer_config, None,
                                   [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.match_context_seq.match_data,
                           ParserMatch(self.match_element_seq), t,
                           parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/seq'] = 1
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)
Esempio n. 15
0
    def test1receive_match_in_time_with_auto_include_flag(self):
        """This test case checks if log_atoms are accepted as expected with the auto_include_flag=True."""
        description = 'test1newMatchIdValueComboDetectorTest'
        output_stream_empty_results = [True, False, True, False, True, False, True, True, True, True, True, True, True, True, False, False,
                                       False, True, False, True, False]
        id_dict_current_results = [
            {1: {'parser/type/syscall/syscall': 1}}, {}, {2: {'parser/type/syscall/syscall': 2}}, {},
            {3: {'parser/type/syscall/syscall': 3}}, {}, {100: {'parser/type/syscall/syscall': 1}},
            {100: {'parser/type/syscall/syscall': 1}, 4: {'parser/type/syscall/syscall': 1}}, {100: {'parser/type/syscall/syscall': 1}},
            {100: {'parser/type/syscall/syscall': 1}, 5: {'parser/type/path/name': 'two'}}, {100: {'parser/type/syscall/syscall': 1}},
            {100: {'parser/type/syscall/syscall': 1}, 6: {'parser/type/syscall/syscall': 4}},
            {100: {'parser/type/syscall/syscall': 1}, 6: {'parser/type/syscall/syscall': 4}, 7: {'parser/type/path/name': 'five'}},
            {100: {'parser/type/syscall/syscall': 1}, 6: {'parser/type/syscall/syscall': 4}, 7: {'parser/type/path/name': 'five'},
                8: {'parser/type/syscall/syscall': 6}},
            {100: {'parser/type/syscall/syscall': 1}, 7: {'parser/type/path/name': 'five'}, 8: {'parser/type/syscall/syscall': 6}},
            {100: {'parser/type/syscall/syscall': 1}, 8: {'parser/type/syscall/syscall': 6}}, {100: {'parser/type/syscall/syscall': 1}},
            {100: {'parser/type/syscall/syscall': 1}, 9: {'parser/type/syscall/syscall': 2}}, {100: {'parser/type/syscall/syscall': 1}},
            {100: {'parser/type/syscall/syscall': 1}, 10: {'parser/type/path/name': 'one'}}, {100: {'parser/type/syscall/syscall': 1}}]
        id_dict_old_results = [{}] * 21
        min_allowed_time_diff = 0.1
        log_atoms = []
        for line in self.log_lines:
            t = time.time()
            log_atoms.append(
                LogAtom(line, ParserMatch(self.parsing_model.get_match_element('parser', MatchContext(line))), t, self.__class__.__name__))
        new_match_id_value_combo_detector = NewMatchIdValueComboDetector(self.aminer_config, [
            'parser/type/path/name', 'parser/type/syscall/syscall'], [self.stream_printer_event_handler],
            id_path_list=['parser/type/path/id', 'parser/type/syscall/id'], min_allowed_time_diff=min_allowed_time_diff,
            auto_include_flag=True, allow_missing_values_flag=True, persistence_id='audit_type_path', output_log_line=False)
        self.analysis_context.register_component(new_match_id_value_combo_detector, description)

        for i, log_atom in enumerate(log_atoms):
            self.assertTrue(new_match_id_value_combo_detector.receive_atom(log_atom))
            self.assertEqual(self.output_stream.getvalue() == "", output_stream_empty_results[i], log_atom.raw_data)
            self.assertEqual(new_match_id_value_combo_detector.id_dict_current, id_dict_current_results[i])
            self.assertEqual(new_match_id_value_combo_detector.id_dict_old, id_dict_old_results[i])
            self.reset_output_stream()
Esempio n. 16
0
class NewMatchPathDetectorTest(TestBase):
    __expected_string = '%s New path(es) detected\n%s: "%s" (%d lines)\n  %s\n%s\n\n'
    match_path_s1 = "['/s1']"
    match_path_d1 = "['/d1']"

    datetime_format_string = '%Y-%m-%d %H:%M:%S'
    analysis = 'Analysis.%s'
    pid = "b' pid='"
    uid = "b' uid=2'"

    match_context_fixed_dme = MatchContext(b' pid=')
    fixed_dme = FixedDataModelElement('s1', b' pid=')
    match_element_fixed_dme = fixed_dme.get_match_element("", match_context_fixed_dme)

    match_context_decimal_integer_value_me = MatchContext(b'25537 uid=2')
    decimal_integer_value_me = DecimalIntegerValueModelElement('d1', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                                                               DecimalIntegerValueModelElement.PAD_TYPE_NONE)
    match_element_decimal_integer_value_me = decimal_integer_value_me.get_match_element("", match_context_decimal_integer_value_me)

    def test1_log_atom_not_known(self):
        """This test case checks the correct processing of unknown log lines, which in reality means that an anomaly has been found. The
        output is directed to an output stream and compared for accuracy. The auto_include_flag is False and the output must be repeatable
        on second run."""
        description = "Test1NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', False,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)
        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)
        log_atom_decimal_integer_value_me = LogAtom(self.match_context_decimal_integer_value_me.match_data,
                                                    ParserMatch(self.match_element_decimal_integer_value_me), t, new_match_path_detector)

        self.assertTrue(new_match_path_detector.receive_atom(log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_s1, self.pid))
        self.reset_output_stream()

        # repeating should produce the same result
        self.assertTrue(new_match_path_detector.receive_atom(log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_s1, self.pid))
        self.reset_output_stream()

        # other MatchElement
        self.assertTrue(new_match_path_detector.receive_atom(log_atom_decimal_integer_value_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_d1, self.uid))

    def test2_log_atom_known(self):
        """This test case checks the functionality of the autoIncludeFlag. If the same MatchElement is processed a second time and the
        auto_include_flag was True, no event must be triggered."""
        description = "Test2NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)

        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)
        log_atom_decimal_integer_value_me = LogAtom(self.match_context_decimal_integer_value_me.match_data,
                                                    ParserMatch(self.match_element_decimal_integer_value_me), t, new_match_path_detector)

        self.assertTrue(new_match_path_detector.receive_atom(log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_s1, self.pid))
        self.reset_output_stream()

        # repeating should NOT produce the same result
        self.assertTrue(new_match_path_detector.receive_atom(log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), '')
        self.reset_output_stream()

        # other MatchElement
        self.assertTrue(new_match_path_detector.receive_atom(log_atom_decimal_integer_value_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_d1, self.uid))

    def test3_log_atom_known_from_persisted_data(self):
        """The persisting and reading of permitted log lines should be checked with this test."""
        description = "Test3NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)
        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)

        self.assertTrue(new_match_path_detector.receive_atom(log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_detector.__class__.__name__, description, 1,
            self.match_path_s1, self.pid))
        new_match_path_detector.do_persist()
        self.reset_output_stream()

        otherNewMatchPathDetector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', False,
                                                         output_log_line=False)
        otherLogAtomFixedDME = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, otherNewMatchPathDetector)

        self.assertTrue(otherNewMatchPathDetector.receive_atom(otherLogAtomFixedDME))
        self.assertEqual(self.output_stream.getvalue(), '')

    def test4GetTimeTriggerClass(self):
        """The known paths are to be periodically stored after a certain time. This requires a synchronization class. The return of the
        correct class is to be checked in this test case."""
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.assertEqual(new_match_path_detector.get_time_trigger_class(), 1)

    """The following test cases should check if the doTimer() method is working properly.This includes the updating of nextPersistTime.
    As it is not updated directly in the method this test cases are not correct. Due to that they are commented."""
    # '''
    # During initialization, the next time is not determined (the value is initialized with None).
    # In this case, the persistence is expected to occur after 600 milliseconds.
    # '''
    # def test5_do_timer_next_persist_time_none(self):
    #   self.new_match_path_detector = NewMatchPathDetector(self.aminer_config,
    #     [self.stream_printer_event_handler], 'Default', True, output_log_line=False)
    #   self.assertEqual(self.new_match_path_detector.do_timer(200), 600)
    #   self.assertEqual(self.new_match_path_detector.do_timer(400), 600)
    #   self.assertEqual(self.new_match_path_detector.do_timer(10000), 600)
    #
    # '''
    # If the NextPersistTime is less than or equal to zero, the data must be saved.
    # '''
    # def test6_do_timer_delta_smaller_or_equal_zero(self):
    #   self.new_match_path_detector = NewMatchPathDetector(self.aminer_config,
    #     [self.stream_printer_event_handler], 'Default', True, output_log_line=False)
    #   self.new_match_path_detector.nextPersistTime = 400
    #   self.assertEqual(self.new_match_path_detector.do_timer(400), 600)
    #   self.assertEqual(self.new_match_path_detector.do_timer(1000), 600)
    #
    # '''
    # If the delta does not fall below the limit value, only the delta value should be returned.
    # '''
    # def test7_do_timer_delta_greater_zero(self):
    #   #this test fails due to the missing update of the nextPersistTime variable in the doTimer method
    #   self.new_match_path_detector = NewMatchPathDetector(self.aminer_config,
    #     [self.stream_printer_event_handler], 'Default', True, output_log_line=False)
    #   self.new_match_path_detector.nextPersistTime = 400
    #   self.assertEqual(self.new_match_path_detector.do_timer(200), 200)
    #   self.assertEqual(self.new_match_path_detector.do_timer(200), 600)
    #   self.assertEqual(self.new_match_path_detector.do_timer(100), 500)

    def test8_whitelist_event_type_exception(self):
        """This test case checks whether an exception is thrown when entering an event of another class."""
        description = "Test8NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)
        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)
        new_match_path_detector.receive_atom(log_atom_fixed_dme)
        new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [], [self.stream_printer_event_handler],
                                                                             'Default', True, True)
        self.assertRaises(
            Exception, new_match_path_detector.whitelist_event, self.analysis % new_match_path_value_combo_detector.__class__.__name__,
            log_atom_fixed_dme.raw_data, self.output_stream.getvalue(), None)

    def test9WhitelistEventWhitelistingDataException(self):
        """The NewMatchPathDetector can not handle whitelisting data and therefore an exception is expected."""
        description = "Test9NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)
        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)
        new_match_path_detector.receive_atom(log_atom_fixed_dme)
        self.assertRaises(Exception, new_match_path_detector.whitelist_event, self.analysis % new_match_path_detector.__class__.__name__,
                          log_atom_fixed_dme.raw_data, self.output_stream.getvalue(), ['random', 'Data'])

    def test10WhitelistEventWithKnownAndUnknownPaths(self):
        """This test case checks in which cases an event is triggered and compares with expected results."""
        description = "Test10NewMatchPathDetector"
        new_match_path_detector = NewMatchPathDetector(self.aminer_config, [self.stream_printer_event_handler], 'Default', True,
                                                       output_log_line=False)
        self.analysis_context.register_component(new_match_path_detector, description)
        t = round(time.time(), 3)
        log_atom_fixed_dme = LogAtom(self.fixed_dme.fixed_data, ParserMatch(self.match_element_fixed_dme), t, new_match_path_detector)
        new_match_path_detector.receive_atom(log_atom_fixed_dme)
        self.assertEqual(new_match_path_detector.whitelist_event(self.analysis % new_match_path_detector.__class__.__name__, [
            log_atom_fixed_dme, [self.match_element_fixed_dme.get_path()]],
            [log_atom_fixed_dme, [self.match_element_fixed_dme.get_path()]], None), 'Whitelisted path(es)  in %s' % log_atom_fixed_dme)

        log_atom_decimal_integer_value_me = LogAtom(self.match_context_decimal_integer_value_me.match_data,
                                                    ParserMatch(self.match_element_decimal_integer_value_me), t, new_match_path_detector)
        new_match_path_detector.auto_include_flag = False
        self.assertEqual(new_match_path_detector.whitelist_event(self.analysis % new_match_path_detector.__class__.__name__, [
            log_atom_decimal_integer_value_me, [self.match_element_decimal_integer_value_me.get_path()]],
            [log_atom_decimal_integer_value_me, [self.match_element_decimal_integer_value_me.get_path()]], None),
            'Whitelisted path(es) %s in %s' % (self.match_element_decimal_integer_value_me.path, log_atom_decimal_integer_value_me))
Esempio n. 17
0
class ParserCountTest(TestBase):
    """Unittests for the ParserCount."""

    match_context_m1 = MatchContext(b'First string')
    match_context_m2 = MatchContext(b' to match.')
    match_context_m3 = MatchContext(b'some completely other string to match.')
    match_context_seq = MatchContext(b'First string to match.')
    fixed_dme_m1 = FixedDataModelElement('m1', b'First string')
    fixed_dme_m2 = FixedDataModelElement('m2', b' to match.')
    seq = SequenceModelElement('seq', [fixed_dme_m1, fixed_dme_m2])
    fixed_dme_m3 = FixedDataModelElement('m3', b'some completely other string to match.')
    match_element_m1 = fixed_dme_m1.get_match_element('fixed', match_context_m1)
    match_element_m2 = fixed_dme_m2.get_match_element('fixed', match_context_m2)
    match_element_m3 = fixed_dme_m3.get_match_element('fixed', match_context_m3)
    match_element_seq = seq.get_match_element('fixed', match_context_seq)

    def test1log_atom_not_in_path_list(self):
        """This unittest checks if no action happens, when no path in the match_dictionary matches a target_path."""
        parser_count = ParserCount(self.aminer_config, ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2'], [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.fixed_dme_m3.fixed_data, ParserMatch(self.match_element_m3), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test2log_atom_matches_single_path(self):
        """This unittest tests the receive_atom method with a single path matching."""
        parser_count = ParserCount(self.aminer_config, ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
                                   [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.fixed_dme_m3.fixed_data, ParserMatch(self.match_element_m3), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/m3'][current_processed_lines_str] = 1
        old_count_dict['fixed/m3'][total_processed_lines_str] = 1
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test3log_atom_matches_multiple_paths(self):
        """This unittest tests the receive_atom method with multiple paths matching."""
        parser_count = ParserCount(self.aminer_config, ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
                                   [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.match_context_seq.match_data, ParserMatch(self.match_element_seq), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/seq'][current_processed_lines_str] = 1
        old_count_dict['fixed/seq'][total_processed_lines_str] = 1
        old_count_dict['fixed/seq/m1'][current_processed_lines_str] = 1
        old_count_dict['fixed/seq/m1'][total_processed_lines_str] = 1
        old_count_dict['fixed/seq/m2'][current_processed_lines_str] = 1
        old_count_dict['fixed/seq/m2'][total_processed_lines_str] = 1
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test4do_timer(self):
        """This unittest checks if the do_timer method works properly."""
        parser_count = ParserCount(self.aminer_config, ['fixed/m3'], [self.stream_printer_event_handler], 600)
        t = time.time()
        self.assertEqual(int(parser_count.do_timer(t + 100)), 600)
        self.assertEqual(self.output_stream.getvalue(), "")
        log_atom = LogAtom(self.match_context_seq.match_data, ParserMatch(self.match_element_seq), t, parser_count)
        parser_count.receive_atom(log_atom)
        self.assertEqual(int(parser_count.do_timer(t + 100)), 500)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.assertEqual(parser_count.do_timer(t + 601), 600)
        self.assertNotEqual(self.output_stream.getvalue(), "")
        self.reset_output_stream()

    def test5resetting(self):
        """This unittest tests the functionality of resetting the counts."""
        parser_count = ParserCount(self.aminer_config, ['fixed/seq', 'fixed/seq/m1', 'fixed/seq/m2', 'fixed/m3'],
                                   [self.stream_printer_event_handler], 600)
        parser_count.count_dict['fixed/seq'][current_processed_lines_str] = 5
        parser_count.count_dict['fixed/seq'][total_processed_lines_str] = 5
        parser_count.count_dict['fixed/seq/m1'][current_processed_lines_str] = 5
        parser_count.count_dict['fixed/seq/m1'][total_processed_lines_str] = 5
        parser_count.count_dict['fixed/seq/m2'][current_processed_lines_str] = 5
        parser_count.count_dict['fixed/seq/m2'][total_processed_lines_str] = 5
        parser_count.count_dict['fixed/m3'][current_processed_lines_str] = 17
        parser_count.count_dict['fixed/m3'][total_processed_lines_str] = 17
        old_count_dict = dict(parser_count.count_dict)
        parser_count.send_report()
        self.assertEqual(parser_count.count_dict, old_count_dict)
        parser_count.send_report()
        old_count_dict['fixed/seq'][current_processed_lines_str] = 0
        old_count_dict['fixed/seq/m1'][current_processed_lines_str] = 0
        old_count_dict['fixed/seq/m2'][current_processed_lines_str] = 0
        old_count_dict['fixed/m3'][current_processed_lines_str] = 0
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test6receive_atom_without_target_paths(self):
        """This unittest tests the receive_atom method with multiple paths matching without having target_paths specified."""
        parser_count = ParserCount(self.aminer_config, None, [self.stream_printer_event_handler])
        t = time.time()
        log_atom = LogAtom(self.match_context_seq.match_data, ParserMatch(self.match_element_seq), t, parser_count)
        old_count_dict = dict(parser_count.count_dict)
        old_count_dict['fixed/seq'] = {current_processed_lines_str: 1, total_processed_lines_str: 1}
        parser_count.receive_atom(log_atom)
        self.assertEqual(parser_count.count_dict, old_count_dict)

    def test7initialize_errored_target_label_list(self):
        """Initialize the ParserCount class with errored target_label_list parameters and check if an error is raised."""
        self.assertRaises(ValueError, ParserCount, self.aminer_config, None, [self.stream_printer_event_handler], target_label_list=['p'])
        self.assertRaises(ValueError, ParserCount, self.aminer_config, ['path1', 'path2'], [self.stream_printer_event_handler],
                          target_label_list=['p'])
        self.assertRaises(ValueError, ParserCount, self.aminer_config, ['path1'], [self.stream_printer_event_handler],
                          target_label_list=['p1', 'p2'])
        ParserCount(self.aminer_config, ['path'], [self.stream_printer_event_handler], target_label_list=['p'])
    def run_time_correlation_violation_detector(self, chance):
        results = [None] * self.iterations
        avg = 0
        z = 0
        while z < self.iterations:
            correlation_rule = CorrelationRule('Correlation',
                                               0,
                                               chance,
                                               max_artefacts_a_for_single_b=1,
                                               artefact_match_parameters=[
                                                   ('/integer/d0',
                                                    '/integer/d1')
                                               ])
            a_class_selector = EventClassSelector('Selector1',
                                                  [correlation_rule], None)
            b_class_selector = EventClassSelector('Selector2', None,
                                                  [correlation_rule])
            rules = [
                Rules.PathExistsMatchRule('/integer/d0', a_class_selector),
                Rules.PathExistsMatchRule('/integer/d1', b_class_selector)
            ]

            time_correlation_violation_detector = TimeCorrelationViolationDetector(
                self.analysis_context.aminer_config, rules,
                [self.stream_printer_event_handler])
            seconds = time.time()
            s = seconds
            i = 0
            decimal_integer_value_me = DecimalIntegerValueModelElement(
                'd0', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                DecimalIntegerValueModelElement.PAD_TYPE_NONE)
            while int(time.time() - seconds) < self.waiting_time:
                integer = '/integer'
                p = process_time()
                r = random.randint(1, 100)
                seconds = seconds + process_time() - p
                decimal_integer_value_me1 = DecimalIntegerValueModelElement(
                    'd1', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                    DecimalIntegerValueModelElement.PAD_TYPE_NONE)
                match_context = MatchContext(str(i).encode())
                match_element = decimal_integer_value_me.get_match_element(
                    integer, match_context)
                log_atom = LogAtom(match_element.match_string,
                                   ParserMatch(match_element), s,
                                   time_correlation_violation_detector)
                time_correlation_violation_detector.receive_atom(log_atom)

                match_context = MatchContext(str(i).encode())
                match_element = decimal_integer_value_me1.get_match_element(
                    integer, match_context)
                log_atom = LogAtom(match_element.match_string,
                                   ParserMatch(match_element), s + r / 100,
                                   time_correlation_violation_detector)
                time_correlation_violation_detector.receive_atom(log_atom)
                s = s + r / 100

                if r / 100 >= chance:
                    p = process_time()
                    match_context = MatchContext(str(i).encode())
                    match_element = decimal_integer_value_me.get_match_element(
                        integer, match_context)
                    log_atom = LogAtom(match_element.match_string,
                                       ParserMatch(match_element), s,
                                       time_correlation_violation_detector)
                    time_correlation_violation_detector.receive_atom(log_atom)
                    seconds = seconds + process_time() - p
                time_correlation_violation_detector.do_timer(s)
                i = i + 1
            results[z] = i
            z = z + 1
            avg = avg + i
        avg = avg / self.iterations
        type(self).result = self.result + self.result_string % (
            time_correlation_violation_detector.__class__.__name__, avg,
            results, '%d%% chance of not finding an element' %
            ((1 - chance) * 100))
Esempio n. 19
0
class KafkaEventHandlerTest(TestBase):
    output_log_line = True
    kafka_topic = 'test_topic'
    kafka_group = 'test_group'
    consumer = None
    match_context = MatchContext(b' pid=')
    fixed_dme = FixedDataModelElement('s1', b' pid=')
    other_data = 4
    match_element = fixed_dme.get_match_element("match", match_context)
    description = 'jsonConverterHandlerDescription'
    t = time.time()
    persistence_id = 'Default'
    test_detector = 'Analysis.TestDetector'
    event_message = 'An event happened!'
    sorted_log_lines = ['Event happend at /path/ 5 times.', '', '', '', '']
    expected_string = '%s %s\n%s: "%s" (5 lines)\n  {\n  "AnalysisComponent": {\n    "AnalysisComponentIdentifier": 0,\n' \
                      '    "AnalysisComponentType": "%s",\n    "AnalysisComponentName": "%s",\n    "Message": "%s",\n' \
                      '    "PersistenceFileName": "%s",\n    "AffectedParserPaths": [\n      "test/path/1",\n' \
                      '      "test/path/2"\n    ]\n  },\n  "LogData": {\n    "RawLogData": [\n      " pid="\n    ],\n    ' \
                      '"Timestamps": [\n      %s\n    ],\n    "LogLinesCount": 5,\n' \
                      '    "AnnotatedMatchElement": "match/s1: b\' pid=\'"\n  }%s\n}\n\n'

    @classmethod
    def setUpClass(cls):
        cls.consumer = KafkaConsumer(cls.kafka_topic,
                                     bootstrap_servers=['localhost:9092'],
                                     enable_auto_commit=True,
                                     consumer_timeout_ms=10000,
                                     group_id=cls.kafka_group,
                                     value_deserializer=lambda x: x.decode(),
                                     api_version=(2, 0, 1),
                                     auto_offset_reset='earliest')

    @classmethod
    def tearDownClass(cls):
        cls.consumer.close()

    def test1receive_serialized_data(self):
        """This unittest tests the receive_event method with serialized data from the JsonConverterHandler."""
        json_converter_handler = JsonConverterHandler(
            [self.stream_printer_event_handler], self.analysis_context)
        log_atom = LogAtom(self.fixed_dme.fixed_data,
                           ParserMatch(self.match_element), self.t, self)
        self.analysis_context.register_component(self, self.description)
        event_data = {
            'AnalysisComponent': {
                'AffectedParserPaths': ['test/path/1', 'test/path/2']
            }
        }
        json_converter_handler.receive_event(self.test_detector,
                                             self.event_message,
                                             self.sorted_log_lines, event_data,
                                             log_atom, self)
        output = self.output_stream.getvalue()
        kafka_event_handler = KafkaEventHandler(
            self.analysis_context, self.kafka_topic, {
                'bootstrap_servers': ['localhost:9092'],
                'api_version': (2, 0, 1)
            })
        self.assertTrue(
            kafka_event_handler.receive_event(self.test_detector,
                                              self.event_message,
                                              self.sorted_log_lines, output,
                                              log_atom, self))

        self.assertEqual(
            self.consumer.__next__().value, self.expected_string %
            (datetime.fromtimestamp(self.t).strftime("%Y-%m-%d %H:%M:%S"),
             self.event_message, self.__class__.__name__, self.description,
             self.__class__.__name__, self.description, self.event_message,
             self.persistence_id, round(self.t, 2), ""))

    def test2receive_non_serialized_data(self):
        """This unittest tests the receive_event method with not serialized data"""
        log_atom = LogAtom(self.fixed_dme.fixed_data,
                           ParserMatch(self.match_element), self.t, self)
        self.analysis_context.register_component(self, self.description)
        event_data = {
            'AnalysisComponent': {
                'AffectedParserPaths': ['test/path/1', 'test/path/2']
            }
        }
        kafka_event_handler = KafkaEventHandler(
            self.analysis_context, self.kafka_topic, {
                'bootstrap_servers': ['localhost:9092'],
                'api_version': (2, 0, 1)
            })
        self.assertFalse(
            kafka_event_handler.receive_event(self.test_detector,
                                              self.event_message,
                                              self.sorted_log_lines,
                                              event_data, log_atom, self))
        self.assertRaises(StopIteration, self.consumer.__next__)
    def run_new_match_id_value_combo_detector(self, min_allowed_time_diff):
        log_lines = [
            b'type=SYSCALL msg=audit(1580367384.000:1): arch=c000003e syscall=1 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367385.000:1): item=0 name="one" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 '
            b'rdev=00:00 nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367386.000:2): arch=c000003e syscall=2 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367387.000:2): item=0 name="two" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367388.000:3): arch=c000003e syscall=3 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367389.000:3): item=0 name="three" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00'
            b' nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367388.500:100): arch=c000003e syscall=1 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=SYSCALL msg=audit(1580367390.000:4): arch=c000003e syscall=1 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367391.000:4): item=0 name="one" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=PATH msg=audit(1580367392.000:5): item=0 name="two" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367393.000:5): arch=c000003e syscall=2 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=SYSCALL msg=audit(1580367394.000:6): arch=c000003e syscall=4 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367395.000:7): item=0 name="five" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367396.000:8): arch=c000003e syscall=6 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367397.000:6): item=0 name="four" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367398.000:7): arch=c000003e syscall=5 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367399.000:8): item=0 name="six" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 rdev=00:00 '
            b'nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367400.000:9): arch=c000003e syscall=2 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 a3=4f '
            b'items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) '
            b'ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)',
            b'type=PATH msg=audit(1580367401.000:9): item=0 name="three" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 '
            b'rdev=00:00 nametype=NORMAL',
            b'type=PATH msg=audit(1580367402.000:10): item=0 name="one" inode=790106 dev=fe:01 mode=0100666 ouid=1000 ogid=1000 '
            b'rdev=00:00 nametype=NORMAL',
            b'type=SYSCALL msg=audit(1580367403.000:10): arch=c000003e syscall=3 success=yes exit=21 a0=7ffda5863060 a1=0 a2=1b6 '
            b'a3=4f items=1 ppid=22913 pid=13187 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 '
            b'tty=(none) ses=4294967295 comm="apache2" exe="/usr/sbin/apache2" key=(null)'
        ]
        parsing_model = FirstMatchModelElement('type', [
            SequenceModelElement('path', [
                FixedDataModelElement('type', b'type=PATH '),
                FixedDataModelElement('msg_audit', b'msg=audit('),
                DelimitedDataModelElement('msg', b':'),
                FixedDataModelElement('placeholder', b':'),
                DecimalIntegerValueModelElement('id'),
                FixedDataModelElement('item_string', b'): item='),
                DecimalIntegerValueModelElement('item'),
                FixedDataModelElement('name_string', b' name="'),
                DelimitedDataModelElement('name', b'"'),
                FixedDataModelElement('inode_string', b'" inode='),
                DecimalIntegerValueModelElement('inode'),
                FixedDataModelElement('dev_string', b' dev='),
                DelimitedDataModelElement('dev', b' '),
                FixedDataModelElement('mode_string', b' mode='),
                DecimalIntegerValueModelElement('mode'),
                FixedDataModelElement('ouid_string', b' ouid='),
                DecimalIntegerValueModelElement('ouid'),
                FixedDataModelElement('ogid_string', b' ogid='),
                DecimalIntegerValueModelElement('ogid'),
                FixedDataModelElement('rdev_string', b' rdev='),
                DelimitedDataModelElement('rdev', b' '),
                FixedDataModelElement('nametype_string', b' nametype='),
                FixedWordlistDataModelElement('nametype',
                                              [b'NORMAL', b'ERROR'])
            ]),
            SequenceModelElement('syscall', [
                FixedDataModelElement('type', b'type=SYSCALL '),
                FixedDataModelElement('msg_audit', b'msg=audit('),
                DelimitedDataModelElement('msg', b':'),
                FixedDataModelElement('placeholder', b':'),
                DecimalIntegerValueModelElement('id'),
                FixedDataModelElement('arch_string', b'): arch='),
                DelimitedDataModelElement('arch', b' '),
                FixedDataModelElement('syscall_string', b' syscall='),
                DecimalIntegerValueModelElement('syscall'),
                FixedDataModelElement('success_string', b' success='),
                FixedWordlistDataModelElement('success', [b'yes', b'no']),
                FixedDataModelElement('exit_string', b' exit='),
                DecimalIntegerValueModelElement('exit'),
                AnyByteDataModelElement('remainding_data')
            ])
        ])

        results = [None] * self.iterations
        avg = 0
        z = 0
        while z < self.iterations:
            i = 0
            new_match_id_value_combo_detector = NewMatchIdValueComboDetector(
                self.aminer_config,
                ['parser/type/path/name', 'parser/type/syscall/syscall'],
                [self.stream_printer_event_handler],
                id_path_list=['parser/type/path/id', 'parser/type/syscall/id'],
                min_allowed_time_diff=min_allowed_time_diff,
                auto_include_flag=False,
                allow_missing_values_flag=True,
                persistence_id='audit_type_path',
                output_log_line=False)
            t = time.time()
            seconds = time.time()
            i = 0
            while int(time.time() - seconds) < self.waiting_time:
                p = process_time()
                r = random.randint(0, len(log_lines) - 1)
                seconds = seconds + process_time() - p

                # this code just creates some data to be able to compare with other analysis components.
                decimal_integer_value_me = DecimalIntegerValueModelElement(
                    'd', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                    DecimalIntegerValueModelElement.PAD_TYPE_NONE)
                match_context = MatchContext(str(i % 100).encode())
                _match_element = decimal_integer_value_me.get_match_element(
                    'integer', match_context)
                ########################################################################################

                line = log_lines[r]
                log_atom = LogAtom(
                    line,
                    ParserMatch(
                        parsing_model.get_match_element(
                            'parser', MatchContext(line))), t,
                    self.__class__.__name__)
                new_match_id_value_combo_detector.receive_atom(log_atom)
                i = i + 1
            results[z] = i
            z = z + 1
            avg = avg + i
        avg = avg / self.iterations
        type(self).result = self.result + self.result_string % (
            new_match_id_value_combo_detector.__class__.__name__, avg, results,
            '%.2f seconds min_allowed_time_diff.' % min_allowed_time_diff)
class JsonConverterHandlerTest(TestBase):
    """Unittests for the JsonConverterHandler."""

    output_log_line = True
    match_context = MatchContext(b' pid=')
    fixed_dme = FixedDataModelElement('s1', b' pid=')
    match_element = fixed_dme.get_match_element("match", match_context)
    t = time.time()

    test_detector = 'Analysis.TestDetector'
    event_message = 'An event happened!'
    sorted_log_lines = ['Event happend at /path/ 5 times.', '', '', '', '']
    persistence_id = 'Default'
    description = 'jsonConverterHandlerDescription'
    expected_string = '%s %s\n%s: "%s" (5 lines)\n  {\n  "AnalysisComponent": {\n    "AnalysisComponentIdentifier": 0,\n' \
                      '    "AnalysisComponentType": "%s",\n    "AnalysisComponentName": "%s",\n    "Message": "%s",\n' \
                      '    "PersistenceFileName": "%s",\n    "AffectedParserPaths": [\n      "test/path/1",\n' \
                      '      "test/path/2"\n    ]\n  },\n  "LogData": {\n    "RawLogData": [\n      " pid="\n    ],\n    ' \
                      '"Timestamps": [\n      %s\n    ],\n    "LogLinesCount": 5,\n' \
                      '    "AnnotatedMatchElement": "match/s1: b\' pid=\'"\n  }%s\n}\n\n'

    def test1receive_expected_event(self):
        """In this test case a normal Event happens and the json output should be sent to a StreamPrinterEventHandler."""
        json_converter_handler = JsonConverterHandler(
            [self.stream_printer_event_handler], self.analysis_context)
        log_atom = LogAtom(self.fixed_dme.fixed_data,
                           ParserMatch(self.match_element), self.t, self)
        self.analysis_context.register_component(self, self.description)
        event_data = {
            'AnalysisComponent': {
                'AffectedParserPaths': ['test/path/1', 'test/path/2']
            }
        }
        json_converter_handler.receive_event(self.test_detector,
                                             self.event_message,
                                             self.sorted_log_lines, event_data,
                                             log_atom, self)
        self.assertEqual(
            self.output_stream.getvalue(), self.expected_string %
            (datetime.fromtimestamp(self.t).strftime("%Y-%m-%d %H:%M:%S"),
             self.event_message, self.__class__.__name__, self.description,
             self.__class__.__name__, self.description, self.event_message,
             self.persistence_id, round(self.t, 2), ""))

    def test2receive_event_with_same_event_data_attributes(self):
        """In this test case an attribute of AnalysisComponent is overwritten and an JsonError attribute is expected."""
        json_converter_handler = JsonConverterHandler(
            [self.stream_printer_event_handler], self.analysis_context)
        log_atom = LogAtom(self.fixed_dme.fixed_data,
                           ParserMatch(self.match_element), self.t, self)
        self.analysis_context.register_component(self, self.description)
        event_data = {
            'AnalysisComponent': {
                'AffectedParserPaths': ['test/path/1', 'test/path/2'],
                'Message': 'An other event happened too!'
            }
        }
        json_converter_handler.receive_event(self.test_detector,
                                             self.event_message,
                                             self.sorted_log_lines, event_data,
                                             log_atom, self)
        self.assertEqual(
            self.output_stream.getvalue(), self.expected_string %
            (datetime.fromtimestamp(self.t).strftime("%Y-%m-%d %H:%M:%S"),
             self.event_message, self.__class__.__name__, self.description,
             self.__class__.__name__, self.description, self.event_message,
             self.persistence_id, round(float("%.2f" % self.t), 2),
             ',\n  "JsonError": "AnalysisComponent attribute \'Message\' is already in use and can not be overwritten!\\n"'
             ))
class NewMatchPathValueComboDetectorTest(TestBase):
    """Unittests for the NewMatchPathValueComboDetector."""

    __expected_string = '%s New value combination(s) detected\n%s: "%s" (%d lines)\n%s\n\n'
    fixed_dme = FixedDataModelElement('s1', b'25537 uid=')
    fixed_dme2 = FixedDataModelElement('s2', b' uid=2')
    datetime_format_string = '%Y-%m-%d %H:%M:%S'
    first_seq_s1 = 'first/seq/s1'
    first_seq_d1 = 'first/seq/d1'
    string = "  first/seq: b'25537 uid=2'\n  " + first_seq_s1 + ": b'25537 uid='\n  " + first_seq_d1 + ": 2\n(b'25537 uid=', 2)"
    string2 = "  (b'25537 uid=', 2)\nb'25537 uid=2'"

    decimal_integer_value_me = DecimalIntegerValueModelElement('d1', DecimalIntegerValueModelElement.SIGN_TYPE_NONE,
                                                               DecimalIntegerValueModelElement.PAD_TYPE_NONE)

    match_context_sequence_me = MatchContext(b'25537 uid=2')
    seq = SequenceModelElement('seq', [fixed_dme, decimal_integer_value_me])
    match_element_sequence_me = seq.get_match_element('first', match_context_sequence_me)

    match_context_sequence_me2 = MatchContext(b'25537 uid=2')
    seq2 = SequenceModelElement('seq2', [decimal_integer_value_me, fixed_dme2])
    match_element_sequence_me2 = seq2.get_match_element('second', match_context_sequence_me2)

    def test1_log_atom_not_known(self):
        """
        This test case checks the correct processing of unknown log lines, which in reality means that an anomaly has been found.
        The output is directed to an output stream and compared for accuracy. The auto_include_flag is False and the output must be
        repeatable on second run.
        """
        description = "Test1NewMatchPathValueComboDetector"
        new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [self.first_seq_s1, self.first_seq_d1], [
            self.stream_printer_event_handler], 'Default', False, False, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector, description)

        t = time.time()
        log_atom_sequence_me = LogAtom(self.match_element_sequence_me.get_match_string(), ParserMatch(self.match_element_sequence_me), t,
                                       new_match_path_value_combo_detector)

        self.assertTrue(new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description, 1, self.string2))
        self.reset_output_stream()

        # repeating should produce the same result
        self.assertTrue(new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description, 1, self.string2))
        self.reset_output_stream()

        new_match_path_value_combo_detector2 = NewMatchPathValueComboDetector(self.aminer_config, ['second/seq2/d1', 'second/seq2/s2'], [
            self.stream_printer_event_handler], 'Default', False, False, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector2, description + "2")

        log_atom_sequence_me2 = LogAtom(self.match_element_sequence_me2.get_match_string(), ParserMatch(self.match_element_sequence_me2), t,
                                        new_match_path_value_combo_detector2)

        # other MatchElement
        self.assertTrue(new_match_path_value_combo_detector2.receive_atom(log_atom_sequence_me2))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description + "2", 1, "  (25537, b' uid=2')\nb'25537 uid=2'"))

    def test2_log_atom_known(self):
        """
        This test case checks the functionality of the auto_include_flag.
        If the same MatchElement is processed a second time and the auto_include_flag was True, no event must be triggered.
        """
        description = "Test2NewMatchPathValueComboDetector"
        new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [self.first_seq_s1, self.first_seq_d1], [
            self.stream_printer_event_handler], 'Default', False, True, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector, description)

        t = time.time()
        log_atom_sequence_me = LogAtom(self.match_element_sequence_me.get_match_string(), ParserMatch(self.match_element_sequence_me), t,
                                       new_match_path_value_combo_detector)

        self.assertTrue(new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description, 1, self.string2))
        self.reset_output_stream()

        # repeating should NOT produce the same result
        self.assertTrue(new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), '')
        self.reset_output_stream()

        new_match_path_value_combo_detector2 = NewMatchPathValueComboDetector(self.aminer_config, ['second/seq2/d1', 'second/seq2/s2'], [
            self.stream_printer_event_handler], 'Default', False, False, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector2, description + "2")

        log_atom_sequence_me2 = LogAtom(self.match_element_sequence_me2.get_match_string(), ParserMatch(self.match_element_sequence_me2), t,
                                        new_match_path_value_combo_detector2)

        # other MatchElement
        self.assertTrue(new_match_path_value_combo_detector2.receive_atom(log_atom_sequence_me2))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description + "2", 1, "  (25537, b' uid=2')\nb'25537 uid=2'"))

    def test3_log_atom_known_from_persisted_data(self):
        """The persisting and reading of permitted log lines should be checked with this test."""
        description = "Test3NewMatchPathValueComboDetector"
        new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [self.first_seq_s1, self.first_seq_d1], [
            self.stream_printer_event_handler], 'Default', False, True, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector, description)

        t = time.time()
        log_atom_sequence_me = LogAtom(self.match_element_sequence_me.get_match_string(), ParserMatch(self.match_element_sequence_me), t,
                                       new_match_path_value_combo_detector)

        self.assertTrue(new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me))
        self.assertEqual(self.output_stream.getvalue(), self.__expected_string % (
            datetime.fromtimestamp(t).strftime(self.datetime_format_string), new_match_path_value_combo_detector.__class__.__name__,
            description, 1, self.string2))
        new_match_path_value_combo_detector.do_persist()
        self.reset_output_stream()

        other_new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [
            self.first_seq_s1, self.first_seq_d1], [self.stream_printer_event_handler], 'Default', False, True, output_log_line=False)
        self.analysis_context.register_component(other_new_match_path_value_combo_detector, description + "2")
        other_log_atom_fixed_dme = LogAtom(self.match_element_sequence_me.get_match_string(), ParserMatch(self.match_element_sequence_me),
                                           t, other_new_match_path_value_combo_detector)

        self.assertTrue(other_new_match_path_value_combo_detector.receive_atom(other_log_atom_fixed_dme))
        self.assertEqual(self.output_stream.getvalue(), '')

    def test4_allowlist_event_with_known_and_unknown_paths(self):
        """This test case checks in which cases an event is triggered and compares with expected results."""
        description = "Test4NewMatchPathValueComboDetector"
        new_match_path_value_combo_detector = NewMatchPathValueComboDetector(self.aminer_config, [self.first_seq_s1, self.first_seq_d1], [
            self.stream_printer_event_handler], 'Default', False, True, output_log_line=False)
        self.analysis_context.register_component(new_match_path_value_combo_detector, description)

        t = time.time()
        log_atom_sequence_me = LogAtom(self.match_element_sequence_me.get_match_string(), ParserMatch(self.match_element_sequence_me), t,
                                       new_match_path_value_combo_detector)
        new_match_path_value_combo_detector.receive_atom(log_atom_sequence_me)
        self.assertEqual(
            new_match_path_value_combo_detector.allowlist_event(
                'Analysis.%s' % new_match_path_value_combo_detector.__class__.__name__,
                self.match_element_sequence_me.get_path(), None), 'Allowlisted path(es) %s with %s.' % (
                ", ".join(new_match_path_value_combo_detector.target_path_list), self.match_element_sequence_me.get_path()))

        new_match_path_value_combo_detector.auto_include_flag = False
        self.assertEqual(
            new_match_path_value_combo_detector.allowlist_event(
                'Analysis.%s' % new_match_path_value_combo_detector.__class__.__name__, self.match_element_sequence_me2.get_path(),
                None), 'Allowlisted path(es) %s with %s.' % (
                ", ".join(new_match_path_value_combo_detector.target_path_list), self.match_element_sequence_me2.path))