diff --git a/README.md b/README.md index f6300c9..d354899 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,19 @@ _pypykatz_ for MemProcFS exposes mimikatz functionality in the folder `/py/secre 3) Copy the _pypykatz_ for _MemProcFS_ plugin by copying all files from [`/files/plugins/pym_pypykatz`](https://github.com/ufrisk/MemProcFS-plugins/tree/master/files/plugins/pym_pypykatz) to corresponding folder in MemProcFS - overwriting any existing files there. 4) Start MemProcFS. -#### Last updated: 2019-03-17 +## pypykatz regsecrets + +#### Author: +Tamas Jos ([@skelsec](https://twitter.com/SkelSec)) , info@skelsec.com , https://github.com/skelsec/ + +#### Overview: +_regsecrets_ for MemProcFS exposes mimikatz functionality in the folder `/py/regsecrets/` in the file system root provided that the target is a supported Windows system. Functionality includes retrieval NTLM hashes for local accounts amongst other things. +

+ +#### Installation instructions: +1) Ensure MemProcFS supported version of 64-bit Python for Windows is on the system path (or specify in `-pythonpath` option when starting MemProcFS). NB! embedded Python will not work with _pypykatz_ and _aiowinreg_ since it requires access to Python pip installed packages. +2) Install _pypykatz_ and _aiowinreg_ pip package, in correct python environment, by running `pip install pypykatz aiowinreg`. +3) Copy the _pyregsecrets_ for _MemProcFS_ plugin by copying all files from [`/files/plugins/pym_regsecrets`](https://github.com/ufrisk/MemProcFS-plugins/tree/master/files/plugins/pym_regsecrets) to corresponding folder in MemProcFS - overwriting any existing files there. +4) Start MemProcFS. + +#### Last updated: 2019-12-19 diff --git a/files/plugins/pym_regsecrets/__init__.py b/files/plugins/pym_regsecrets/__init__.py new file mode 100644 index 0000000..e5eabee --- /dev/null +++ b/files/plugins/pym_regsecrets/__init__.py @@ -0,0 +1,9 @@ +from plugins.pym_regsecrets.pym_regsecrets import ( + Initialize, + Notify, +) + +__all__ = [ + "Initialize", + "Notify", +] \ No newline at end of file diff --git a/files/plugins/pym_regsecrets/pym_regsecrets.py b/files/plugins/pym_regsecrets/pym_regsecrets.py new file mode 100644 index 0000000..562613d --- /dev/null +++ b/files/plugins/pym_regsecrets/pym_regsecrets.py @@ -0,0 +1,286 @@ +# pym_regsecrets.py +# +# Pypykatz RegSecrets plugin for MemProcFs +# +# https://github.com/skelsec/ +# https://gist.githubusercontent.com/skelsec/617abdc40a29a60edd337177f5dce85a/raw/b11e456acc23a454bd52e649cc42081c8ddd1b32/gistfile1.txt +# +# (c) Tamas Jos, 2019 +# Author: Tamas Jos (@skelsec), info@skelsec.com +# +# adaptation to MemProcFS plugin by: +# (c) Ulf Frisk, 2019 +# Author: Ulf Frisk (@UlfFrisk), pcileech@frizk.net +# + +from vmmpy import * +from vmmpyplugin import * +import traceback + +# globals needed for FS + +is_initialized = False +import_failed = None +parsing_failed = None +result_all = '' +result_sam = '' +result_security = '' +result_software = '' + +import_error_text_template = """ +The imports for pypykatz plugin have failed at some point. +Common causes: + 1. You dont have pypykatz installed. + 2. You dont have the latest versions of pypykatz and/or aiowinreg. + 2. Python runtime environment used by MemProcFs is not the same as you have installed pypykatz in. + 3. You are not using the correct python version. + +Error traceback: +%s +""" + +parsing_error_template = """ +pypykatz plugin tried to parse the registry hives in the memory dump but failed. +This could be caused by multiple things: + 1. The pypykatz's parser code is potato. + 2. MemProcFs could not fully parse the memory, usually this happens with incorrect memory dump files. + +Error traceback: +%s +""" + +import_error_text = None +parsing_error_text = None + +try: + from pypykatz.registry.sam.sam import * + from pypykatz.registry.security.security import * + from pypykatz.registry.system.system import * + from pypykatz.registry.software.software import * + from aiowinreg.hive import AIOWinRegHive + from aiowinreg.filestruct.hbin import NTRegistryHbin + #this needs to be the last line! + import_failed = False + +except Exception as e: + import_failed = True + if VmmPyPlugin_fPrintV: + traceback.print_exc() + import_error_text = import_error_text_template % traceback.format_exc() + pass + + + +class MemProcFS_RegReader: + """ + This class provides buffer-like reader interface which can be delegated to AIOWinreg's HIVE classes. + Emulates reading and seeking capablities of a buffer but actually calling the underlying MemProcFS API. + """ + def __init__(self, va_hive): + self.va_hive = va_hive + self.position = 0 + self.firstread = True + + def read(self, count = -1): + if count < 0: + raise Exception('Cant read negative count') + elif count == 0: + return None + + data = VmmPy_WinReg_HiveRead(self.va_hive, self.position, count, flags = 0) + self.position += count + return data + + def seek(self, count, whence = 0): + if whence == 0: + if count < 0: + raise Exception('whence 0 requires positive values or 0') + self.position = count + elif whence == 1: + self.position += count + elif whence == 2: + raise Exception('Cant seek from the end!') + +def list_hives(): + for x in VmmPy_WinReg_HiveList(): + yield x + + + +def get_hive_va(hive_name, hive_name_short): + for hiveinfo in list_hives(): + if 'name' in hiveinfo and hiveinfo['name'].endswith(hive_name): + return hiveinfo['va_hive'] + for hiveinfo in list_hives(): + if 'name' in hiveinfo and hive_name_short in hiveinfo['name']: + return hiveinfo['va_hive'] + return None + + + +def create_hive(hive_name, hive_name_short): + hive_va = get_hive_va(hive_name, hive_name_short) + reader = MemProcFS_RegReader(hive_va) + hroot = NTRegistryHbin.read(reader) + reader = MemProcFS_RegReader(hive_va) + return AIOWinRegHive(reader, hroot, is_file = False) + + + +def parse_reg(): + global result_all, result_sam, result_security, result_software + + sam_hive = create_hive('SAM-MACHINE_SAM', 'SAM') + security_hive = create_hive('SECURITY-MACHINE_SECURITY', 'SECURITY') + system_hive = create_hive('SYSTEM-MACHINE_SYSTEM', 'SYSTEM') + software_hive = create_hive('SOFTWARE-MACHINE_SOFTWARE', 'SOFTWARE') + + if system_hive is None: + raise Exception('System hive not found! this is mandatory for extracting secrets!') + system = SYSTEM(system_hive) + bootkey = system.get_bootkey() + #input('BootKey: %s' % bootkey.hex()) + + if sam_hive is not None: + sam = SAM(sam_hive, bootkey) + sam.get_secrets() + else: + print('SAM hive not found!') + + if security_hive is not None: + security = SECURITY(security_hive, bootkey) + security.get_secrets() + else: + print('SECURITY hive not found!') + + if software_hive is not None: + software = SOFTWARE(software_hive, bootkey) + software.get_default_logon() + else: + print('SOFTWARE hive not found!') + + result_sam = str(sam) + result_security = str(security) + result_software = str(software) + result_all = result_sam + result_security + result_software + + + +def parse_reg_catch(): + global parsing_failed, parsing_error_text + + try: + parse_reg() + parsing_failed = False + + except Exception as e: + parsing_failed = True + if VmmPyPlugin_fPrintV: + traceback.print_exc() + parsing_error_text = parsing_error_template % (traceback.format_exc()) + pass + + + +def ReadResultFile(pid, file_name, file_attr, bytes_length, bytes_offset): + """ + reads the all_results data as file on the virtual FS + """ + global result_all, result_sam, result_security, result_software + + if file_name == 'all.txt': + return result_all[bytes_offset:bytes_offset+bytes_length].encode() + + if file_name == 'sam.txt': + return result_sam[bytes_offset:bytes_offset+bytes_length].encode() + + if file_name == 'security.txt': + return result_security[bytes_offset:bytes_offset+bytes_length].encode() + + if file_name == 'software.txt': + return result_software[bytes_offset:bytes_offset+bytes_length].encode() + + return None + + + +def ReadErrors(pid, file_name, file_attr, bytes_length, bytes_offset): + try: + + if file_name == 'import_error.txt': + return import_error_text.encode()[bytes_offset:bytes_offset+bytes_length] + if file_name == 'parsing_error.txt': + return parsing_error_text.encode()[bytes_offset:bytes_offset+bytes_length] + + except Exception as e: + if VmmPyPlugin_fPrintV: + traceback.print_exc() + return None + + + +def List(pid, path): + # + # List function - this module employs a dynamic list function - which makes + # it responsible for providing directory listings of its contents in a + # highly optimized way. It is very important that the List function is as + # speedy as possible - to avoid locking up the file system. + # + # First check the directory to be listed. Only the module root directory is + # allowed. If it's not the module root directory return None. + global is_initialized, import_failed, parsing_failed, import_error_text, parsing_error_text + global result_all, result_sam, result_security, result_software + + try: + + if path != 'regsecrets': + return None + + if is_initialized == False: + parse_reg_catch() + is_initialized = True + + if import_failed == True: + print(import_failed) + result = { + 'import_error.txt': {'size': len(import_error_text), 'read': ReadErrors, 'write': None}, + } + return result + + if parsing_failed == True: + result = { + 'parsing_error.txt': {'size': len(parsing_error_text), 'read': ReadErrors, 'write': None}, + } + return result + + if path == 'regsecrets': + result = { + 'all.txt': {'size': len(result_all), 'read': ReadResultFile, 'write': None}, + 'sam.txt': {'size': len(result_sam), 'read': ReadResultFile, 'write': None}, + 'security.txt': {'size': len(result_security), 'read': ReadResultFile, 'write': None}, + 'software.txt': {'size': len(result_software), 'read': ReadResultFile, 'write': None}, + } + return result + + return None + + except Exception as e: + if VmmPyPlugin_fPrintV: + traceback.print_exc() + return None + + + +def Notify(fEvent, bytesData): + if fEvent == VMMPY_PLUGIN_EVENT_TOTALREFRESH and not import_failed and not parsing_failed: + global is_initialized + is_initialized = False + + + +def Initialize(target_system, target_memorymodel): + # Check that the operating system is 32-bit or 64-bit Windows. If it's not + # then raise an exception to terminate loading of this module. + if target_system != VMMPY_SYSTEM_WINDOWS_X64 and target_system != VMMPY_SYSTEM_WINDOWS_X86: + raise RuntimeError("Only Windows is supported by the pym_regsecrets module.") + VmmPyPlugin_FileRegisterDirectory(None, 'regsecrets', List) diff --git a/files/plugins/pym_regsecrets/version.txt b/files/plugins/pym_regsecrets/version.txt new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/files/plugins/pym_regsecrets/version.txt @@ -0,0 +1 @@ +1.0.0 diff --git a/versions.txt b/versions.txt index 53b8d14..51b7019 100644 --- a/versions.txt +++ b/versions.txt @@ -1,2 +1,2 @@ -pluginupdater 1.0.0 pypykatz 1.1.0 +regsecrets 1.0.0