Example #1
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']"
Example #2
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)
def test_multiple_file_observable_expression(observation_class, op):
    exp1 = stix2.EqualityComparisonExpression(
        "file:hashes.'SHA-256'",
        stix2.HashConstant(
            "bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
            'SHA-256',
        ),
    )
    exp2 = stix2.EqualityComparisonExpression(
        "file:hashes.MD5",
        stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"),
    )
    bool1_exp = stix2.OrBooleanExpression([exp1, exp2])
    exp3 = stix2.EqualityComparisonExpression(
        "file:hashes.'SHA-256'",
        stix2.HashConstant(
            "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
            'SHA-256',
        ),
    )
    op1_exp = stix2.ObservationExpression(bool1_exp)
    op2_exp = stix2.ObservationExpression(exp3)
    exp = observation_class([op1_exp, op2_exp])
    assert str(
        exp
    ) == "[file:hashes.'SHA-256' = 'bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c' OR file:hashes.MD5 = 'cead3f77f6cda6ec00f57d76c9a6879f'] {} [file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']".format(
        op)  # noqa
Example #4
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 #5
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
Example #6
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_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
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"),
            ),
        ])
Example #9
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
Example #10
0
def test_create_comparison_expression():
    exp = stix2.EqualityComparisonExpression(
        "file:hashes.'SHA-256'",
        stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256"),
    )   # noqa

    assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'"
def test_list2():
    # alternate way to construct an "IN" Comparison Expression
    exp = stix2.EqualityComparisonExpression(
        "process:name",
        ['proccy', 'proximus', 'badproc'],
    )
    assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
def test_invalid_constant_type():
    with pytest.raises(ValueError) as excinfo:
        stix2.EqualityComparisonExpression(
            "artifact:payload_bin",
            {'foo': 'bar'},
        )
    assert 'Unable to create a constant' in str(excinfo)
def test_binary():
    const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=")
    exp = stix2.EqualityComparisonExpression(
        "artifact:payload_bin",
        const,
    )
    assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
Example #14
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
def test_invalid_constant_type():
    with pytest.raises(ValueError):
        stix2.EqualityComparisonExpression(
            "artifact:payload_bin",
            {'foo': 'bar'},
        )
def test_boolean():
    exp = stix2.EqualityComparisonExpression(
        "email-message:is_multipart",
        True,
    )
    assert str(exp) == "email-message:is_multipart = true"
