Files
Rublon-SSP/SSP_DLL/rublonSSP.cpp
2025-08-25 08:57:52 +02:00

631 lines
17 KiB
C++

#include "interprocessSSP.h"
#include "connectorSSP.h"
#include "domainUtilsSSP.h"
#include "rublonSSP.h"
#pragma warning(disable:4996)
//#define PACKAGE_NAME "RublonSSP"
void* trampoline = NULL;
BYTE originalBytes[16] = { 0 };
SECPKG_FUNCTION_TABLE Rublon_ssp_SPFunction_Table = {
.LogonUserEx2 = Rublon_ap_SpLogonUserEx2,
.Initialize = Rublon_ssp_SpInitialize,
.Shutdown = Rublon_ssp_SpShutDown,
.GetInfo = Rublon_ssp_SpGetInfo,
.AcceptCredentials = Rublon_ssp_SpAcceptCredentials,
.AcquireCredentialsHandle = Rublon_ssp_SpAcquireCredentialsHandle,
.InitLsaModeContext = Rublon_ssp_SpInitLsaModeContext,
.AcceptLsaModeContext = Rublon_ssp_SpAcceptLsaModeContext,
};
NTSTATUS NTAPI Rublon_ap_SpLogonUserEx2(
PLSA_CLIENT_REQUEST ClientRequest,
SECURITY_LOGON_TYPE LogonType,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferSize,
PVOID* ProfileBuffer,
PULONG ProfileBufferSize,
PLUID LogonId,
PNTSTATUS SubStatus,
PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
PVOID* TokenInformation,
PUNICODE_STRING* AccountName,
PUNICODE_STRING* AuthenticatingAuthority,
PUNICODE_STRING* MachineName,
PSECPKG_PRIMARY_CRED PrimaryCredentials,
PSECPKG_SUPPLEMENTAL_CRED_ARRAY* SupplementalCredentials
)
{
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpLogonUserEx2...",
function_name
);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpInitialize(ULONG_PTR PackageId, PSECPKG_PARAMETERS Parameters, PLSA_SECPKG_FUNCTION_TABLE FunctionTable)
{
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpInitialize...",
function_name
);
HMODULE kerberos_handle = GetModuleHandleW(L"kerberos.dll");
if (kerberos_handle != NULL) {
log_line(LOG_TYPE_DEBUG,
L"[%s] kerberos.dll jest zaladowany...",
function_name);
print_kerberos_module_functions(kerberos_handle);
FARPROC target_func = GetProcAddress(kerberos_handle, "KerbMakeKdcCall");
if (!target_func) {
log_line(LOG_TYPE_WARNING,
L"[%s] nie odnaleziono funkcji %s...",
function_name,
L"KerbMakeKdcCall");
}
Original_KerbMakeKdcCall = (KerbMakeKdcCall_t)target_func;
DWORD oldProtect;
BYTE trampoline[] = {
0x49, 0xBB,
0,0,0,0,0,0,0,0,
0x41, 0xFF, 0xE3
};
void* hook_target = (void*)target_func;
CopyMemory(&trampoline[2], &Hooked_KerbMakeKdcCall, sizeof(void*));
if (VirtualProtect(hook_target, sizeof(trampoline), PAGE_EXECUTE_READWRITE, &oldProtect)) {
CopyMemory(hook_target, trampoline, sizeof(trampoline));
VirtualProtect(hook_target, sizeof(trampoline), oldProtect, &oldProtect);
log_line(LOG_TYPE_DEBUG,
L"[%s] HOOK zainstalowany...",
function_name);
}
}
else {
log_line(LOG_TYPE_WARNING,
L"[%s] kerberos.dll jest niezaladowany...",
function_name);
}
initialize_rdp_sessions_array();
ZeroMemory(remote_interactive_sessions, sizeof(remote_interactive_sessions));
log_line(LOG_TYPE_INFO,
L"[%s] Zerowanie listy sesji RDP...",
function_name
);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpShutDown(void)
{
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
if (domain_info.domain_SID) {
log_line(LOG_TYPE_INFO, L"[%s] %s", function_name,
L"Zwalnianie pamieci Domain SID..."
);
LocalFree(domain_info.domain_SID);
}
if (domain_users) {
HANDLE hHeap = GetProcessHeap();
log_line(LOG_TYPE_INFO, L"[%s] %s", function_name,
L"Zwalnianie pamieci USER_INFO..."
);
HeapFree(hHeap, 0, domain_users);
}
log_line(LOG_TYPE_INFO,
L"[%s] %s%s",
function_name,
L"Zamykanie pliku log i sesji...\n",
L"=================================================================\n"
);
if (log_file) {
CloseHandle(log_file);
log_file = NULL;
}
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpGetInfo(PSecPkgInfoW PackageInfo)
{
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpGetInfo...",
function_name
);
SEC_WCHAR piname[] = L"RublonSSP";
SEC_WCHAR picomment[] = L"Rublon Security Support Provider";
PackageInfo->fCapabilities =
SECPKG_FLAG_INTEGRITY |
SECPKG_FLAG_PRIVACY |
SECPKG_FLAG_CONNECTION |
SECPKG_FLAG_NEGOTIABLE |
SECPKG_FLAG_MULTI_REQUIRED |
SECPKG_FLAG_ACCEPT_WIN32_NAME |
SECPKG_FLAG_LOGON |
SECPKG_FLAG_EXTENDED_ERROR;
PackageInfo->wVersion = 1;
PackageInfo->wRPCID = SECPKG_ID_NONE;
PackageInfo->cbMaxToken = 0;
PackageInfo->Name = piname;
PackageInfo->Comment = picomment;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
{
NTSTATUS result = STATUS_UNSUCCESSFUL;
WCHAR function_name[40] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
if (!g_logfile_lock_initialized) {
init_logfile_lock();
}
if (LogonType == RemoteInteractive) {
PWTS_SESSION_INFO session_info = NULL;
DWORD session_count = 0;
DWORD rdp_session_id = 0;
if (!WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &session_info, &session_count)) {
log_line(LOG_TYPE_ERROR, L"[%s] Blad pobierania sesji WTSEnumerateSessions", function_name);
return STATUS_ACCESS_DENIED;
}
MATCH_SESSION_STATUS stat = SESSION_UNINITALIZED;
for (DWORD i = 0; i < session_count; i++) {
DWORD id = session_info[i].SessionId;
USHORT* protocol = NULL;
DWORD bytesReturned = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, id, WTSClientProtocolType, (LPWSTR*)&protocol, &bytesReturned)) {
if (*protocol == WTS_PROTOCOL_RDP) {
stat = match_existing_rdp_sessions(id, &rdp_session_id);
}
WTSFreeMemory(protocol);
}
}
if (stat == SESSION_CREATE_NEW) {
if (create_new_rdp_session(PrimaryCredentials->UserSid, rdp_session_id))
return STATUS_SUCCESS;
}
if (stat == SESSION_UPDATE_EXISTING) {
if (update_existing_rdp_session(rdp_session_id)) {
}
}
if (stat == SESSION_TERMINATE_EXISTING) {
if (remove_session_from_list(rdp_session_id)) {
}
}
}
PSID rublon_user_2 = convert_sidstring_to_sid();
/*
PCWSTR logon_type_str = L"<NIEZNANY TYP>";
if(LogonType < LOGON_TYPE_COUNT) {
logon_type_str = W_LOGON_TYPE_STRINGS[LogonType];
}
WCHAR sid_string[128] = { 0 };
WCHAR luid_string[128] = { 0 };
check_SID(PrimaryCredentials->UserSid, sid_string, ARRAYSIZE(sid_string));
get_LUID_string(&PrimaryCredentials->LogonId, luid_string, ARRAYSIZE(luid_string));
log_line(LOG_TYPE_INFO,
L"[%s] Logon Type: %s, Logon ID: %s, PSID: %s, Nazwa konta: %s, Nazwa domeny: %s, Nazwa DNS: %s, SupCred->PackageName :%s",
function_name,
logon_type_str,
luid_string,
sid_string,
check_unicode_string(AccountName),
check_unicode_string(&PrimaryCredentials->DomainName),
check_unicode_string(&PrimaryCredentials->DnsDomainName),
check_unicode_string(&SupplementalCredentials->PackageName)
);
if (LogonType == RemoteInteractive) {
//find_remote_domain_user_session();
DWORD session_id = { 0 };
if (find_remote_domain_user_session(PrimaryCredentials->UserSid, AccountName, &session_id) == FIND_SESSION_NOT_FOUND) {
DWORD pid = 0;
WCHAR proc_name[64] = { 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) return 0;
PROCESSENTRY32W pe;
pe.dwSize = sizeof(pe);
if (Process32FirstW(hSnap, &pe)) {
do {
DWORD procSessionId = 0;
if (ProcessIdToSessionId(pe.th32ProcessID, &procSessionId)) {
if (procSessionId == session_id) {
if (CompareStringOrdinal(pe.szExeFile, -1, L"services.exe", -1, TRUE) == CSTR_EQUAL ||
CompareStringOrdinal(pe.szExeFile, -1, L"smss.exe", -1, TRUE) == CSTR_EQUAL ||
CompareStringOrdinal(pe.szExeFile, -1, L"wininit.exe", -1, TRUE) == CSTR_EQUAL ||
CompareStringOrdinal(pe.szExeFile, -1, L"lsass.exe", -1, TRUE) == CSTR_EQUAL ||
CompareStringOrdinal(pe.szExeFile, -1, L"csrss.exe", -1, TRUE) == CSTR_EQUAL)
{
continue;
}
pid = pe.th32ProcessID;
StringCchCopyW(proc_name, 64, pe.szExeFile);
break;
}
}
} while (Process32NextW(hSnap, &pe));
}
log_line(LOG_TYPE_DEBUG,
L"[%s] Skorelowano sesje RDP z procesem: %s, PID: %lu, w sesji: %lu",
function_name,
proc_name,
pid,
session_id
);
CloseHandle(hSnap);
WCHAR wDNS[64] = { 0 };
char DNS[64] = { 0 };
WCHAR wUser[64] = { 0 };
char User[64] = { 0 };
StringCchCopyW(wDNS, 64, PrimaryCredentials->DnsDomainName.Buffer);
WideCharToMultiByte(CP_ACP, 0, wDNS, -1, DNS, 64, NULL, NULL);
StringCchCopyW(wUser, 64, AccountName->Buffer);
WideCharToMultiByte(CP_ACP, 0, wUser, -1, User, 64, NULL, NULL);
char buff[192];
StringCchPrintfA(buff, sizeof(buff), "{\"Domena\":\"%s\",\"Nazwa konta\":\"%s\"}", DNS, User);
result = manage_mfa_session(buff);
if (result != STATUS_SUCCESS) {
//WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE, 999, 1);
log_line(LOG_TYPE_ERROR,
L"[%s] MFA nie powiodlo sie, odrzucanie polaczenia...",
function_name);
log_line(LOG_TYPE_DEBUG,
L"[%s] Ubijanie procesu %lu...",
function_name,
pid
);
WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE, pid, 1);
return STATUS_ACCESS_DENIED;
}
}
}
*/
if (LogonType == Network || LogonType == NetworkCleartext) {
//testowy scenariusz gdy logowanie jest od RublonUser2
if (EqualSid(PrimaryCredentials->UserSid, rublon_user_2)) {
log_line(LOG_TYPE_DEBUG,
L"[%s] PSID sa identyczne",
function_name
);
//test_load_library(L"C:\\AdditionalDLL.dll", L"C:\\rust_ssp_lib.dll");
//retrieve_current_logon_sessions();
//result = manage_mfa_session(u8"{\"organizacja\":\"Rublon\",\"login\":\"Adrian\",\"haslo\":\"bezpieczne_haslo_321\"}");
/*
DWORD pids[32];
DWORD proc_id = get_PID_from_PSID(rublon_user_2, pids, ARRAYSIZE(pids));
log_line(LOG_TYPE_DEBUG,
L"[%s] Odnaleziono %05u PID dla uzytkownika.",
function_name,
proc_id
);
if (proc_id != NULL) {
for(DWORD i = 0; i < proc_id; i++)
list_net_connections_by_PID(pids[i]);
}*/
}
}
LocalFree(rublon_user_2);
return result;
}
NTSTATUS NTAPI Rublon_ssp_SpAcquireCredentialsHandle(
PUNICODE_STRING PrincipalName,
ULONG CredentialUseFlags,
PLUID LogonId,
PVOID AuthorizationData,
PVOID GetKeyFn,
PVOID GetKeyArgument,
PLSA_SEC_HANDLE CredentialHandle,
PTimeStamp ExpirationTime
) {
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpAcquireCredentialsHandle...",
function_name
);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpInitLsaModeContext(
LSA_SEC_HANDLE CredentialHandle,
LSA_SEC_HANDLE ContextHandle,
PUNICODE_STRING TargetName,
ULONG ContextRequirements,
ULONG TargetDataRep,
PSecBufferDesc InputBuffers,
PLSA_SEC_HANDLE NewContextHandle,
PSecBufferDesc OutputBuffers,
PULONG ContextAttributes,
PTimeStamp ExpirationTime,
PBOOLEAN MappedContext,
PSecBuffer ContextData
) {
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpInitLsaModeContext...",
function_name
);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpAcceptLsaModeContext(
LSA_SEC_HANDLE CredentialHandle,
LSA_SEC_HANDLE ContextHandle,
PSecBufferDesc InputBuffer,
ULONG ContextRequirements,
ULONG TargetDataRep,
PLSA_SEC_HANDLE NewContextHandle,
PSecBufferDesc OutputBuffer,
PULONG ContextAttributes,
PTimeStamp ExpirationTime,
PBOOLEAN MappedContext,
PSecBuffer ContextData
) {
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpAcceptLsaModeContext...",
function_name
);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpAcceptSecurityContext(
LSA_SEC_HANDLE CredentialHandle,
LSA_SEC_HANDLE ContextHandle,
PSecBufferDesc InputBuffer,
ULONG ContextRequirements,
ULONG TargetDataRep,
PLSA_SEC_HANDLE NewContextHandle,
PSecBufferDesc OutputBuffer,
PULONG ContextAttributes,
PTimeStamp ExpirationTime,
PBOOLEAN MappedContext,
PSecBuffer ContextData
)
{
if (!InputBuffer || !InputBuffer->pBuffers) return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_SpLsaModeInitialize(_In_ ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE* ppTables, PULONG pcTables)
{
create_log_file(rublon_log_filepath);
WCHAR function_name[64] = { 0 };
MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name));
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano SpLsaModeInitialize...",
function_name
);
// TODO: dodac obsulge co w przypadku fail
// czy odlaczenie dll'ki od procesu?...
HRESULT res = get_domain_info();
if (SUCCEEDED(res)) {
domain_info.initialized = TRUE;
log_line(LOG_TYPE_INFO,
L"[%s] Status maszyny: Nazwa DNS domeny: %s, Nazwa NetBIOS: %s, Czy w domenie: %s, Czy kontroler domeny: %s",
function_name,
domain_info.DNS_domain_name,
domain_info.NetBIOS_name,
(domain_info.is_machine_domain_joined) ? L"TAK" : L"NIE",
(domain_info.is_domain_controller) ? L"TAK" : L"NIE"
);
}
else if (res == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) {
log_line(LOG_TYPE_WARNING,
L"[%s] RPC niedostepny, uruchamiam monitor...",
function_name);
if (InterlockedCompareExchange(&domain_monitor_thread_counter, 1, 0) == 0) {
HANDLE hThread = CreateThread(NULL, 0, run_dc_monitor, NULL, 0, NULL);
if (hThread) CloseHandle(hThread);
}
}
else {
log_line(LOG_TYPE_ERROR,
L"[%s] Nie mozna pobrac danych do ustalenia statusu DC: 0x%08X",
function_name,
res);
}
*PackageVersion = SECPKG_INTERFACE_VERSION;
// *ppTables = Rublon_ssp_SecPkgFunctionTable;
// *pcTables = ARRAYSIZE(Rublon_ssp_SecPkgFunctionTable);
*ppTables = &Rublon_ssp_SPFunction_Table;
*pcTables = 1;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_LsaApInitializePackage(
ULONG AuthenticationPackageId,
PLSA_DISPATCH_TABLE LsaDispatchTable,
PSTRING Database,
PSTRING Confidentiality,
PSTRING* PackageName
) {
/*
static STRING name = { sizeof(PACKAGE_NAME) - 2, sizeof(PACKAGE_NAME), (PCHAR)PACKAGE_NAME };
*PackageName = &name;
send_to_interprocess_pipe("[LSA] Wywolano LsaApInitializePackage...\n");
*/
return STATUS_SUCCESS;
}
NTSTATUS NTAPI Rublon_ssp_LsaApLogonUser(
PLSA_CLIENT_REQUEST ClientRequest,
SECURITY_LOGON_TYPE LogonType,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProfileBuffer,
PULONG ProfileBufferLength,
PLUID LogonId,
PNTSTATUS SubStatus,
PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
PVOID* TokenInformation,
PLSA_UNICODE_STRING* AccountName,
PLSA_UNICODE_STRING* AuthenticatingAuthority
) {
send_to_interprocess_pipe("[LSA] Wywolano LsaApLogonUser...\n");
*SubStatus = 0;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS NTAPI Rublon_ssp_LsaApLogonUserEx(
PLSA_CLIENT_REQUEST ClientRequest,
SECURITY_LOGON_TYPE LogonType,
PVOID ProtocolSubmitBuffer,
PVOID* ProfileBuffer,
PULONG ProfileBufferLength,
PLUID LogonId,
PNTSTATUS SubStatus,
PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
PVOID* TokenInformation,
PUNICODE_STRING* AccountName,
PUNICODE_STRING* AuthenticatingAuthority
)
{
WCHAR logLine[MAX_LOG_LINE] = { 0 };
char logonTypeStr[64];
wsprintfA(logonTypeStr, "LogonType = %d", LogonType);
return STATUS_SUCCESS;
}
NTSTATUS WINAPI Hooked_KerbMakeKdcCall(PVOID a, PVOID b, PVOID c) {
log_line(LOG_TYPE_INFO,
L"[%s] Wywolano shookowany KerbMakeKdcCall...",
L"HOOK"
);
// jakakolwiek logika dzialania...
return Original_KerbMakeKdcCall(a, b, c);
}
void HookFunction_x64(void* targetFunc, void* hookFunc) {
DWORD oldProtect;
memcpy(originalBytes, targetFunc, 12);
trampoline = VirtualAlloc(NULL, 32, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!trampoline) {
printf("VirtualAlloc failed\n");
return;
}
memcpy(trampoline, originalBytes, 12);
BYTE* tramp = (BYTE*)trampoline;
uintptr_t origFuncRest = (uintptr_t)targetFunc + 12;
tramp[12] = 0xE9;
INT32 relOffset = (INT32)(origFuncRest - ((uintptr_t)tramp + 12 + 5));
memcpy(tramp + 13, &relOffset, sizeof(relOffset));
VirtualProtect(targetFunc, 12, PAGE_EXECUTE_READWRITE, &oldProtect);
BYTE patch[12];
patch[0] = 0x48;
patch[1] = 0xB8;
uintptr_t hookAddr = (uintptr_t)hookFunc;
memcpy(patch + 2, &hookAddr, sizeof(hookAddr));
patch[10] = 0xFF;
patch[11] = 0xE0;
memcpy(targetFunc, patch, 12);
VirtualProtect(targetFunc, 12, oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), targetFunc, 12);
Original_KerbMakeKdcCall = (KerbMakeKdcCall_t)trampoline;
printf("Hook zainstalowany pod adresem: %p\n", targetFunc);
}
void UnhookFunction_x64(void* targetFunc) {
DWORD oldProtect;
VirtualProtect(targetFunc, 12, PAGE_EXECUTE_READWRITE, &oldProtect);
CopyMemory(targetFunc, originalBytes, 12);
VirtualProtect(targetFunc, 12, oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), targetFunc, 12);
if (trampoline) {
VirtualFree(trampoline, 0, MEM_RELEASE);
trampoline = NULL;
}
printf("Hook usuniety\n");
}