Example #1
0
def _label_search(label: Text,
                  return_fields: Optional[Text] = '',
                  max_entries: Optional[int] = None) -> pd.DataFrame:
    """Returns a DataFrame with all events that have a certain label.

  Args:
    label (str): a string representing the label to search for.
    return_fields (str): a comma separated string with all the fields that
        should be returned. If not provided all fields will be returned.
    max_entries (int): an integer with the maximum number of entries to return.

  Returns:
      A pandas DataFrame with the search results.
  """
    connect()
    state_obj = state.state()

    sketch = state_obj.get_from_cache('timesketch_sketch')
    if not sketch:
        print('No data, not connected to a sketch.')
        return pd.DataFrame()

    if not return_fields:
        return_fields = '*'

    search_obj = api_search.Search(sketch)
    label_chip = api_search.LabelChip()
    label_chip.label = label
    search_obj.add_chip(label_chip)
    search_obj.return_fields = _fix_return_fields(return_fields)
    if max_entries:
        search_obj.max_entries = max_entries

    return search_obj.table
Example #2
0
 def test_wildcard_query(self):
     """Wildcard query over all data in the sketch."""
     search_obj = search.Search(self.sketch)
     search_obj.query_string = '*'
     data_frame = search_obj.table
     count = len(data_frame)
     self.assertions.assertEqual(count, 3205)
Example #3
0
    def test_get_sigma_rule(self):
        """Client Sigma object tests."""
        rule = self.api.get_sigma_rule(
            rule_uuid="5266a592-b793-11ea-b3de-0242ac130004")
        rule.from_rule_uuid("5266a592-b793-11ea-b3de-0242ac130004")
        self.assertions.assertGreater(len(rule.attributes), 5)
        self.assertions.assertIsNotNone(rule)
        self.assertions.assertIn("Alexander", rule.author)
        self.assertions.assertIn("Alexander", rule.get_attribute("author"))
        self.assertions.assertIn("b793-11ea-b3de-0242ac130004", rule.id)
        self.assertions.assertIn("Installation of ZMap", rule.title)
        self.assertions.assertIn("zmap", rule.es_query)
        self.assertions.assertIn("shell:zsh:history", rule.es_query)
        self.assertions.assertIn("lnx_susp_zmap.yml", rule.file_relpath)
        self.assertions.assertIn("sigma/rule/5266a592", rule.resource_uri)
        self.assertions.assertIn("installation of ZMap", rule.description)
        self.assertions.assertIn("high", rule.level)
        self.assertions.assertEqual(len(rule.falsepositives), 1)
        self.assertions.assertIn("Unknown", rule.falsepositives[0])
        self.assertions.assertIn("susp_zmap", rule.file_name)
        self.assertions.assertIn("2020/06/26", rule.date)
        self.assertions.assertIn("2020/06/26", rule.modified)
        self.assertions.assertIn("high", rule.level)
        self.assertions.assertIn("rmusser.net", rule.references[0])
        self.assertions.assertEqual(len(rule.detection), 2)
        self.assertions.assertEqual(len(rule.logsource), 2)

        # Test an actual query
        self.import_timeline("sigma_events.csv")
        search_obj = search.Search(self.sketch)
        search_obj.query_string = rule.es_query
        data_frame = search_obj.table
        count = len(data_frame)
        self.assertions.assertEqual(count, 1)
