Example #1
0
def test_root_types():
    ast = stix2.ObservationExpression(
            stix2.AndBooleanExpression(
                [stix2.ParentheticalExpression(
                    stix2.OrBooleanExpression([
                        stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
                        stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2"))])),
                 stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3"))]))
    assert str(ast) == "[(a:b = '1' OR b:c = '2') AND b:d = '3']"
Example #2
0
def test_boolean_expression_with_parentheses():
    exp1 = stix2.MatchesComparisonExpression(stix2.ObjectPath("email-message",
                                                              [stix2.ReferenceObjectPathComponent("from_ref"),
                                                               stix2.BasicObjectPathComponent("value")]),
                                             stix2.StringConstant(".+\\@example\\.com$"))
    exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
                                             stix2.StringConstant("^Final Report.+\\.exe$"))
    exp = stix2.ParentheticalExpression(stix2.AndBooleanExpression([exp1, exp2]))
    assert str(exp) == "(email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$')"  # noqa
Example #3
0
def test_hash_followed_by_registryKey_expression():
    hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5",
                                                  stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"))
    o_exp1 = stix2.ObservationExpression(hash_exp)
    reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]),
                                                 stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"))
    o_exp2 = stix2.ObservationExpression(reg_exp)
    fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
    para_exp = stix2.ParentheticalExpression(fb_exp)
    qual_exp = stix2.WithinQualifier(stix2.IntegerConstant(300))
    exp = stix2.QualifiedObservationExpression(para_exp, qual_exp)
    assert str(exp) == "([file:hashes.MD5 = '79054025255fb1a26e4bc422aef54eb4'] FOLLOWEDBY [windows-registry-key:key = 'HKEY_LOCAL_MACHINE\\\\foo\\\\bar']) WITHIN 300 SECONDS"  # noqa
    def __generate_observation_expression(self, size):
        """
        Generate a random complex observation expression, which may consist of
        sub-expressions and qualifiers.

        :param size: The size of the desired observation expression, in terms of
            the number of simple comparison expressions it must contain
        :return: The observation expression AST
        """
        assert size > 0

        # The generation strategy is similar to that for comparison expressions
        # (see __generate_complex_comparison_expression()).  It is generated in
        # two parts of random size; one side is constructed as a sub-expression.

        if size == 1:
            obs_expr = stix2.ObservationExpression(
                self.__generate_complex_comparison_expression(1))

        else:
            lsize = random.randint(0, size)
            rsize = size - lsize

            if random.random() < 0.5:
                # Parenthesize right case
                obs_exprs = [
                    stix2.ObservationExpression(
                        self.__generate_complex_comparison_expression(sz))
                    for sz in _rand_series(lsize)
                ]

                if rsize > 0:
                    obs_exprs.append(
                        stix2.ParentheticalExpression(
                            self.__generate_observation_expression(rsize)))

            else:
                # Parenthesize left case
                if lsize == 0:
                    obs_exprs = []
                else:
                    obs_exprs = [
                        stix2.ParentheticalExpression(
                            self.__generate_observation_expression(lsize))
                    ]

                obs_exprs.extend(
                    stix2.ObservationExpression(
                        self.__generate_complex_comparison_expression(sz))
                    for sz in _rand_series(rsize))

            ast_class = random.choice(
                (stix2.AndObservationExpression, stix2.OrObservationExpression,
                 stix2.FollowedByObservationExpression))

            obs_expr = ast_class(obs_exprs)

        if random.random() < self.__config.probability_qualifier:
            qualifier = self.__generate_random_qualifier()
            obs_expr = stix2.QualifiedObservationExpression(
                obs_expr, qualifier)

        return obs_expr
    def __generate_complex_comparison_expression(self,
                                                 size,
                                                 type_constraint=None):
        """
        Generates a "complex" comparison expression, i.e. one which may consist
        of sub-expressions connected via AND or OR.  If a type constraint is
        given, the resulting expression will honor that constraint.

        :param size: The size of the desired complex comparison expression, in
            terms of the number of simple comparison expressions it must contain
        :param type_constraint: An SCO type, or None
        :return:
        """
        assert size > 0

        # This complex expression must be composed of N simple expressions.
        # This implementation builds the overall expression in two parts: a
        # left and right side.  The location of the split between left and
        # right is random.  A side is randomly chosen to just contain a series
        # of simple expressions, and the other side will have a nested
        # subexpression.
        #
        # One goal of the strategy is to avoid excessive nested parentheses.
        # Too many parentheses results in ugly crazy-looking patterns.  This
        # algorithm still can generate some silly patterns, but I hope it helps
        # a little.
        if size == 1:
            expr = self.__generate_simple_comparison_expression_list(
                1, type_constraint, False)[0]

        else:

            # Choose whether top-level operator will be AND or OR.
            # This will also determine how we handle the type constraint.
            is_and = random.random() < 0.5

            # If AND, all operands *must* be type-constrained.
            if is_and and not type_constraint:
                type_constraint = self.__random_sco_type()

            # In the following, if type_constraint is None, both left and right
            # constraints will be None.  No need for a special case.  If we
            # have a type constraint, for 'AND', the constraint must be
            # enforced on both sides.  For 'OR', we need only enforce it on one
            # side.
            if is_and:
                left_constraint = right_constraint = type_constraint
            else:
                left_constraint, right_constraint = type_constraint, None
                if random.random() < 0.5:
                    left_constraint, right_constraint = \
                        right_constraint, left_constraint

            # Don't let either side be zero size here.  Avoids the case where
            # we have an OR, and randomly choose to enforce the type constraint
            # on the zero-length side.  That can result in an invalid pattern.
            lsize = random.randint(1, size - 1)
            rsize = size - lsize

            if random.random() < 0.5:
                # Parenthesize right case
                operands = self.__generate_simple_comparison_expression_list(
                    lsize, left_constraint, is_and)

                operands.append(
                    stix2.ParentheticalExpression(
                        self.__generate_complex_comparison_expression(
                            rsize, right_constraint)))

            else:
                # Parenthesize left case
                operands = [
                    stix2.ParentheticalExpression(
                        self.__generate_complex_comparison_expression(
                            lsize, left_constraint))
                ]

                operands.extend(
                    self.__generate_simple_comparison_expression_list(
                        rsize, right_constraint, is_and))

            if is_and:
                expr = stix2.AndBooleanExpression(operands)
            else:
                expr = stix2.OrBooleanExpression(operands)

        return expr