def test_and_observable_expression():
    exp1 = stix2.AndBooleanExpression([
        stix2.EqualityComparisonExpression("user-account:account_type",
                                           "unix"),
        stix2.EqualityComparisonExpression("user-account:user_id",
                                           stix2.StringConstant("1007")),
        stix2.EqualityComparisonExpression("user-account:account_login",
                                           "Peter")
    ])
    exp2 = stix2.AndBooleanExpression([
        stix2.EqualityComparisonExpression("user-account:account_type",
                                           "unix"),
        stix2.EqualityComparisonExpression("user-account:user_id",
                                           stix2.StringConstant("1008")),
        stix2.EqualityComparisonExpression("user-account:account_login",
                                           "Paul")
    ])
    exp3 = stix2.AndBooleanExpression([
        stix2.EqualityComparisonExpression("user-account:account_type",
                                           "unix"),
        stix2.EqualityComparisonExpression("user-account:user_id",
                                           stix2.StringConstant("1009")),
        stix2.EqualityComparisonExpression("user-account:account_login",
                                           "Mary")
    ])
    exp = stix2.AndObservationExpression([
        stix2.ObservationExpression(exp1),
        stix2.ObservationExpression(exp2),
        stix2.ObservationExpression(exp3)
    ])
    assert str(
        exp
    ) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = '******'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = '******'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = '******']"  # noqa
Exemple #2
0
def test_hex():
    exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("file:mime_type",
                                                                             "image/bmp"),
                                          stix2.EqualityComparisonExpression("file:magic_number_hex",
                                                                             stix2.HexConstant("ffd8"))])
    exp = stix2.ObservationExpression(exp_and)
    assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
Exemple #3
0
def test_invalid_and_observable_expression():
    with pytest.raises(ValueError) as excinfo:
        stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:display_name",
                                                                       "admin"),
                                    stix2.EqualityComparisonExpression("email-addr:display_name",
                                                                       stix2.StringConstant("admin"))])
    assert "All operands to an 'AND' expression must have the same object type" in str(excinfo)
Exemple #4
0
def test_boolean_expression():
    exp1 = stix2.MatchesComparisonExpression("email-message:from_ref.value",
                                             stix2.StringConstant(".+\\@example\\.com$"))
    exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
                                             stix2.StringConstant("^Final Report.+\\.exe$"))
    exp = 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
Exemple #5
0
def test_artifact_payload():
    exp1 = stix2.EqualityComparisonExpression("artifact:mime_type",
                                              "application/vnd.tcpdump.pcap")
    exp2 = stix2.MatchesComparisonExpression("artifact:payload_bin",
                                             stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"))
    and_exp = stix2.AndBooleanExpression([exp1, exp2])
    exp = stix2.ObservationExpression(and_exp)
    assert str(exp) == "[artifact:mime_type = 'application/vnd.tcpdump.pcap' AND artifact:payload_bin MATCHES '\\\\xd4\\\\xc3\\\\xb2\\\\xa1\\\\x02\\\\x00\\\\x04\\\\x00']"  # noqa
Exemple #6
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']"
Exemple #7
0
def test_file_observable_expression():
    exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
                                              stix2.HashConstant(
                                                  "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
                                                  'SHA-256'))
    exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf"))
    bool_exp = stix2.AndBooleanExpression([exp1, exp2])
    exp = stix2.ObservationExpression(bool_exp)
    assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']"  # noqa
Exemple #8
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
Exemple #9
0
def test_multiple_qualifiers():
    exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("network-traffic:dst_ref.type",
                                                                             "domain-name"),
                                          stix2.EqualityComparisonExpression("network-traffic:dst_ref.value",
                                                                             "example.com")])
    exp_ob = stix2.ObservationExpression(exp_and)
    qual_rep = stix2.RepeatQualifier(5)
    qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800))
    exp = stix2.QualifiedObservationExpression(stix2.QualifiedObservationExpression(exp_ob, qual_rep), qual_within)
    assert str(exp) == "[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS"  # noqa
def test_invalid_and_observable_expression():
    with pytest.raises(ValueError):
        stix2.AndBooleanExpression([
            stix2.EqualityComparisonExpression(
                "user-account:display_name",
                "admin",
            ),
            stix2.EqualityComparisonExpression(
                "email-addr:display_name",
                stix2.StringConstant("admin"),
            ),
        ])
    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