Example #4
0
    def test_get_sigma_rule(self):
        """Client Sigma object tests."""
        rule = self.api.get_sigma_rule(
            rule_uuid='5266a592-b793-11ea-b3de-0242ac130004')
        rule.from_rule_uuid('5266a592-b793-11ea-b3de-0242ac130004')
        self.assertions.assertGreater(len(rule.attributes), 5)
        self.assertions.assertIsNotNone(rule)
        self.assertions.assertIn('Alexander', rule.author)
        self.assertions.assertIn('Alexander', rule.get_attribute('author'))
        self.assertions.assertIn('b793-11ea-b3de-0242ac130004', rule.id)
        self.assertions.assertIn('Installation of ZMap', rule.title)
        self.assertions.assertIn('zmap', rule.es_query)
        self.assertions.assertIn('shell:zsh:history', rule.es_query)
        self.assertions.assertIn('lnx_susp_zmap.yml', rule.file_relpath)
        self.assertions.assertIn('sigma/rule/5266a592', rule.resource_uri)
        self.assertions.assertIn('installation of ZMap', rule.description)
        self.assertions.assertIn('high', rule.level)
        self.assertions.assertEqual(len(rule.falsepositives), 1)
        self.assertions.assertIn('Unknown', rule.falsepositives[0])
        self.assertions.assertIn('susp_zmap', rule.file_name)
        self.assertions.assertIn('2020/06/26', rule.date)
        self.assertions.assertIn('2020/06/26', rule.modified)
        self.assertions.assertIn('high', rule.level)
        self.assertions.assertIn('rmusser.net', rule.references[0])
        self.assertions.assertEqual(len(rule.detection), 2)
        self.assertions.assertEqual(len(rule.logsource), 2)

        # Test an actual query
        self.import_timeline('sigma_events.csv')
        search_obj = search.Search(self.sketch)
        search_obj.query_string = rule.es_query
        data_frame = search_obj.table
        count = len(data_frame)
        self.assertions.assertEqual(count, 1)
Example #5
0
    def test_specific_queries(self):
        """Test few specific queries."""
        search_obj = search.Search(self.sketch)
        search_obj.query_string = 'message_identifier: "1073748864"'
        search_obj.return_fields = "computer_name,data_type,strings,user_sid"

        data_frame = search_obj.table
        self.assertions.assertEqual(len(data_frame), 204)

        computers = list(data_frame.computer_name.unique())
        self.assertions.assertEqual(len(computers), 1)
        self.assertions.assertEqual(computers[0], "WKS-WIN764BITB.shieldbase.local")

        def extract_strings(row):
            strings = row.strings
            return pd.Series(
                {
                    "service": strings[0],
                    "state_from": strings[1],
                    "state_to": strings[2],
                    "by": strings[3],
                }
            )

        strings_frame = data_frame.apply(extract_strings, axis=1)
        services = set(strings_frame.service.unique())
        expected_set = set(
            ["Background Intelligent Transfer Service", "Windows Modules Installer"]
        )
        self.assertions.assertSetEqual(services, expected_set)

        search_name = "My First Search"
        search_obj.name = search_name
        search_obj.description = "Can it be, is it really?"

        search_obj.save()

        _ = self.sketch.lazyload_data(refresh_cache=True)
        saved_search = None
        for search_obj in self.sketch.list_saved_searches():
            if search_obj.name == search_name:
                saved_search = search_obj
                break

        if search_obj is None:
            raise RuntimeError("Unable to find the saved search.")
        self.assertions.assertEqual(
            saved_search.return_fields,
            "computer_name,data_type,strings,user_sid,datetime"
        )

        self.assertions.assertEqual(
            saved_search.query_string, 'message_identifier: "1073748864"'
        )
Example #6
0
 def _click_function(_):
     sketch = timesketch_get_sketch_func()
     search_obj = search.Search(sketch)
     if start_time_form.value and end_time_form.value:
         date_chip = search.DateRangeChip()
         date_chip.start_time = start_time_form.value.strftime(
             '%Y-%m-%dT%H:%M:%S')
         date_chip.end_time = end_time_form.value.strftime(
             '%Y-%m-%dT%H:%M:%S')
         search_obj.add_chip(date_chip)
     search_obj.query_string = query_string_form.value
     display(
         Markdown(f'Query **executed** - returned: {len(search_obj.table)} '
                  'records'))
     utils.ipython_bind_global('search_obj', search_obj)
     display(Markdown('Results are stored in the **search_obj**'))
