Exemple #1
0
    def test_load_hunts(self):
        hunter = HuntManager(**manager_kwargs())
        hunter.load_hunts_from_config()
        self.assertEquals(len(hunter.hunts), 2)
        self.assertTrue(isinstance(hunter.hunts[0], TestHunt))
        self.assertTrue(isinstance(hunter.hunts[1], TestHunt))

        for hunt in hunter.hunts:
            hunt.last_executed_time = datetime.datetime.now()

        self.assertTrue(hunter.hunts[1].enabled)
        self.assertEquals(hunter.hunts[1].name, 'unit_test_1')
        self.assertEquals(hunter.hunts[1].description,
                          'Unit Test Description 1')
        self.assertEquals(hunter.hunts[1].type, 'test')
        self.assertTrue(
            isinstance(hunter.hunts[1].frequency, datetime.timedelta))
        self.assertEquals(hunter.hunts[1].tags, ['tag1', 'tag2'])

        self.assertTrue(hunter.hunts[0].enabled)
        self.assertEquals(hunter.hunts[0].name, 'unit_test_2')
        self.assertEquals(hunter.hunts[0].description,
                          'Unit Test Description 2')
        self.assertEquals(hunter.hunts[0].type, 'test')
        self.assertTrue(
            isinstance(hunter.hunts[0].frequency, datetime.timedelta))
        self.assertEquals(hunter.hunts[0].tags, ['tag1', 'tag2'])
Exemple #2
0
 def test_load_hunt_ini(self):
     manager = HuntManager(**manager_kwargs())
     manager.load_hunts_from_config()
     self.assertEquals(len(manager.hunts), 1)
     hunt = manager.hunts[0]
     self.assertTrue(hunt.enabled)
     self.assertEquals(hunt.name, 'query_test_1')
     self.assertEquals(hunt.description, 'Query Test Description 1')
     self.assertEquals(hunt.type, 'test_query')
     self.assertEquals(hunt.frequency, create_timedelta('00:01:00'))
     self.assertEquals(hunt.tags, ['tag1', 'tag2'])
     self.assertEquals(hunt.time_range, create_timedelta('00:01:00'))
     self.assertEquals(hunt.max_time_range, create_timedelta('01:00:00'))
     self.assertEquals(hunt.offset, create_timedelta('00:05:00'))
     self.assertTrue(hunt.full_coverage)
     self.assertEquals(hunt.group_by, 'field1')
     self.assertEquals(hunt.query, 'Test query.')
     self.assertTrue(hunt.use_index_time)
     self.assertEquals(hunt.observable_mapping, {
         'src_ip': 'ipv4',
         'dst_ip': 'ipv4'
     })
     self.assertEquals(hunt.temporal_fields, {
         'src_ip': True,
         'dst_ip': True
     })
Exemple #3
0
    def test_full_coverage(self):
        manager = HuntManager(**manager_kwargs())
        hunt = default_hunt(time_range=create_timedelta('01:00:00'),
                            frequency=create_timedelta('01:00:00'))
        manager.add_hunt(hunt)

        # first test that the start time and end time are correct for normal operation
        # for first-time hunt execution
        self.assertTrue(hunt.ready)

        # now put the last time we executed to 5 minutes ago
        # ready should return False
        hunt.last_executed_time = local_time() - datetime.timedelta(minutes=5)
        self.assertFalse(hunt.ready)

        # now put the last time we executed to 65 minutes ago
        # ready should return True
        hunt.last_executed_time = local_time() - datetime.timedelta(minutes=65)
        self.assertTrue(hunt.ready)

        # set the last time we executed to 3 hours ago
        hunt.last_executed_time = local_time() - datetime.timedelta(hours=3)
        # and the last end date to 2 hours ago
        hunt.last_end_time = local_time() - datetime.timedelta(hours=2)
        # so now we have 2 hours to cover under full coverage
        # ready should return True, start should be 3 hours ago and end should be 2 hours ago
        self.assertTrue(hunt.ready)
        self.assertEquals(hunt.start_time, hunt.last_end_time)
        self.assertEquals(hunt.end_time, hunt.last_end_time + hunt.time_range)
        #logging.info(f"MARKER: start {hunt.start_time} end {hunt.end_time} comp {hunt.end_time - hunt.start_time} >= {hunt.time_range}")

        # now let's pretend that we just executed that
        # at this point, the last_end_time becomes the end_time
        hunt.last_end_time = hunt.end_time
        # and the last_executed_time becomes now
        hunt.last_executed_time = local_time()
        # at this point the hunt should still be ready because we're not caught up yet
        self.assertTrue(hunt.ready)

        # now give the hunt the ability to cover 2 hours instead of 1 to get caught up
        hunt.max_time_range = create_timedelta('02:00:00')
        # set the last time we executed to 3 hours ago
        hunt.last_executed_time = local_time() - datetime.timedelta(hours=3)
        # and the last end date to 2 hours ago
        hunt.last_end_time = local_time() - datetime.timedelta(hours=2)
        # now the difference between the stop and stop should be 2 hours instead of one
        #logging.info(f"MARKER: start {hunt.start_time} end {hunt.end_time} comp {hunt.end_time - hunt.start_time} >= {hunt.time_range}")
        self.assertTrue(hunt.end_time - hunt.start_time >= hunt.max_time_range)

        # set the last time we executed to 3 hours ago
        hunt.last_executed_time = local_time() - datetime.timedelta(hours=3)
        # and the last end date to 2 hours ago
        hunt.last_end_time = local_time() - datetime.timedelta(hours=2)
        # so now we have 2 hours to cover but let's turn off full coverage
        hunt.full_coverage = False
        # it should be ready to run
        self.assertTrue(hunt.ready)
    def test_load_hunt_with_includes(self):
        ips_txt = 'hunts/test/splunk/ips.txt'
        with open(ips_txt, 'w') as fp:
            fp.write('1.1.1.1\n')

        manager = HuntManager(**manager_kwargs())
        manager.load_hunts_from_config(hunt_filter=lambda hunt: hunt.name == 'query_test_includes')
        hunt = manager.get_hunt_by_name('query_test_includes')
        self.assertIsNotNone(hunt)
        # same as above except that ip address comes from a different file
        self.assertEquals(hunt.query, 'index=proxy {time_spec} src_ip=1.1.1.1\n')

        # and then change it and it should have a different value 
        with open(ips_txt, 'a') as fp:
            fp.write('1.1.1.2\n')

        self.assertEquals(hunt.query, 'index=proxy {time_spec} src_ip=1.1.1.1\n1.1.1.2\n')

        os.remove(ips_txt)
