Skip to content

Commit 36a504b

Browse files
authored
Merge pull request #750 from cudeso/main
Synchronise with Microsoft Sentinel or Defender: A wrapper around an existing installation of MISP2Sentinel or MISP2Defender
2 parents 3244fd5 + 0aecbab commit 36a504b

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import json
2+
import subprocess
3+
import os
4+
5+
'''
6+
Synchronise with Microsoft Sentinel or Defender: A wrapper around an existing installation of MISP2Sentinel or MISP2Defender
7+
8+
Calls the script from MISP2Sentinel or MISP2Defender (misp2_script) using the Python virtual environment (misp2_venv)
9+
Uses the event UUID from the MISP event to export the indicators
10+
Preferably run as Ad-Hoc workflow
11+
'''
12+
13+
misperrors = {"error": "Error"}
14+
15+
moduleconfig = {
16+
"params": {
17+
"misp2_venv": {"type": "string", "description": "Where is the MISP2Sentinel or MISP2Defender Python virtual environment?", "value": "/var/www/MISP/misp-custom/misp2sentinel/venv/"},
18+
"misp2_script": {"type": "string", "description": "Where is the MISP2Sentinel or MISP2Defender installation?", "value": "/var/www/MISP/misp-custom/misp2sentinel/script.py"},
19+
},
20+
# Blocking modules break the exection of the current of action
21+
"blocking": False,
22+
# Indicates whether parts of the data passed to this module should be extracted. Extracted data can be found under the `filteredItems` key
23+
"support_filters": True,
24+
# Indicates whether the data passed to this module should be compliant with the MISP core format
25+
"expect_misp_core_format": False,
26+
}
27+
28+
returns = "boolean"
29+
30+
moduleinfo = {
31+
"version": "0.1",
32+
"author": "Koen Van Impe",
33+
"description": "Export indicators to Microsoft Sentinel or Microsoft Defender. Requires an existing installation of MISP2Sentinel or MISP2Defender.",
34+
"module-type": ["action"],
35+
"name": "Export to Sentinel or Defender",
36+
"logo": "",
37+
"requirements": [],
38+
"features": "",
39+
"references": [],
40+
"input": "",
41+
"output": "",
42+
}
43+
44+
45+
def export_to_sentinel(request, event_uuid):
46+
params = request["params"]
47+
misp2_venv = params["misp2_venv"]
48+
misp2_script = params["misp2_script"]
49+
50+
script_dir = os.path.dirname(misp2_script)
51+
python_executable = os.path.join(misp2_venv, "bin", "python")
52+
53+
if not os.path.exists(python_executable):
54+
print(f"Error: Python executable not found at {python_executable}")
55+
return False
56+
57+
if not os.path.exists(misp2_script):
58+
print(f"Error: Script not found at {misp2_script}")
59+
return False
60+
61+
print(f"Exporting event {event_uuid} to Sentinel or Defender...")
62+
print(f"Using Python: {python_executable}")
63+
print(f"Running script: {misp2_script}")
64+
print(f"Working directory: {script_dir}")
65+
66+
try:
67+
result = subprocess.run(
68+
[python_executable, misp2_script, event_uuid],
69+
cwd=script_dir,
70+
capture_output=True,
71+
text=True,
72+
timeout=300
73+
)
74+
75+
if result.returncode == 0:
76+
print(f"Successfully exported event {event_uuid}")
77+
if result.stdout:
78+
print(f"Output: {result.stdout}")
79+
return True
80+
else:
81+
print(f"Export failed with return code {result.returncode}")
82+
if result.stderr:
83+
print(f"Error: {result.stderr}")
84+
if result.stdout:
85+
print(f"Output: {result.stdout}")
86+
return False
87+
88+
except subprocess.TimeoutExpired:
89+
print("Export timed out")
90+
return False
91+
except Exception as e:
92+
print(f"Error executing script: {str(e)}")
93+
return False
94+
95+
96+
def handler(q=False):
97+
if q is False:
98+
return False
99+
100+
request = json.loads(q)
101+
success = False
102+
103+
event_uuid = request.get("data", {}).get("Event", {}).get("uuid")
104+
if event_uuid:
105+
success = export_to_sentinel(request, event_uuid)
106+
else:
107+
print("Error: No event UUID found in request data")
108+
109+
return {"data": success}
110+
111+
112+
def introspection():
113+
modulesetup = {}
114+
try:
115+
modulesetup["config"] = moduleconfig
116+
except NameError:
117+
pass
118+
return modulesetup
119+
120+
121+
def version():
122+
moduleinfo["config"] = moduleconfig
123+
return moduleinfo

0 commit comments

Comments
 (0)