#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""; 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"); }