Exemple #5
0
    def test_offset(self):
        manager = HuntManager(**manager_kwargs())
        hunt = default_hunt(time_range=create_timedelta('01:00:00'),
                            frequency=create_timedelta('01:00:00'),
                            offset=create_timedelta('00:30:00'))
        manager.add_hunt(hunt)

        # set the last time we executed to 3 hours ago
        hunt.last_executed_time = local_time() - datetime.timedelta(hours=3)
        # and the last end date to 2 hours ago
        target_start_time = hunt.last_end_time = local_time(
        ) - datetime.timedelta(hours=2)
        self.assertTrue(hunt.ready)
        hunt.execute()

        # the times passed to hunt.execute_query should be 30 minutes offset
        self.assertEquals(target_start_time - hunt.offset,
                          hunt.exec_start_time)
        self.assertEquals(hunt.last_end_time - hunt.offset, hunt.exec_end_time)
Exemple #6
0
    def test_hunt_persistence(self):
        hunter = HuntManager(**manager_kwargs())
        hunter.add_hunt(default_hunt())
        hunter.hunts[0].last_executed_time = datetime.datetime(
            2019, 12, 10, 8, 21, 13)

        with open_hunt_db(hunter.hunts[0].type) as db:
            c = db.cursor()
            c.execute(
                """SELECT last_executed_time FROM hunt WHERE hunt_name = ?""",
                (hunter.hunts[0].name, ))
            row = c.fetchone()
            self.assertIsNotNone(row)
            last_executed_time = row[0]
            self.assertTrue(isinstance(last_executed_time, datetime.datetime))
            self.assertEquals(last_executed_time.year, 2019)
            self.assertEquals(last_executed_time.month, 12)
            self.assertEquals(last_executed_time.day, 10)
            self.assertEquals(last_executed_time.hour, 8)
            self.assertEquals(last_executed_time.minute, 21)
            self.assertEquals(last_executed_time.second, 13)
 def test_load_hunt_ini(self):
     manager = HuntManager(**manager_kwargs())
     manager.load_hunts_from_config(hunt_filter=lambda hunt: hunt.name == 'query_test_1')
     self.assertEquals(len(manager.hunts), 1)
     
     hunt = manager.get_hunt_by_name('query_test_1')
     self.assertIsNotNone(hunt)
     self.assertTrue(hunt.enabled)
     self.assertEquals(hunt.name, 'query_test_1')
     self.assertEquals(hunt.description, 'Query Test Description 1')
     self.assertEquals(hunt.type, 'splunk')
     self.assertEquals(hunt.frequency, create_timedelta('00:01:00'))
     self.assertEquals(hunt.tags, ['tag1', 'tag2'])
     self.assertEquals(hunt.time_range, create_timedelta('00:01:00'))
     self.assertEquals(hunt.max_time_range, create_timedelta('01:00:00'))
     self.assertEquals(hunt.offset, create_timedelta('00:05:00'))
     self.assertTrue(hunt.full_coverage)
     self.assertEquals(hunt.group_by, 'field1')
     self.assertEquals(hunt.query, 'index=proxy {time_spec} src_ip=1.1.1.1\n')
     self.assertTrue(hunt.use_index_time)
     self.assertEquals(hunt.observable_mapping, { 'src_ip': 'ipv4', 'dst_ip': 'ipv4' })
     self.assertEquals(hunt.temporal_fields, { 'src_ip': True, 'dst_ip': True })
    def test_splunk_query(self):
        manager = HuntManager(**manager_kwargs())
        manager.load_hunts_from_config(hunt_filter=lambda hunt: hunt.name == 'test_query')
        self.assertEquals(len(manager.hunts), 1)
        hunt = manager.get_hunt_by_name('test_query')
        self.assertIsNotNone(hunt)

        with open('test_data/hunts/splunk/test_output.json', 'r') as fp:
            query_results = json.load(fp)

        result = hunt.execute(unit_test_query_results=query_results)
        self.assertTrue(isinstance(result, list))
        self.assertEquals(len(result), 4)
        for submission in result:
            with self.subTest(description=submission.description):
                self.assertEquals(submission.analysis_mode, ANALYSIS_MODE_CORRELATION)
                self.assertTrue(isinstance(submission.details, list))
                self.assertTrue(all([isinstance(_, dict) for _ in submission.details]))
                self.assertEquals(submission.files, [])
                self.assertEquals(submission.tags, ['tag1', 'tag2'])
                self.assertEquals(submission.tool, 'hunter-splunk')
                self.assertEquals(submission.tool_instance, saq.CONFIG['splunk']['uri'])
                self.assertEquals(submission.type, 'splunk')

                if submission.description == 'Test Splunk Query: 29380 (3 events)':
                    self.assertEquals(submission.event_time, datetime.datetime(2019, 12, 23, 16, 5, 36))
                    self.assertEquals(submission.observables, [ {'type': 'file_name', 'value': '__init__.py'} ])
                elif submission.description == 'Test Splunk Query: 29385 (2 events)':
                    self.assertEquals(submission.event_time, datetime.datetime(2019, 12, 23, 16, 5, 37))
                    self.assertEquals(submission.observables, [ {'type': 'file_name', 'value': '__init__.py'} ])
                elif submission.description == 'Test Splunk Query: 29375 (2 events)':
                    self.assertEquals(submission.event_time, datetime.datetime(2019, 12, 23, 16, 5, 36))
                    self.assertEquals(submission.observables, [ {'type': 'file_name', 'value': '__init__.py'} ])
                elif submission.description == 'Test Splunk Query: 31185 (93 events)':
                    self.assertEquals(submission.event_time, datetime.datetime(2019, 12, 23, 16, 5, 22))
                    self.assertEquals(submission.observables, [ {'type': 'file_name', 'value': '__init__.py'} ])
                else:
                    self.fail("invalid description")