Example #7
0
def query_timesketch(
        query: Optional[Text] = None,
        query_dsl: Optional[Text] = None,
        query_filter: Optional[Dict[Text, Any]] = None,
        return_fields: Optional[Text] = None,
        start_date: Optional[Text] = '',
        end_date: Optional[Text] = '',
        max_entries: Optional[int] = None,
        indices: Optional[List[Text]] = None) -> api_search.Search:
    """Return back a search object from a Timesketch query.

  Args:
    query (str): the query string to send to Timesketch.
    query_dsl (str): the query DSL to send to Timesketch.
    return_fields (str): string with comma separated names of fields to
        return back.
    start_date (str): a timestamp in the form of
        'YYYY-MM-DDTHH:MM:SS+00:00' of when to start the search query.
    end_date (str): a timestamp in the form of
        'YYYY-MM-DDTHH:MM:SS+00:00' of when to end the search query.
    max_entries (int): Optional integer denoting a best effort to limit
        the output size to the number of events. Events are read in,
        10k at a time so there may be more events in the answer back
        than this number denotes, this is a best effort. This value defaults
        to 40k events. Setting max_entries to zero will return all entries
        back (as in no limit).
    indices (list): a list of indices to query, if not provided _all
        will be used.

  Returns:
    A search object (api_search.Search) that is pre-configured.

  Raises:
    KeyError: if the query is sent in without a query or query_dsl.
  """
    connect()
    state_obj = state.state()
    sketch = state_obj.get_from_cache('timesketch_sketch')

    if all(x is None for x in [query, query_dsl]):
        raise KeyError('Need to provide a query or query_dsl')

    chip = None
    if start_date or end_date:
        if start_date and end_date:
            chip = api_search.DateRangeChip()
            chip.start_time = start_date
            chip.end_time = end_date
        else:
            chip = api_search.DateIntervalChip()
            if end_date:
                chip.date = end_date
            else:
                chip.date = start_date

    search_obj = api_search.Search(sketch)
    search_obj.from_manual(query_string=query,
                           query_dsl=query_dsl,
                           query_filter=query_filter,
                           max_entries=max_entries)

    return_fields = _fix_return_fields(return_fields)
    if return_fields:
        search_obj.return_fields = return_fields

    if chip:
        search_obj.add_chip(chip)

    return search_obj
Example #8
0
def search_group(ctx, query, times, time_ranges, labels, header, output,
                 return_fields, order, limit, saved_search, describe):
    """Search and explore."""
    sketch = ctx.obj.sketch
    output_format = ctx.obj.output_format
    search_obj = search.Search(sketch=sketch)

    if output:
        output_format = output

    new_line = True
    if output_format == 'csv':
        new_line = False

    # Construct query from saved search and return early.
    if saved_search:
        search_obj.from_saved(saved_search)
        if describe:
            describe_query(search_obj)
            return
        click.echo(format_output(
            search_obj, output_format, header), nl=new_line)
        return

    # Construct the query from flags.
    # TODO (berggren): Add support for query DSL.
    search_obj.query_string = query

    if return_fields:
        search_obj.return_fields = return_fields

    if limit:
        search_obj.max_entries = limit

    if order == 'asc':
        search_obj.order_ascending()
    elif order == 'desc':
        search_obj.order_descending()

    # TODO: Add term chips.
    if time_ranges:
        for time_range in time_ranges:
            try:
                range_chip = search.DateRangeChip()
                range_chip.add_start_time = time_range[0]
                range_chip.add_end_time = time_range[1]
                search_obj.add_chip(range_chip)
            except ValueError:
                click.echo(
                    "Error parsing date (make sure it is ISO formatted)")
                sys.exit(1)

    # TODO (berggren): This should support dates like 2021-02-12 and then
    # convert to ISO format.
    if times:
        for time in times:
            try:
                range_chip = search.DateRangeChip()
                range_chip.add_start_time = time
                range_chip.add_end_time = time
                search_obj.add_chip(range_chip)
            except ValueError:
                click.echo(
                    "Error parsing date (make sure it is ISO formatted)")
                sys.exit(1)

    if labels:
        for label in labels:
            label_chip = search.LabelChip()
            if label == 'star':
                label_chip.use_star_label()
            elif label == 'comment':
                label_chip.use_comment_label()
            else:
                label_chip.label = label
            search_obj.add_chip(label_chip)

    if describe:
        describe_query(search_obj)
        return

    click.echo(format_output(search_obj, output_format, header), nl=new_line)