Skip to content

Commit ea4859f

Browse files
Merge pull request #1375 from TheHive-Project:devtools-integration
Analyzers & Responders for testing / development purpose
2 parents 24296f6 + 2b3c0a1 commit ea4859f

File tree

5 files changed

+203
-56
lines changed

5 files changed

+203
-56
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"name": "DevTools_Echo",
3+
"version": "1.0",
4+
"author": "Fabien Bloume, StrangeBee",
5+
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
6+
"license": "AGPL-V3",
7+
"description": "Development utility that simply echoes the (available) input received by the analyzer.",
8+
"dataTypeList": [
9+
"ip",
10+
"domain",
11+
"url",
12+
"fqdn",
13+
"mail",
14+
"file",
15+
"hash",
16+
"filename",
17+
"uri_path",
18+
"user-agent",
19+
"mail-subject"
20+
],
21+
"baseConfig": "TestAnalyzer",
22+
"command": "TestAnalyzer/testing.py",
23+
"config": {
24+
"service": "echo"
25+
},
26+
"configurationItems": [
27+
{
28+
"name": "some_string",
29+
"description": "placeholder string",
30+
"type": "string",
31+
"multi": false,
32+
"required": false,
33+
"defaultValue": "some string.."
34+
},
35+
{
36+
"name": "some_list",
37+
"description": "placeholder list",
38+
"type": "string",
39+
"multi": true,
40+
"required": false,
41+
"defaultValue": [
42+
"item1",
43+
"item2",
44+
"item3"
45+
]
46+
},
47+
{
48+
"name": "some_number",
49+
"description": "placeholder number",
50+
"type": "number",
51+
"multi": false,
52+
"required": false,
53+
"defaultValue": 1
54+
},
55+
{
56+
"name": "throw_error",
57+
"description": "throw an error!",
58+
"type": "boolean",
59+
"multi": false,
60+
"required": true,
61+
"defaultValue": false
62+
}
63+
],
64+
"registration_required": false,
65+
"subscription_required": false,
66+
"free_subscription": false,
67+
"serviceHomepage": "None"
68+
}

analyzers/TestAnalyzer/testing.py

Lines changed: 106 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,121 @@
33

44
from cortexutils.analyzer import Analyzer
55