Exemple #9
0
    def test_hunt_order(self):
        hunter = HuntManager(**manager_kwargs())
        # test initial hunt order
        # these are added in the wrong order but the should be sorted when we access them
        hunter.add_hunt(
            default_hunt(name='test_hunt_3',
                         frequency=create_timedelta('00:30')))
        hunter.add_hunt(
            default_hunt(name='test_hunt_2',
                         frequency=create_timedelta('00:20')))
        hunter.add_hunt(
            default_hunt(name='test_hunt_1',
                         frequency=create_timedelta('00:10')))

        # assume we've executed all of these hunts
        for hunt in hunter.hunts:
            hunt.last_executed_time = datetime.datetime.now()

        # now they should be in this order
        self.assertEquals(hunter.hunts[0].name, 'test_hunt_1')
        self.assertEquals(hunter.hunts[1].name, 'test_hunt_2')
        self.assertEquals(hunter.hunts[2].name, 'test_hunt_3')
Exemple #10
0
 def test_remove_hunt(self):
     hunter = HuntManager(**manager_kwargs())
     hunt = hunter.add_hunt(default_hunt())
     removed = hunter.remove_hunt(hunt)
     self.assertEquals(hunt.name, removed.name)
     self.assertEquals(len(hunter.hunts), 0)
Exemple #11
0
 def test_add_duplicate_hunt(self):
     # should not be allowed to add a hunt that already exists
     hunter = HuntManager(**manager_kwargs())
     hunter.add_hunt(default_hunt())
     with self.assertRaises(KeyError):
         hunter.add_hunt(default_hunt())
Exemple #12
0
 def test_add_hunt(self):
     hunter = HuntManager(**manager_kwargs())
     hunter.add_hunt(default_hunt())
     self.assertEquals(len(hunter.hunts), 1)