Example #17
0
    def process_reports(self, reports):
        if reports is None:
            printer.error("No results")
            return

        for report in reports:
            name = report["name"]
            id = report["id"]
            stix2_objects = []
            stix2_object_refs = []

            # FFS AV, consistency!
            if 'tlp' in report:
                tlp_id = REF_TLPS[report['tlp'].upper()]
            elif 'TLP' in report:
                tlp_id = REF_TLPS[report['TLP'].upper()]
            else:
                tlp_id = REF_TLPS['WHITE']

            sectors = report['industries']
            if sectors:
                unmatched_sectors = []
                added_sector = False

                for sector in [html.unescape(x.upper()) for x in sectors]:
                    sector_name = None
                    sector_id = None

                    if sector in SECTOR_MAPPINGS:
                        # sector_ids.append(self.octi_sectors[SECTOR_MAPPINGS[sector]])
                        sector_name = SECTOR_MAPPINGS[sector]
                        try:
                            sector_id = self.octi_sectors[
                                SECTOR_MAPPINGS[sector]]
                        except Exception as e:
                            printer.error(e)
                            continue
                    else:
                        printer.debug(f"Looking for sector {sector}")
                        match = difflib.get_close_matches(
                            sector, self.octi_sectors.keys(), 1)
                        if not len(match):
                            printer.error(
                                f"Unable to determine a matching sector for {sector}"
                            )
                            unmatched_sectors.append(sector)
                            continue
                        # sector_ids.append(self.octi_sectors[match[0]])
                        sector_name = match[0]
                        sector_id = self.octi_sectors[match[0]]

                    if sector_name is not None:
                        s = stix2.Identity(id=sector_id,
                                           name=sector_name,
                                           identity_class='class',
                                           custom_properties={
                                               'x_opencti_identity_type':
                                               'sector'
                                           })
                        printer.debug(f"Adding sector {sector_name}")
                        stix2_objects.append(s)
                        stix2_object_refs.append(s)
                        added_sector = True

                if not added_sector:
                    printer.warn("Adding 'UNKNOWN' placeholder sector")
                    s = stix2.Identity(id=self.octi_sectors["UNKNOWN"],
                                       name="Unknown",
                                       identity_class='class',
                                       custom_properties={
                                           'x_opencti_identity_type': 'sector'
                                       })
                    stix2_objects.append(s)
                    stix2_object_refs.append(s)

                description = report['description']
                if len(unmatched_sectors):
                    description = description + "\n\n###\nUnable to find a match for the following sectors, " \
                                                "please review manually:\n - " + '\n - '.join(unmatched_sectors)

                printer.info(f"Generating STIX2 for {name} ({id})")

                author = stix2.Identity(name=report['author_name'],
                                        identity_class='organization')
                stix2_objects.append(author)

                adversary = None
                if report['adversary']:
                    printer.debug("Adding adversary {}".format(
                        report['adversary']))
                    adversary = stix2.IntrusionSet(name=report['adversary'])
                    stix2_object_refs.append(adversary)
                    stix2_objects.append(adversary)

                if report['targeted_countries']:
                    for country in report['targeted_countries']:
                        printer.debug(f"Adding country {country}")
                        c = stix2.Identity(name=country,
                                           identity_class='organization',
                                           custom_properties={
                                               'x_opencti_identity_type':
                                               'country'
                                           })
                        stix2_objects.append(c)
                        stix2_object_refs.append(c)

                external_refs = []
                for eref in report['references']:
                    external_refs.append(
                        stix2.ExternalReference(source_name=tldextract.extract(
                            eref).registered_domain,
                                                url=eref))

                indicators = report["indicators"]
                if indicators:
                    for indicator in indicators:
                        resolved_type = self.resolve_type(
                            indicator["type"].lower())
                        if resolved_type != None and indicator["is_active"]:

                            observable_type = resolved_type
                            observable_value = indicator["indicator"]
                            pattern_type = 'stix'

                            try:
                                if observable_type in PATTERNTYPES:
                                    pattern_type = observable_type
                                elif observable_type not in OPENCTISTIX2:
                                    printer.info("Not in stix2 dict")
                                else:
                                    if 'transform' in OPENCTISTIX2[
                                            observable_type]:
                                        if OPENCTISTIX2[observable_type][
                                                'transform'][
                                                    'operation'] == 'remove_string':
                                            observable_value = observable_value.replace(
                                                OPENCTISTIX2[observable_type]
                                                ['transform']['value'], '')
                                    lhs = stix2.ObjectPath(
                                        OPENCTISTIX2[observable_type]['type'],
                                        OPENCTISTIX2[observable_type]['path'])
                                    observable_value = stix2.ObservationExpression(
                                        stix2.EqualityComparisonExpression(
                                            lhs, observable_value))
                            except Exception as e:
                                printer.error(e)
                                printer.info(
                                    "Could not determine suitable pattern")

                            try:

                                indicator_obj = stix2.Indicator(
                                    name=indicator["indicator"],
                                    description=indicator["description"],
                                    pattern=str(observable_value),
                                    valid_from=indicator["created"],
                                    labels=['malicious-activity'],
                                    created_by_ref=author,
                                    object_marking_refs=[tlp_id],
                                    custom_properties={
                                        'x_opencti_observable_type':
                                        resolved_type,
                                        'x_opencti_observable_value':
                                        indicator["indicator"],
                                        'x_opencti_pattern_type':
                                        pattern_type
                                    })
                                stix2_object_refs.append(indicator_obj)
                                stix2_objects.append(indicator_obj)
                            except Exception as e:
                                printer.error(e)
                                printer.info("Couldn't fetch indicator")

                else:
                    printer.error("No indicators")

                report = stix2.Report(name=name,
                                      description=description,
                                      created_by_ref=author,
                                      labels=['threat-report'],
                                      published=report['created'],
                                      created=report['created'],
                                      modified=report['modified'],
                                      object_refs=stix2_object_refs,
                                      object_marking_refs=[tlp_id],
                                      external_references=external_refs)
                stix2_objects.append(report)
                bundle = stix2.Bundle(stix2_objects).serialize()
                if not self.dryrun:
                    self.opencti_connector_helper.send_stix2_bundle(
                        bundle, None, True, False)
                    printer.info("Sending to OpenCTI")
                #printer.debug(str(bundle))

            else:
                printer.debug(f"No sectors, disregarding '{name}'")