import demistomock as demisto # noqa: F401
import pytest
from CommonServerPython import * # noqa: F401
from StixCreator import add_file_fields_to_indicator, create_stix_sco_indicator, guess_indicator_type, main
FILE_INDICATOR = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2022-07-31T13:26:05Z",
"indicator_type": "File",
"lastSeen": "2022-07-31T13:26:05Z",
"score": "good",
"timestamp": "2022-07-31T13:26:05Z",
"value": "e14daa9c88a7ec91d770ae262758db73b6593b178527a2d7bba14159fad5f1c2",
}
}
}
MALWARE_INDICATOR = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2022-07-31T13:26:05Z",
"indicator_type": "Malware",
"lastSeen": "2022-07-31T13:26:05Z",
"score": "bad",
"timestamp": "2022-07-31T13:26:05Z",
"value": "Bad Malware",
"ismalwarefamily": "True",
}
}
}
ATTACK_PATTERN_INDICATOR = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2022-07-31T13:26:05Z",
"indicator_type": "Attack Pattern",
"lastSeen": "2022-07-31T13:26:05Z",
"score": "unknown",
"timestamp": "2022-07-31T13:26:05Z",
"value": "Attack Pattern",
"mitreid": "T1111",
}
}
}
DOMAIN_INDICATORS = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2022-07-31T13:24:44Z",
"indicator_type": "CVE",
"lastSeen": "2022-07-31T13:24:44Z",
"score": "Unknown",
"timestamp": "2022-07-31T13:24:44Z",
"value": "test.com",
},
"1": {
"expirationStatus": "active",
"firstSeen": "2022-07-31T13:24:40Z",
"indicator_type": "Attack Pattern",
"lastSeen": "2022-07-31T13:24:40Z",
"score": "suspicious",
"timestamp": "2022-07-31T13:24:40Z",
"value": "bad.com",
},
}
}
IP_INDICATOR_SCO = { # checking the new logic
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2023-04-18T12:17:38+03:00",
"indicator_type": "IP",
"lastSeen": "2023-04-18T12:17:38+03:00",
"score": "Unknown",
"timestamp": "2023-04-18T12:17:38+03:00",
"value": "8.8.8.8",
}
},
"sco_flag": "true",
}
IP_INDICATOR_SDO = { # checking bc
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2023-04-18T12:17:38+03:00",
"indicator_type": "IP",
"lastSeen": "2023-04-18T12:17:38+03:00",
"score": "Unknown",
"timestamp": "2023-04-18T12:17:38+03:00",
"value": "8.8.8.8",
}
},
"sco_flag": "false",
}
SOFTWARE_INDICATOR_SCO = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2023-05-07T14:42:59Z",
"indicator_type": "Software",
"lastSeen": "2023-05-07T14:42:59Z",
"score": "Unknown",
"timestamp": "2023-05-07T14:42:59Z",
"value": "Microsoft Word",
"CustomFields": {"vendor": "Microsoft", "version": "2019", "cpe": "cpe:2.3:a:microsoft:word:2019:*:*:*:*:*:*:*"},
}
},
"sco_flag": "true",
}
SOFTWARE_INDICATOR_MINIMAL = {
"indicators": {
"0": {
"expirationStatus": "active",
"firstSeen": "2023-05-07T14:42:59Z",
"indicator_type": "Software",
"lastSeen": "2023-05-07T14:42:59Z",
"score": "Unknown",
"timestamp": "2023-05-07T14:42:59Z",
"value": "Adobe Reader",
}
},
"sco_flag": "true",
}
@pytest.mark.parametrize(
"indicators, stix_type",
[
(DOMAIN_INDICATORS, "bundle"),
(FILE_INDICATOR, "indicator"),
(MALWARE_INDICATOR, "malware"),
(ATTACK_PATTERN_INDICATOR, "attack-pattern"),
(IP_INDICATOR_SCO, "ipv4-addr"),
(IP_INDICATOR_SDO, "indicator"),
(SOFTWARE_INDICATOR_SCO, "software"),
(SOFTWARE_INDICATOR_MINIMAL, "software"),
],
)
def test_stixCreator_with_indicators(mocker, indicators, stix_type):
mocker.patch.object(demisto, "args", return_value=indicators)
mocker.patch.object(demisto, "results")
main()
results = demisto.results.call_args[0]
assert stix_type in results[0]["Contents"]
@pytest.mark.parametrize(
"k,v,exp",
(
("actually-ip", "", "ip"), # key detection
("", "1.1.1.1", "ip"), # val detection (further tested in CSP_test.py)
("sha1sh", "", "sha1"), # key detection
("test", "t", "test"), # no detection
),
)
def test_guess_indicator_type(k, v, exp):
a = guess_indicator_type(k, v)
assert a == exp
xsoar_indicator_file = {
"expirationStatus": "active",
"firstSeen": "2023-05-07T14:42:59Z",
"indicator_type": "File",
"lastSeen": "2023-05-07T14:42:59Z",
"score": "Unknown",
"sha1": "57218c316b6921e2cd61027a2387edc31a2d9471",
"sha256": "f1945cd6c19e56b3c1c78943ef5ec18116907a4ca1efc40a57d48ab1db7adfc5",
"sha512": "37c783b80b1d458b89e712c2dfe2777050eff0aefc9f6d8beedee77807d9aeb2e27d14815cf4f0229"
"b1d36c186bb5f2b5ef55e632b108cc41e9fb964c39b42a5",
"ssdeep": "3:g:g",
"timestamp": "2023-05-07T14:42:59Z",
}
def test_add_file_fields_to_indicator():
"""
Given:
- A dictionary representing a xsoar indicator.
When:
- Creating a dictionary containing the file hashes.
Then:
- check the hashes dictionary
"""
expected_hashes_dict = {
"SHA-1": "57218c316b6921e2cd61027a2387edc31a2d9471",
"SHA-256": "f1945cd6c19e56b3c1c78943ef5ec18116907a4ca1efc40a57d48ab1db7adfc5",
"SHA-512": "37c783b80b1d458b89e712c2dfe2777050eff0aefc9f6d8beedee77807d9aeb2e27d14815cf4f0"
"229b1d36c186bb5f2b5ef55e632b108cc41e9fb964c39b42a5",
}
value = xsoar_indicator_file.get("value", "")
result = add_file_fields_to_indicator(xsoar_indicator_file, value)
assert expected_hashes_dict == result
xsoar_indicator_domain = {
"expirationStatus": "active",
"firstSeen": "2023-05-07T13:18:27Z",
"indicator_type": "Domain",
"lastSeen": "2023-05-07T13:18:27Z",
"score": "Unknown",
"timestamp": "2023-05-07T13:18:27Z",
"value": "hello@test.com",
}
xsoar_indicator_asn = {
"expirationStatus": "active",
"firstSeen": "2023-05-07T07:37:30Z",
"indicator_type": "ASN",
"lastSeen": "2023-05-07T07:37:30Z",
"name": "name",
"score": "Unknown",
"timestamp": "2023-05-07T07:37:30Z",
}
file_stix_id = "file--a1b6bbfd-73cd-5fef-9e12-9453e3b74cc5"
domain_stix_id = "domain-name--fdf407b4-c3d0-5011-a66c-5ef889593b08"
asn_stix_id = "autonomous-system--937a0541-d893-5707-ad67-bcfe8398164e"
file_stix_type = "file"
domain_stix_type = "domain-name"
asn_stix_type = "autonomous-system"
file_value = "f1945cd6c19e56b3c1c78943ef5ec18116907a4ca1efc40a57d48ab1db7adfc5"
domain_value = "hello@test.com"
asn_value = "54538"
expectes_stix_file_indicator = {
"type": "file",
"spec_version": "2.1",
"id": "file--a1b6bbfd-73cd-5fef-9e12-9453e3b74cc5",
"hashes": {
"SHA-1": "57218c316b6921e2cd61027a2387edc31a2d9471",
"SHA-256": "f1945cd6c19e56b3c1c78943ef5ec18116907a4ca1efc40a57d48ab1db7adfc5",
"SHA-512": "37c783b80b1d458b89e712c2dfe2777050eff0aefc9f6d8beedee77807d9aeb2e27d14"
"815cf4f0229b1d36c186bb5f2b5ef55e632b108cc41e9fb964c39b42a5",
},
}
expectes_stix_domain_indicator = {
"type": "domain-name",
"spec_version": "2.1",
"value": "hello@test.com",
"id": "domain-name--fdf407b4-c3d0-5011-a66c-5ef889593b08",
}
expectes_stix_asn_indicator = {
"type": "autonomous-system",
"spec_version": "2.1",
"id": "autonomous-system--937a0541-d893-5707-ad67-bcfe8398164e",
"number": "54538",
"name": "name",
}
params_test_create_stix_sco_indicator = [
(file_stix_id, file_stix_type, file_value, xsoar_indicator_file, expectes_stix_file_indicator),
(domain_stix_id, domain_stix_type, domain_value, xsoar_indicator_domain, expectes_stix_domain_indicator),
(asn_stix_id, asn_stix_type, asn_value, xsoar_indicator_asn, expectes_stix_asn_indicator),
]
# Software indicator test data
xsoar_indicator_software_full = {
"expirationStatus": "active",
"firstSeen": "2023-05-07T14:42:59Z",
"indicator_type": "Software",
"lastSeen": "2023-05-07T14:42:59Z",
"score": "Unknown",
"timestamp": "2023-05-07T14:42:59Z",
"value": "Microsoft Word",
"CustomFields": {"vendor": "Microsoft", "version": "2019", "cpe": "cpe:2.3:a:microsoft:word:2019:*:*:*:*:*:*:*"},
}
xsoar_indicator_software_minimal = {
"expirationStatus": "active",
"firstSeen": "2023-05-07T14:42:59Z",
"indicator_type": "Software",
"lastSeen": "2023-05-07T14:42:59Z",
"score": "Unknown",
"timestamp": "2023-05-07T14:42:59Z",
"value": "Adobe Reader",
}
software_stix_id_full = "software--710b0b41-d4d0-5d6c-a400-fc9254554ffc"
software_stix_id_minimal = "software--a1b2c3d4-e5f6-7890-abcd-ef1234567890"
software_stix_type = "software"
software_value_full = "Microsoft Word"
software_value_minimal = "Adobe Reader"
expected_stix_software_indicator_full = {
"type": "software",
"spec_version": "2.1",
"id": "software--710b0b41-d4d0-5d6c-a400-fc9254554ffc",
"name": "Microsoft Word",
"vendor": "Microsoft",
"version": "2019",
"cpe": "cpe:2.3:a:microsoft:word:2019:*:*:*:*:*:*:*",
}
expected_stix_software_indicator_minimal = {
"type": "software",
"spec_version": "2.1",
"id": "software--a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Adobe Reader",
}
params_test_create_stix_sco_indicator = [
(file_stix_id, file_stix_type, file_value, xsoar_indicator_file, expectes_stix_file_indicator),
(domain_stix_id, domain_stix_type, domain_value, xsoar_indicator_domain, expectes_stix_domain_indicator),
(asn_stix_id, asn_stix_type, asn_value, xsoar_indicator_asn, expectes_stix_asn_indicator),
(
software_stix_id_full,
software_stix_type,
software_value_full,
xsoar_indicator_software_full,
expected_stix_software_indicator_full,
),
(
software_stix_id_minimal,
software_stix_type,
software_value_minimal,
xsoar_indicator_software_minimal,
expected_stix_software_indicator_minimal,
),
]
@pytest.mark.parametrize(
"stix_id, stix_type, value, xsoar_indicator, expectes_stix_indicator", params_test_create_stix_sco_indicator
)
def test_create_stix_sco_indicator(stix_id, stix_type, value, xsoar_indicator, expectes_stix_indicator):
"""
Given:
- Case 1: A XSOAR indicator of type 'File', with a stix id of 'file--a1b6bbfd-73cd-5fef-9e12-9453e3b74cc5',
stix type of 'file' and a value of 'f1945cd6c19e56b3c1c78943ef5ec18116907a4ca1efc40a57d48ab1db7adfc5'.
- Case 2: A XSOAR indicator of type 'Domain', with a stix id of
'domain-name--fdf407b4-c3d0-5011-a66c-5ef889593b08', stix type of 'domain-name' and a value of
'hello@test.com'.
- Case 2: A XSOAR indicator of type 'ASN', with a stix id of
'autonomous-system--937a0541-d893-5707-ad67-bcfe8398164e', stix type of 'autonomous-system' and a value of
'54538'.
When:
- Creating a SCO indicator and calling create_stix_sco_indicator.
Then:
- Assert the indicator dictionary is as expected.
"""
result = create_stix_sco_indicator(stix_id, stix_type, value, xsoar_indicator)
assert result == expectes_stix_indicator
@pytest.mark.parametrize("indicators, stix_type", [(DOMAIN_INDICATORS, "bundle")])
def test_stixCreator_with_indicators_spec_version(mocker, indicators, stix_type):
"""
Given:
- A list of indicators.
When:
- Creating a bundle.
Then:
- Assert the spec_version is not empty.
"""
mocker.patch.object(demisto, "args", return_value=indicators)
mocker.patch.object(demisto, "results")
main()
results = demisto.results.call_args[0]
json_content = json.loads(results[0]["Contents"])
assert "spec_version" in json_content
assert json_content["spec_version"] == "2.1"
assert stix_type in results[0]["Contents"]
def test_software_indicator_with_all_fields():
"""
Given:
- A Software indicator with all optional fields (vendor, version, cpe).
When:
- Creating a STIX SCO indicator using create_stix_sco_indicator.
Then:
- Assert all fields are correctly included in the STIX object.
- Assert the structure matches STIX 2.1 specification for software objects.
"""
xsoar_indicator = {
"value": "Google Chrome",
"indicator_type": "Software",
"CustomFields": {
"vendor": "Google",
"version": "120.0.6099.109",
"cpe": "cpe:2.3:a:google:chrome:120.0.6099.109:*:*:*:*:*:*:*",
},
}
stix_id = "software--test-uuid-12345"
stix_type = "software"
value = "Google Chrome"
result = create_stix_sco_indicator(stix_id, stix_type, value, xsoar_indicator)
# Verify required fields
assert result["type"] == "software"
assert result["spec_version"] == "2.1"
assert result["id"] == stix_id
assert result["name"] == "Google Chrome"
# Verify optional fields are included
assert result["vendor"] == "Google"
assert result["version"] == "120.0.6099.109"
assert result["cpe"] == "cpe:2.3:a:google:chrome:120.0.6099.109:*:*:*:*:*:*:*"
def test_software_indicator_without_optional_fields():
"""
Given:
- A Software indicator without optional fields (only name).
When:
- Creating a STIX SCO indicator using create_stix_sco_indicator.
Then:
- Assert only required fields are present.
- Assert no optional fields with None/empty values are included.
"""
xsoar_indicator = {
"value": "Unknown Software",
"indicator_type": "Software",
}
stix_id = "software--test-uuid-67890"
stix_type = "software"
value = "Unknown Software"
result = create_stix_sco_indicator(stix_id, stix_type, value, xsoar_indicator)
# Verify required fields
assert result["type"] == "software"
assert result["spec_version"] == "2.1"
assert result["id"] == stix_id
assert result["name"] == "Unknown Software"
# Verify optional fields are NOT included when not provided
assert "vendor" not in result
assert "version" not in result
assert "cpe" not in result
def test_software_indicator_guess_type():
"""
Given:
- A type string containing 'software'.
When:
- Calling guess_indicator_type.
Then:
- Assert it correctly identifies the type as 'software'.
"""
result = guess_indicator_type("software", "test_value")
assert result == "software"
def test_software_indicator_partial_fields():
"""
Given:
- A Software indicator with only some optional fields (vendor and version, but no CPE).
When:
- Creating a STIX SCO indicator using create_stix_sco_indicator.
Then:
- Assert provided optional fields are included.
- Assert missing optional fields are not included.
"""
xsoar_indicator = {
"value": "Firefox",
"indicator_type": "Software",
"CustomFields": {"vendor": "Mozilla", "version": "121.0"},
}
stix_id = "software--test-uuid-partial"
stix_type = "software"
value = "Firefox"
result = create_stix_sco_indicator(stix_id, stix_type, value, xsoar_indicator)
# Verify required fields
assert result["type"] == "software"
assert result["spec_version"] == "2.1"
assert result["id"] == stix_id
assert result["name"] == "Firefox"
# Verify provided optional fields are included
assert result["vendor"] == "Mozilla"
assert result["version"] == "121.0"
# Verify missing optional field is not included
assert "cpe" not in result