-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcustom-misp
More file actions
179 lines (151 loc) · 6.2 KB
/
custom-misp
File metadata and controls
179 lines (151 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/var/ossec/framework/python/bin/python3
# Integración de la API MISP con Wazuh
import sys
import os
from socket import socket, AF_UNIX, SOCK_DGRAM
import json
import ipaddress
import re
import logging
import requests
# Configuración del registro
log_dir = "/var/ossec/logs/"
log_file = os.path.join(log_dir, "integration.log")
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler(log_file, encoding="utf-8"),
logging.StreamHandler()
]
)
# Configuración del socket
pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
socket_addr = f'{pwd}/queue/sockets/queue'
# Función para limpiar cadenas
def safe_string(value):
if isinstance(value, str):
return value.encode("utf-8", errors="replace").decode("utf-8", errors="replace")
return value
# Función para enviar eventos al socket
def send_event(msg, agent=None):
try:
logging.info("misp enviando evento al socket")
if not agent or agent.get("id") == "000":
string = f'1:misp:{json.dumps(msg)}'
else:
string = (
f'1:[{agent.get("id")}] ({agent.get("name")}) '
f'{agent.get("ip", "any")}->misp:{json.dumps(msg)}'
)
sock = socket(AF_UNIX, SOCK_DGRAM)
sock.connect(socket_addr)
sock.send(string.encode())
sock.close()
except Exception as e:
logging.error(f"misp - Error al enviar el evento: {str(e)}")
# Leer parámetros de configuración
try:
with open(sys.argv[1], encoding="utf-8", errors="replace") as alert_file:
alert = json.load(alert_file)
except (IndexError, FileNotFoundError, json.JSONDecodeError) as e:
logging.error(f"misp - Error al leer el archivo de alerta: {str(e)}")
sys.exit(1)
# Configuración del servidor MISP
misp_base_url = "https://{{IP-MISP}}/attributes/restSearch/"
misp_api_auth_key = "APIKEY"
misp_apicall_headers = {
"Content-Type": "application/json",
"Authorization": misp_api_auth_key,
"Accept": "application/json"
}
# Expresión regular para SHA256
regex_file_hash = re.compile(r'^[a-fA-F0-9]{64}$')
# Función para validar SHA256
def is_valid_sha256(value):
try:
int(value, 16)
return len(value) == 64
except ValueError:
return False
# Procesar eventos de Windows
def process_windows_event(alert):
try:
groups = alert.get("rule", {}).get("groups", [])
if len(groups) > 2:
event_type = groups[2]
else:
logging.error("misp - Estructura inesperada: la lista 'groups' no tiene suficientes elementos.")
return
eventdata = alert.get("data", {}).get("win", {}).get("eventdata", {})
wazuh_event_param = None
# Identificar el tipo de evento
if event_type in ['sysmon_event1', 'sysmon_event6', 'sysmon_event7',
'sysmon_event_15', 'sysmon_event_23', 'sysmon_event_24', 'sysmon_event_25']:
h = eventdata.get("hashes", "")
match = regex_file_hash.search(h)
h2 = str(h).split("=")[1]
logging.info("hash -> "+h2)
#if match:
wazuh_event_param = h2
#else:
# logging.error("misp - No se encontró ningún hash SHA256 válido en los datos del evento.")
# return
elif event_type == 'sysmon_event3' and eventdata.get("destinationIsIpv6") == 'false':
dst_ip = eventdata.get("destinationIp", "")
if dst_ip and ipaddress.ip_address(dst_ip).is_global:
wazuh_event_param = dst_ip
else:
logging.info("misp - La IP de destino no es global o no es válida, se omite.")
return
elif event_type == 'sysmon_event_22':
wazuh_event_param = eventdata.get("queryName", "")
if not wazuh_event_param:
logging.error("No se encontró queryName en los datos del evento.")
return
else:
logging.info("Tipo de evento no compatible, se omite.")
return
# Consultar MISP con el parámetro extraído
misp_search_payload = {"Attribute.value": wazuh_event_param,"Attribute.returnFormat":"json"}
logging.info(misp_search_payload)
try:
response = requests.post(
misp_base_url,
headers=misp_apicall_headers,
json=misp_search_payload,
verify=False # Cambiar a True si tienes un certificado válido
)
response.raise_for_status()
misp_api_response = response.json()
except (requests.exceptions.RequestException, json.JSONDecodeError) as e:
logging.error(f"misp - Error procesando la respuesta de la API MISP: {str(e)}")
alert_output = {"misp": {"error": "misp - Error de conexión o decodificación de la API"}}
send_event(alert_output, alert.get("agent"))
return
# Procesar la respuesta de MISP
if "response" in misp_api_response and "Attribute" in misp_api_response["response"]:
logging.info(misp_api_response)
attributes = misp_api_response["response"]["Attribute"]
if attributes:
alert_output = {
"misp": {
"event_id": attributes[0].get("event_id"),
"category": attributes[0].get("category"),
"value": attributes[0].get("value"),
"type": attributes[0].get("type")
}
}
send_event(alert_output, alert.get("agent"))
else:
logging.info("misp - No se encontraron atributos relevantes en la respuesta de la API.")
logging.info(attributes)
else:
logging.info("misp - No se encontraron atributos en la respuesta de la API MISP.")
except KeyError as e:
logging.error(f"misp - Clave faltante en la estructura de datos de alerta: {str(e)}")
# Determinar la plataforma
if alert.get("rule", {}).get("groups", [])[0] == 'windows':
process_windows_event(alert)
else:
logging.info("misp - Plataforma no compatible, se omite.")