From 098d11ba47b984e257b2a42b14c9ec5146173cbd Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Mon, 1 Jul 2024 13:12:23 +0200 Subject: [PATCH] new: [app] Added setting diagnostic and brief exercise validation --- ...ion.json.bak => basic-event-creation.json} | 0 ...iltering.json.bak => basic-filtering.json} | 0 config.py | 1 - exercise.py | 25 +++++++++++ exercises/ransomware-exercise.json | 2 +- misp_api.py | 20 +++++++++ notification.py | 5 ++- server.py | 16 +++++-- src/components/TheAdminPanel.vue | 44 ++++++++++++++++--- src/socket.js | 9 ++++ 10 files changed, 110 insertions(+), 12 deletions(-) rename active_exercises/{basic-event-creation.json.bak => basic-event-creation.json} (100%) rename active_exercises/{basic-filtering.json.bak => basic-filtering.json} (100%) diff --git a/active_exercises/basic-event-creation.json.bak b/active_exercises/basic-event-creation.json similarity index 100% rename from active_exercises/basic-event-creation.json.bak rename to active_exercises/basic-event-creation.json diff --git a/active_exercises/basic-filtering.json.bak b/active_exercises/basic-filtering.json similarity index 100% rename from active_exercises/basic-filtering.json.bak rename to active_exercises/basic-filtering.json diff --git a/config.py b/config.py index ff89a46..4cf36a1 100644 --- a/config.py +++ b/config.py @@ -4,7 +4,6 @@ misp_apikey = 'FI4gCRghRZvLVjlLPLTFZ852x2njkkgPSz0zQ3E0' misp_skipssl = True live_logs_accepted_scope = { - 'rest_client_history': '*', 'events': ['add', 'edit', 'delete', 'restSearch',], 'attributes': ['add', 'edit', 'delete', 'restSearch',], 'tags': '*', diff --git a/exercise.py b/exercise.py index 61c2316..e861dff 100644 --- a/exercise.py +++ b/exercise.py @@ -15,6 +15,9 @@ ACTIVE_EXERCISES_DIR = "active_exercises" def load_exercises() -> bool: db.ALL_EXERCISES = read_exercise_dir() + if not is_validate_exercises(db.ALL_EXERCISES): + print('Issue while validating exercises') + return False init_inject_flow() init_exercises_tasks() return True @@ -32,6 +35,28 @@ def read_exercise_dir(): return exercises +def is_validate_exercises(exercises: list) -> bool: + exercises_uuid = set() + tasks_uuid = set() + exercise_by_uuid = {} + task_by_uuid = {} + for exercise in exercises: + e_uuid = exercise['exercise']['uuid'] + if e_uuid in exercises_uuid: + print(f'Duplicated UUID {e_uuid}. ({exercise['exercise']['name']}, {exercise_by_uuid[e_uuid]['exercise']['name']})') + return False + exercises_uuid.add(e_uuid) + exercise_by_uuid[e_uuid] = exercise + for inject in exercise['injects']: + t_uuid = inject['uuid'] + if t_uuid in tasks_uuid: + print(f'Duplicated UUID {t_uuid}. ({inject['name']}, {task_by_uuid[t_uuid]['name']})') + return False + tasks_uuid.add(t_uuid) + task_by_uuid[t_uuid] = inject + return True + + def init_inject_flow(): for exercise in db.ALL_EXERCISES: for inject in exercise['injects']: diff --git a/exercises/ransomware-exercise.json b/exercises/ransomware-exercise.json index cda25c1..209c497 100644 --- a/exercises/ransomware-exercise.json +++ b/exercises/ransomware-exercise.json @@ -14,7 +14,7 @@ "state:production" ], "total_duration": "7200", - "uuid": "29324587-db6c-4a73-a209-cf8c79871629", + "uuid": "eb00428f-40b5-4da7-9402-7ce22a840659", "version": "20240624" }, "inject_flow": [ diff --git a/misp_api.py b/misp_api.py index a2d12b9..261ef40 100644 --- a/misp_api.py +++ b/misp_api.py @@ -44,3 +44,23 @@ def doRestQuery(authkey: str, request_method: str, url: str, payload: dict = {}) return post(url, payload, api_key=authkey) else: return get(url, payload, api_key=authkey) + + +def getSettings() -> Union[None, dict]: + SETTING_TO_QUERY = [ + 'Plugin.ZeroMQ_enable', + 'Plugin.ZeroMQ_audit_notifications_enable', + 'Plugin.ZeroMQ_event_notifications_enable', + 'Plugin.ZeroMQ_attribute_notifications_enable', + 'MISP.log_paranoid', + 'MISP.log_paranoid_skip_db', + 'MISP.log_paranoid_include_post_body', + 'MISP.log_auth', + 'Security.allow_unsafe_cleartext_apikey_logging', + ] + settings = get(f'/servers/serverSettings.json') + if not settings: + return None + return { + setting['setting']: setting['value'] for setting in settings.get('finalSettings', []) if setting['setting'] in SETTING_TO_QUERY + } \ No newline at end of file diff --git a/notification.py b/notification.py index abb8bbd..1a5ee50 100644 --- a/notification.py +++ b/notification.py @@ -41,8 +41,9 @@ def get_user_authkey_id_pair(data: dict): if 'user_id' in data and 'title' in data : if data['title'].startswith('Successful authentication using API key'): authkey_search = re.search(authkey_title_regex, data['title'], re.IGNORECASE) - authkey = authkey_search.group(1) - return (int(data['user_id']), authkey,) + if authkey_search is not None: + authkey = authkey_search.group(1) + return (int(data['user_id']), authkey,) return (None, None,) diff --git a/server.py b/server.py index 2eabae0..4348016 100755 --- a/server.py +++ b/server.py @@ -11,6 +11,7 @@ from eventlet.green import zmq as gzmq import exercise as exercise_model import notification as notification_model import db +import misp_api # Initialize ZeroMQ context and subscriber socket @@ -68,6 +69,10 @@ def mark_task_incomplete(sid, payload): def reset_all_exercise_progress(sid): return exercise_model.resetAllExerciseProgress() +@sio.event +def get_diagnostic(sid): + return getDiagnostic() + @sio.on('*') def any_event(event, sid, data={}): print('>> Unhandled event', event) @@ -114,15 +119,20 @@ def get_context(data: dict) -> dict: return context +def getDiagnostic() -> dict: + misp_settings = misp_api.getSettings() + return { + 'settings': misp_settings, + } + + # Function to forward zmq messages to Socket.IO def forward_zmq_to_socketio(): while True: message = zsocket.recv_string() topic, s, m = message.partition(" ") - handleMessage(topic, s, m) try: - pass - # handleMessage(topic, s, m) + handleMessage(topic, s, m) except Exception as e: print(e) diff --git a/src/components/TheAdminPanel.vue b/src/components/TheAdminPanel.vue index 3fea7a7..9a9202b 100644 --- a/src/components/TheAdminPanel.vue +++ b/src/components/TheAdminPanel.vue @@ -1,8 +1,8 @@