6+
67
class TestAnalyzer(Analyzer):
78
def __init__(self):
89
Analyzer.__init__(self)
9-
self.some_string = self.get_param(
10-
"config.some_string", None, "some_string parameter is missing"
11-
)
12-
self.some_list = self.get_param(
13-
"config.some_list", ["item1", "item2", "item3"], "some_list parameter is missing"
14-
)
15-
self.some_number = self.get_param(
16-
"config.some_number", 1, "some_number parameter is missing"
17-
)
10+
self.some_string = self.get_param("config.some_string", None)
11+
self.some_list = self.get_param("config.some_list", ["item1", "item2", "item3"])
12+
self.some_number = self.get_param("config.some_number", 1)
1813
self.throw_error = self.get_param(
1914
"config.throw_error", False, "throw_error parameter is missing"
2015
)
21-
16+
self.service = self.get_param(
17+
"config.service", None, "Service parameter is missing"
18+
)
19+
2220
def run(self):
23-
if self.throw_error:
24-
error_message = "this is an error string: throw_error boolean is set to True in Cortex"
25-
self.error(error_message)
26-
data = self.get_data()
27-
#data = self.get_param("data", None, "Data is missing")
28-
datatype = self.data_type
29-
30-
#result = {"data": data, "dataType": datatype, "arrayExample": ["A", "B", "C"], "tableExample": {"colA": "row A value", "colB": "row B value", "colC": "row C value",}}
31-
32-
# Unicode test data
33-
unicode_test_string = "こんにちは, 你好, 안녕하세요, 😀, 💻, π, ∑, ∞, « Bonjour, comment ça va ? »"
34-
unicode_table_example = {
35-
"colA": "Row A: こんにちは (Hello in Japanese)",
36-
"colB": "Row B: 你好 (Hello in Chinese)",
37-
"colC": "Row C: 😀 (Smiley emoji)",
38-
"colD": "«Row D: Bonjour, comment ça va ? Très bien. » (Hello, how are you? Doing very well. in French)"
39-
}
40-
41-
result = {
42-
"data": data,
43-
"dataType": datatype,
44-
"arrayExample": ["A", "B", "C", "Δ", "Ж", "Ω", "💡"],
45-
"tableExample": unicode_table_example,
46-
"unicodeTest": unicode_test_string
47-
}
48-
49-
self.report(result)
50-
21+
try:
22+
if self.throw_error:
23+
error_message = "this is an error string: throw_error boolean is set to True in Cortex"
24+
self.error(error_message)
25+
data = self.get_data()
26+
# data = self.get_param("data", None, "Data is missing")
27+
datatype = self.data_type
28+
29+
if self.service == "echo":
30+
everything = {
31+
# Observable metadata
32+
# "_id": self.get_param("_id", None), ## Not supported / Not in input
33+
# "_type": self.get_param("_type", None), ## Not supported / Not in input
34+
# "_createdBy": self.get_param("_createdBy", None), ## Not supported / Not in input
35+
# "_updatedBy": self.get_param("_updatedBy", None), ## Not supported / Not in input
36+
# "_createdAt": self.get_param("_createdAt", None), ## Not supported / Not in input
37+
# "_updatedAt": self.get_param("_updatedAt", None), ## Not supported / Not in input
38+
39+
# Core observable
40+
"dataType": self.get_param("dataType", None),
41+
"data": self.get_param("data", None),
42+
43+
# Dates
44+
# "startDate": self.get_param("startDate", None), ## Not supported / Not in input
45+
46+
# TLP / PAP
47+
"tlp": self.get_param("tlp", None),
48+
# "tlpLabel": self.get_param("tlpLabel", None), ## Not supported / Not in input
49+
"pap": self.get_param("pap", None),
50+
# "papLabel": self.get_param("papLabel", None), ## Not supported / Not in input
51+
52+
# Tags / IOC / Sighted
53+
# "tags": self.get_param("tags", None), ## Not supported / Not in input
54+
# "ioc": self.get_param("ioc", None), ## Not supported / Not in input
55+
# "sighted": self.get_param("sighted", None), ## Not supported / Not in input
56+
# "sightedAt": self.get_param("sightedAt", None), ## Not supported / Not in input
57+
# "ignoreSimilarity": self.get_param("ignoreSimilarity", None), ## Not supported / Not in input
58+
59+
# Reports
60+
# "reports": self.get_param("reports", None), ## Not supported / Not in input
61+
62+
# Message
63+
"message": self.get_param("message", None), # Represents case ID!
64+
65+
# Extra data
66+
# "extraData": self.get_param("extraData", None), ## Not supported / Not in input
67+
68+
# File / attachment (if applicable)
69+
"file": self.get_param("file", None), ## Not in input (null unless dataType=="file")
70+
"attachment": self.get_param("attachment", None),## Not supported / Not in input
71+
72+
# Job parameters & analyzer config blocks
73+
"parameters": self.get_param("parameters", {}),
74+
"config": self.get_param("config", {}),
75+
76+
# Proxy (if passed)
77+
"proxy": self.get_param("proxy", {}),
78+
}
79+
result = everything
80+
81+
elif self.service == "testing":
82+
# result = {"data": data, "dataType": datatype, "arrayExample": ["A", "B", "C"], "tableExample": {"colA": "row A value", "colB": "row B value", "colC": "row C value",}}
83+
84+
# Unicode test data
85+
unicode_test_string = "こんにちは, 你好, 안녕하세요, 😀, 💻, π, ∑, ∞, « Bonjour, comment ça va ? »"
86+
unicode_table_example = {
87+
"colA": "Row A: こんにちは (Hello in Japanese)",
88+
"colB": "Row B: 你好 (Hello in Chinese)",
89+
"colC": "Row C: 😀 (Smiley emoji)",
90+
"colD": "«Row D: Bonjour, comment ça va ? Très bien. » (Hello, how are you? Doing very well. in French)",
91+
}
92+
93+
result = {
94+
"data": data,
95+
"dataType": datatype,
96+
"arrayExample": ["A", "B", "C", "Δ", "Ж", "Ω", "💡"],
97+
"tableExample": unicode_table_example,
98+
"unicodeTest": unicode_test_string,
99+
}
100+
101+
self.report(result)
102+
except Exception as e:
103+
self.error(f"Unhandled exception: {e}")
104+
51105
def summary(self, raw):
52106
taxonomies = []
53107
namespace = "testing"
54108
predicate = self.data_type
55109
value = "None"
56-
57-
# safe, info, suspicious, malicious
58-
for level in ["info", "safe", "suspicious", "malicious"]:
59-
taxonomies.append(
60-
self.build_taxonomy(
61-
level, namespace, predicate, value)
62-
)
63-
110+
111+
if self.service == "testing":
112+
# safe, info, suspicious, malicious
113+
for level in ["info", "safe", "suspicious", "malicious"]:
114+
taxonomies.append(
115+
self.build_taxonomy(level, namespace, predicate, value)
116+
)
64117
return {"taxonomies": taxonomies}
65118

66119
def operations(self, raw):
67120
operations = []
68-
operations.append(self.build_operation('AddTagToArtifact', tag="test"))
69121
## For reference only
70122
# case class AddTagToCase(tag: String) extends ActionOperation
71123
# case class AddTagToArtifact(tag: String) extends ActionOperation
@@ -86,16 +138,17 @@ def operations(self, raw):
86138
# tags: Option[Seq[String]]
87139
# ) extends ActionOperation
88140
# case class AssignCase(owner: String) extends ActionOperation
141+
if self.service == "testing":
142+
operations.append(self.build_operation("AddTagToArtifact", tag="test"))
89143
return operations
90144

91145
def artifacts(self, raw):
92146
artifacts = []
93-
data_type = "ip"
94-
value = "8.8.8.8"
95-
extra_args = {
96-
"tags": ["test"]
97-
}
98-
artifacts.append(self.build_artifact(data_type, value, **extra_args))
147+
if self.service == "testing":
148+
data_type = "ip"
149+
value = "8.8.8.8"
150+
extra_args = {"tags": ["test"]}
151+
artifacts.append(self.build_artifact(data_type, value, **extra_args))
99152
return artifacts
100153

101154

responders/Test/DevTools_Echo.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "DevTools_Echo",
3+
"version": "1.0",
4+
"author": "Fabien Bloume, StrangeBee",
5+
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
6+
"license": "AGPL-V3",
7+
"description": "Development utility that simply echoes the input received by the responder.",
8+
"dataTypeList": ["thehive:case", "thehive:alert", "thehive:case_artifact", "thehive:case_task", "thehive:case_task_log"],
9+
"command": "Test/test.py",
10+
"baseConfig": "Test",
11+
"config": {
12+
"service": "echo"
13+
},
14+
"configurationItems": [
15+
]
16+
}

responders/Test/test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
"dataTypeList": ["thehive:case", "thehive:alert", "thehive:case_artifact", "thehive:case_task", "thehive:case_task_log"],
99
"command": "Test/test.py",
1010
"baseConfig": "Test",
11+
"config": {
12+
"service": "test"
13+
},
1114
"configurationItems": [
1215
]
1316
}

responders/Test/test.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,24 @@
55
class Test(Responder):
66
def __init__(self):
77
Responder.__init__(self)
8-
self.report({"message": "test"})
8+
self.service = self.get_param("config.service", None, "Service parameter is missing.")
99

1010
def run(self):
1111
Responder.run(self)
12-
12+
if self.service == "test":
13+
self.report({"message": "test"})
14+
elif self.service == "echo":
15+
self.report(self.get_param("data"))
16+
1317
def operations(self, raw):
18+
artifacts = []
1419
# AddTagToArtifact ({ "type": "AddTagToArtifact", "tag": "tag to add" }): add a tag to the artifact related to the object
1520
# AddTagToCase ({ "type": "AddTagToCase", "tag": "tag to add" }): add a tag to the case related to the object
1621
# MarkAlertAsRead: mark the alert related to the object as read
1722
# AddCustomFields ({"name": "key", "value": "value", "tpe": "type"): add a custom field to the case related to the object
18-
return [self.build_operation("AddTagToCase", tag="test")]
23+
if self.service == "test":
24+
artifacts.append(self.build_operation("AddTagToCase", tag="test"))
25+
return artifacts
1926

2027

2128
if __name__ == "__main__":

0 commit comments

Comments
 (0)