From 307984caf042f118a7c12e062482b3c3d09ee8a3 Mon Sep 17 00:00:00 2001 From: adrian Date: Mon, 25 Aug 2025 08:57:52 +0200 Subject: [PATCH] Add project files. --- SSP_DLL.sln | 31 ++ SSP_DLL/SSP_DLL.vcxproj | 170 ++++++ SSP_DLL/SSP_DLL.vcxproj.filters | 62 +++ SSP_DLL/connectorSSP.cpp | 178 ++++++ SSP_DLL/connectorSSP.h | 18 + SSP_DLL/domainUtilsSSP.cpp | 199 +++++++ SSP_DLL/domainUtilsSSP.h | 30 + SSP_DLL/interprocessSSP.cpp | 952 ++++++++++++++++++++++++++++++++ SSP_DLL/interprocessSSP.h | 115 ++++ SSP_DLL/kerberos_lib.h | 2 + SSP_DLL/main.h | 37 ++ SSP_DLL/rublonLSA.cpp | 0 SSP_DLL/rublonSSP.cpp | 630 +++++++++++++++++++++ SSP_DLL/rublonSSP.h | 147 +++++ SSP_DLL/rublonssp.def | 15 + SSP_DLL/utilsSSP.cpp | 247 +++++++++ SSP_DLL/utilsSSP.h | 60 ++ 17 files changed, 2893 insertions(+) create mode 100644 SSP_DLL.sln create mode 100644 SSP_DLL/SSP_DLL.vcxproj create mode 100644 SSP_DLL/SSP_DLL.vcxproj.filters create mode 100644 SSP_DLL/connectorSSP.cpp create mode 100644 SSP_DLL/connectorSSP.h create mode 100644 SSP_DLL/domainUtilsSSP.cpp create mode 100644 SSP_DLL/domainUtilsSSP.h create mode 100644 SSP_DLL/interprocessSSP.cpp create mode 100644 SSP_DLL/interprocessSSP.h create mode 100644 SSP_DLL/kerberos_lib.h create mode 100644 SSP_DLL/main.h create mode 100644 SSP_DLL/rublonLSA.cpp create mode 100644 SSP_DLL/rublonSSP.cpp create mode 100644 SSP_DLL/rublonSSP.h create mode 100644 SSP_DLL/rublonssp.def create mode 100644 SSP_DLL/utilsSSP.cpp create mode 100644 SSP_DLL/utilsSSP.h diff --git a/SSP_DLL.sln b/SSP_DLL.sln new file mode 100644 index 0000000..52d3eee --- /dev/null +++ b/SSP_DLL.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36121.58 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SSP_DLL", "SSP_DLL\SSP_DLL.vcxproj", "{409AFE33-D438-4590-8F91-2C0C83113FE5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Debug|x64.ActiveCfg = Debug|x64 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Debug|x64.Build.0 = Debug|x64 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Debug|x86.ActiveCfg = Debug|Win32 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Debug|x86.Build.0 = Debug|Win32 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Release|x64.ActiveCfg = Release|x64 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Release|x64.Build.0 = Release|x64 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Release|x86.ActiveCfg = Release|Win32 + {409AFE33-D438-4590-8F91-2C0C83113FE5}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {971508A5-D2BE-4254-BCAA-3B0E44B7E633} + EndGlobalSection +EndGlobal diff --git a/SSP_DLL/SSP_DLL.vcxproj b/SSP_DLL/SSP_DLL.vcxproj new file mode 100644 index 0000000..082a45a --- /dev/null +++ b/SSP_DLL/SSP_DLL.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {409afe33-d438-4590-8f91-2c0c83113fe5} + SSPDLL + 10.0 + RublonSSP + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;SSPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;SSPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + _DEBUG;SSPDLL_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + NotUsing + + + stdcpp20 + + + Console + true + false + iphlpapi.lib;ws2_32.lib;winhttp.lib;Secur32.lib;%(AdditionalDependencies) + rublonssp.def + + + + + Level3 + true + true + true + NDEBUG;SSPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + + + MultiThreaded + false + stdcpp20 + + + Windows + true + false + rublonssp.def + iphlpapi.lib;ws2_32.lib;winhttp.lib;Secur32.lib;WtsApi32.lib;Netapi32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SSP_DLL/SSP_DLL.vcxproj.filters b/SSP_DLL/SSP_DLL.vcxproj.filters new file mode 100644 index 0000000..06ee9f5 --- /dev/null +++ b/SSP_DLL/SSP_DLL.vcxproj.filters @@ -0,0 +1,62 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/SSP_DLL/connectorSSP.cpp b/SSP_DLL/connectorSSP.cpp new file mode 100644 index 0000000..1dd95cf --- /dev/null +++ b/SSP_DLL/connectorSSP.cpp @@ -0,0 +1,178 @@ +#include "connectorSSP.h" + +NTSTATUS manage_mfa_session(const char *json_data) { + NTSTATUS mfa_status = STATUS_UNSUCCESSFUL; + HINTERNET http_session = NULL; + HINTERNET http_connect = NULL; + HINTERNET http_request = NULL; + + DWORD http_status = 0; + + if (open_http_connection(&http_session, &http_connect, &http_request, + mfa_server_ip, mfa_server_destination_port, web_api_endpoint)) { + if (handle_http_traffic(&http_request, json_data, &http_status)) { + BYTE* http_response = NULL; + DWORD http_response_size = 0; + if (process_received_data(&http_request, &http_response, &http_response_size)) { + int wide_http_response_size = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)http_response, http_response_size, NULL, 0); + if (wide_http_response_size > 0) { + LPWSTR wide_http_response = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, wide_http_response_size * sizeof(wchar_t)); + if (wide_http_response) { + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)http_response, http_response_size, wide_http_response, wide_http_response_size); + log_line(LOG_TYPE_INFO, L" -> Odpowiedz z serwera MFA: %s", wide_http_response); + HeapFree(GetProcessHeap(), 0, wide_http_response); + } + } + HeapFree(GetProcessHeap(), 0, http_response); + } + else { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w odczytywaniu odpowiedzi HTTP", L"process_received_data"); + } + } + else { + WinHttpCloseHandle(http_request); + WinHttpCloseHandle(http_connect); + WinHttpCloseHandle(http_session); + } + if (http_status == 200) + mfa_status = STATUS_SUCCESS; + } + + if(http_request) WinHttpCloseHandle(http_request); + if(http_connect) WinHttpCloseHandle(http_connect); + if(http_session) WinHttpCloseHandle(http_session); + + return mfa_status; +} + +BOOL open_http_connection(HINTERNET *session_handle, HINTERNET *connection_handle, HINTERNET *request_handle, + LPCWSTR ip, INTERNET_PORT port, LPCWSTR web_api_path) { + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + *session_handle = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + + if (!*session_handle) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpOpen: %lu", function_name, GetLastError()); + return FALSE; + } + + *connection_handle = WinHttpConnect(*session_handle, ip, port, 0); + if (!*connection_handle) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpConnect: %lu", function_name, GetLastError()); + WinHttpCloseHandle(*session_handle); + return FALSE; + } + + *request_handle = WinHttpOpenRequest(*connection_handle, L"POST", web_api_path, NULL, + WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + + if (!*request_handle) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpOpenRequest: %lu", function_name, GetLastError()); + WinHttpCloseHandle(*connection_handle); + WinHttpCloseHandle(*session_handle); + return FALSE; + } + + if (!WinHttpAddRequestHeaders(*request_handle, L"Content-Type: application/json; charset=utf-8\r\n", + -1, WINHTTP_ADDREQ_FLAG_ADD)) { + log_line(LOG_TYPE_WARNING, L"[%s] Blad w WinHttpAddRequestHeaders: %lu", function_name, GetLastError()); + } + return TRUE; +} + +BOOL handle_http_traffic(HINTERNET *request_handle, const char *json_data, DWORD *status) { + DWORD json_length = (DWORD)strlen(json_data); + + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + if (!WinHttpSendRequest(*request_handle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, + (LPVOID)json_data, json_length, json_length, 0)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpSendRequest: %lu", function_name, GetLastError()); + return false; + } + + if (!WinHttpReceiveResponse(*request_handle, NULL)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpReceiveResponse: %lu", function_name, GetLastError()); + return false; + } + + DWORD statusCode = 0; + DWORD size = sizeof(statusCode); + if (WinHttpQueryHeaders(*request_handle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &statusCode, &size, WINHTTP_NO_HEADER_INDEX)) { + *status = statusCode; + log_line(LOG_TYPE_DEBUG, L"[%s] status HTTP: %lu", function_name, statusCode); + } + else { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpQueryHeaders: %lu", function_name, GetLastError()); + return FALSE; + } + return TRUE; +} + +BOOL process_received_data(HINTERNET *request_handle, BYTE** response_data, DWORD* response_size) { + BYTE* buffer = NULL; + DWORD totalSize = 0; + + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + while (true) { + DWORD available = 0; + if (!WinHttpQueryDataAvailable(*request_handle, &available)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpQueryDataAvailable: %lu", function_name, GetLastError()); + break; + } + log_line(LOG_TYPE_DEBUG, L"[%s] Dostepne bajty: %lu", function_name, available); + if (available == 0) { + break; + } + + BYTE* temp = NULL; + if (buffer == NULL) { + temp = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalSize + available); + } + else { + temp = (BYTE*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, totalSize + available); + } + if (!temp) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w HeapRealloc\\Alloc", function_name); + if (buffer) HeapFree(GetProcessHeap(), 0, buffer); + buffer = NULL; + break; + } + + buffer = temp; + //printf("Buffer resized: total size now %lu\n", totalSize + available); + //log_line(LOG_TYPE_DEBUG, L"[%s] Zmiana rozmiaru bufora, calkowity rozmiar po zmianie: %lu", function_name, totalSize + available); + + DWORD bytesRead = 0; + if (WinHttpReadData(*request_handle, buffer + totalSize, available, &bytesRead)) { + //log_line(LOG_TYPE_DEBUG, L"[%s] Odczytano bajtow: %lu", function_name, bytesRead); + totalSize += bytesRead; + } + else { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w WinHttpReadData: %lu", function_name, GetLastError()); + if (buffer) HeapFree(GetProcessHeap(), 0, buffer); + buffer = NULL; + break; + } + } + bool success = (buffer != NULL && totalSize > 0); + const wchar_t* success_string = success ? L"SUCCESS" : L"FAIL"; + log_line(LOG_TYPE_DEBUG, L"[%s] Status odczytywania: %s, odczytano lacznie: %lu bajtow", function_name, success_string, totalSize); + if (success) { + *response_data = buffer; + *response_size = totalSize; + } + else { + if (buffer) + HeapFree(GetProcessHeap(), 0, buffer); + } + + return success; +} \ No newline at end of file diff --git a/SSP_DLL/connectorSSP.h b/SSP_DLL/connectorSSP.h new file mode 100644 index 0000000..73ad181 --- /dev/null +++ b/SSP_DLL/connectorSSP.h @@ -0,0 +1,18 @@ +#pragma once + +#include "utilsSSP.h" + +#include + +constexpr LPCWSTR mfa_server_ip = L"192.168.56.104"; +constexpr INTERNET_PORT mfa_server_destination_port = 8080; +constexpr LPCWSTR web_api_endpoint = L"/connect"; + +NTSTATUS manage_mfa_session(const char* json_data); + +BOOL open_http_connection(HINTERNET* session_handle, HINTERNET* connection_handle, HINTERNET* request_handle, + LPCWSTR ip, INTERNET_PORT port, LPCWSTR web_api_path); + +BOOL handle_http_traffic(HINTERNET* request_handle, const char* json_data, DWORD* status); + +BOOL process_received_data(HINTERNET* request_handle, BYTE** responseData, DWORD* responseSize); \ No newline at end of file diff --git a/SSP_DLL/domainUtilsSSP.cpp b/SSP_DLL/domainUtilsSSP.cpp new file mode 100644 index 0000000..bf4891f --- /dev/null +++ b/SSP_DLL/domainUtilsSSP.cpp @@ -0,0 +1,199 @@ +#include "domainUtilsSSP.h" + +#include "utilsSSP.h" + +DOMAIN_INFO domain_info = { 0 }; + +USER_INFO* domain_users = NULL; + +LONG domain_monitor_thread_counter = 0; + + +HRESULT get_domain_info() { + DSROLE_PRIMARY_DOMAIN_INFO_BASIC* domain_role_info = NULL; + + DWORD status = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE*)&domain_role_info); + if (status == ERROR_SUCCESS) { + domain_info.is_domain_controller = (domain_role_info->MachineRole == DsRole_RolePrimaryDomainController || + domain_role_info->MachineRole == DsRole_RoleBackupDomainController); + domain_info.is_machine_domain_joined = (domain_role_info->MachineRole != DsRole_RoleStandaloneWorkstation && + domain_role_info->MachineRole != DsRole_RoleStandaloneServer); + StringCchCopyW(domain_info.NetBIOS_name, ARRAYSIZE(domain_info.NetBIOS_name), domain_role_info->DomainNameFlat); + StringCchCopyW(domain_info.DNS_domain_name, ARRAYSIZE(domain_info.DNS_domain_name), domain_role_info->DomainNameDns); + DsRoleFreeMemory(domain_role_info); + } + else { + return HRESULT_FROM_WIN32(status); + } + + SID_NAME_USE pe_use; + BYTE sid_buffer[SECURITY_MAX_SID_SIZE] = { 0 }; + DWORD sid_size = sizeof(sid_buffer); + WCHAR referenced_domain[MAX_PATH]; + DWORD domain_size = ARRAYSIZE(referenced_domain); + + if (!LookupAccountNameW(NULL, domain_info.DNS_domain_name, sid_buffer, &sid_size, + referenced_domain, &domain_size, &pe_use + )) { + DWORD err = GetLastError(); + log_line(LOG_TYPE_ERROR, L"[%s] Blad LookupAccountNameW, kod bledu: %lu", L"get_domain_info", GetLastError()); + return HRESULT_FROM_WIN32(err); + } + + DWORD len = GetLengthSid(sid_buffer); + domain_info.domain_SID = (PSID)LocalAlloc(LMEM_FIXED, len); + if (!domain_info.domain_SID) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad alokacji pamieci dla SID", L"get_domain_info"); + return E_OUTOFMEMORY; + } + if (!CopySid(len, domain_info.domain_SID, sid_buffer)) { + DWORD err = GetLastError(); + LocalFree(domain_info.domain_SID); + domain_info.domain_SID = NULL; + log_line(LOG_TYPE_ERROR, L"[%s] Blad w kopiowaniu SID", L"get_domain_info"); + return HRESULT_FROM_WIN32(err); + } + return S_OK; +} + +HRESULT get_domain_users() { + DWORD total_users = 0; + DWORD read = 0; + + WCHAR function_name[] = L"get_domain_users"; + + NET_API_STATUS status = NetUserEnum( + NULL, 0, FILTER_NORMAL_ACCOUNT, + NULL, 0, &read, &total_users, NULL + ); + if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad NetUserEnum, kod bledu: %lu", function_name, status); + return HRESULT_FROM_WIN32(status); + } + if (total_users == 0) { + log_line(LOG_TYPE_WARNING, L"[%s] Nie odnaleziono uzytkownikow domeny...", function_name); + return S_OK; + } + + HANDLE hHeap = GetProcessHeap(); + domain_users = (USER_INFO*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(USER_INFO) * total_users); + if (!domain_users) + { + log_line(LOG_TYPE_ERROR, L"[%s] Blad alokacji pamieci dla USER_INFO", function_name); + return E_OUTOFMEMORY; + } + + USER_INFO_0* user_info_buff = NULL; + DWORD resume = 0, read_sec = 0, total_users_sec = 0; + DWORD user_index = 0; + int regular_users = 0; + int system_users = 0; + + DWORD start = GetTickCount(); + + do + { + status = NetUserEnum(NULL, 0, FILTER_NORMAL_ACCOUNT, (LPBYTE*)&user_info_buff, + MAX_PREFERRED_LENGTH, &read_sec, &total_users_sec, &resume + ); + + if ((status == NERR_Success || status == ERROR_MORE_DATA) && user_info_buff) + { + for (DWORD i = 0; i < read_sec && user_index < total_users; ++i) + { + LPCWSTR name = user_info_buff[i].usri0_name; + + BYTE sidBuffer[512]; + DWORD sidSize = sizeof(sidBuffer); + WCHAR domain[256]; + DWORD domainSize = ARRAYSIZE(domain); + SID_NAME_USE sidType; + + if (LookupAccountNameW(NULL, name, sidBuffer, &sidSize, domain, &domainSize, &sidType)) + { + DWORD rid = *GetSidSubAuthority((PSID)sidBuffer, *GetSidSubAuthorityCount((PSID)sidBuffer) - 1); + domain_users[user_index].user_rid = rid; + (rid < 1000) ? ++system_users : ++regular_users; + + StringCchCopyW(domain_users[user_index].user_name, ARRAYSIZE(domain_users[user_index].user_name), name); + ++user_index; + } + } + + NetApiBufferFree(user_info_buff); + user_info_buff = NULL; + } + + } while (status == ERROR_MORE_DATA && user_index < total_users_sec); + + DWORD totalTime = GetTickCount() - start; + log_line(LOG_TYPE_INFO, + L"[%s] Pobrano informacje o uzytkownikach domenowych: Uzytkownikow regularnych: %d, uzytkownikow systemowych: %d, czas wykonania: %.2f s.", + function_name, + regular_users, + system_users, + totalTime / 1000.0); + + return S_OK; +} + +DWORD WINAPI run_dc_monitor(LPVOID) { + const DWORD maxRetries = 30; + const DWORD retryDelayMs = 1000; + + WCHAR function_name[] = L"DomainMonitor"; + + log_line(LOG_TYPE_INFO, + L"[%s] Start monitora gotowosci domeny...", + function_name + ); + + DWORD start = GetTickCount(); + + for (DWORD i = 0; i < maxRetries; ++i) { + HRESULT res = get_domain_info(); + if (SUCCEEDED(res)) { + LPWSTR sid_string = NULL; + if (!ConvertSidToStringSidW(domain_info.domain_SID, &sid_string)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w konwersji SID", function_name); + } + LocalFree(sid_string); + + DWORD elapsed_ms = GetTickCount() - start; + log_line(LOG_TYPE_INFO, + L"[%s] Informacje o domenie gotowe po %.2f s", + function_name, + elapsed_ms / 1000.0); + + log_line(LOG_TYPE_INFO, + L"[%s] Status maszyny -- Nazwa DNS domeny: %s, Nazwa NetBIOS: %s, PSID domeny: %s, Czy w domenie: %s, Czy kontroler domeny: %s", + function_name, + domain_info.DNS_domain_name, + domain_info.NetBIOS_name, + sid_string, + (domain_info.is_machine_domain_joined) ? L"TAK" : L"NIE", + (domain_info.is_domain_controller) ? L"TAK" : L"NIE" + ); + + domain_info.initialized = TRUE; + + return 0; + } + + if (res != HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) { + log_line(LOG_TYPE_ERROR, + L"[%s] Nie mozna pobrac danych do ustalenia statusu DC: 0x%08X", + function_name, + res); + return 1; + } + Sleep(retryDelayMs); + } + + DWORD totalTime = GetTickCount() - start; + log_line(LOG_TYPE_WARNING, + L"[%s] Timeout — nie pobrano danych o domenie po %lu ms.", + function_name, + totalTime); + return 2; +} \ No newline at end of file diff --git a/SSP_DLL/domainUtilsSSP.h b/SSP_DLL/domainUtilsSSP.h new file mode 100644 index 0000000..e1d2bdb --- /dev/null +++ b/SSP_DLL/domainUtilsSSP.h @@ -0,0 +1,30 @@ +#pragma once + +#include "main.h" + +#include +#include +#include + +typedef struct _DOMAIN_INFO { + BOOL initialized; + BOOL is_machine_domain_joined; + BOOL is_domain_controller; + PSID domain_SID; + WCHAR DNS_domain_name[256]; + WCHAR NetBIOS_name[64]; +} DOMAIN_INFO; + +typedef struct _USER_INFO { + DWORD user_rid; + WCHAR user_name[256]; +} USER_INFO; + +extern DOMAIN_INFO domain_info; +extern USER_INFO* domain_users; +extern LONG domain_monitor_thread_counter; + +DWORD WINAPI run_dc_monitor(LPVOID); + +HRESULT get_domain_info(); +HRESULT get_domain_users(); \ No newline at end of file diff --git a/SSP_DLL/interprocessSSP.cpp b/SSP_DLL/interprocessSSP.cpp new file mode 100644 index 0000000..3df446d --- /dev/null +++ b/SSP_DLL/interprocessSSP.cpp @@ -0,0 +1,952 @@ +#include "interprocessSSP.h" +#include "connectorSSP.h" + +EXISTING_RDP_SESSION remote_interactive_sessions[MAX_RDP_SESSIONS] = { 0 }; + +RDP_SESSION_ARRAY rdp_sessions = { 0 }; + + +PSID convert_sidstring_to_sid(LPCWSTR sid_str) { + PSID p_sid = NULL; + if (!ConvertStringSidToSidW(sid_str, &p_sid)) { + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + log_line(LOG_TYPE_WARNING, + L"[%s] Blad ConvertStringSidToSidW: %lu", function_name, GetLastError() + ); + return NULL; + } + return p_sid; +} + +void get_LUID_string(const PLUID luid, PWSTR out, size_t out_len) { + if (!luid) { + StringCchCopyW(out, out_len, L""); + return; + } + StringCchPrintfW(out, out_len, L"%08x-%08x", luid->HighPart, luid->LowPart); +} + +BOOL get_PIDs_from_sessionID(DWORD in_session_id, RELATED_PROCESSES *session_processes, BOOL update_flag) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad CreateToolhelp32Snapshot", function_name); + return FALSE; + } + + PROCESSENTRY32W pe; + pe.dwSize = sizeof(pe); + + if (Process32FirstW(hSnap, &pe)) { + do { + /* + * w przypadku gdy procesow jest wiecej niz 5 + * zrob realloc - powieksz 2 razy, powinno wystarczyc + */ + if (session_processes->count >= INITIAL_PROCESSES_COUNT) { + RELATED_PROCESS* new_processes = (RELATED_PROCESS*)HeapReAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + session_processes->process, + INITIAL_PROCESSES_COUNT * 2 * sizeof(RELATED_PROCESS)); + + if (!new_processes) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w HeapReAlloc", function_name); + return FALSE; + } + session_processes->process = new_processes; + } + DWORD procSessionId = 0; + if (ProcessIdToSessionId(pe.th32ProcessID, &procSessionId)) { + if (procSessionId == in_session_id) { + // jesli PID jest jednym z istotnych procesow systemowych - NIE UBIJAJ + 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; + } + if (update_flag) { + for (DWORD i = 0; i < session_processes->count; i++) { + if (CompareStringOrdinal(pe.szExeFile, -1, + session_processes->process[session_processes->count].process_name, + -1, TRUE) == CSTR_EQUAL && + session_processes->process[session_processes->count].pid == pe.th32ProcessID) + { + log_line(LOG_TYPE_DEBUG, + L"[%s] Dla sesji ID = %lu, proces = %s, PID = %lu. juz istnieje...", + function_name, + session_processes->process[session_processes->count].process_name, + session_processes->process[session_processes->count].pid + ); + continue; + } + session_processes->process[session_processes->count].pid = pe.th32ProcessID; + session_processes->process[session_processes->count].pid; + StringCchCopyW(session_processes->process[session_processes->count].process_name, + ARRAYSIZE(session_processes->process[session_processes->count].process_name), + pe.szExeFile); + log_line(LOG_TYPE_DEBUG, + L"[%s] Wykryto dodatkowy proces dla sesji = %s, PID = %lu.", + function_name, + session_processes->process[session_processes->count].process_name, + session_processes->process[session_processes->count].pid + ); + session_processes->count++; + } + + } + else { + session_processes->process[session_processes->count].pid = pe.th32ProcessID; + session_processes->process[session_processes->count].pid; + StringCchCopyW(session_processes->process[session_processes->count].process_name, + ARRAYSIZE(session_processes->process[session_processes->count].process_name), + pe.szExeFile); + log_line(LOG_TYPE_DEBUG, + L"[%s] Wykryto proces dla sesji = %s, PID = %lu.", + function_name, + session_processes->process[session_processes->count].process_name, + session_processes->process[session_processes->count].pid + ); + session_processes->count++; + } + } + } + } while (Process32NextW(hSnap, &pe)); + } + + return TRUE; +} + +BOOL get_PID_from_SessionID(DWORD in_session_id, DWORD *pid, WCHAR *pid_exe_name) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + DWORD processes_count = 0; + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad CreateToolhelp32Snapshot", function_name); + return FALSE; + } + + PROCESSENTRY32W pe; + pe.dwSize = sizeof(pe); + + if (Process32FirstW(hSnap, &pe)) { + do { + DWORD procSessionId = 0; + if (ProcessIdToSessionId(pe.th32ProcessID, &procSessionId)) { + if (procSessionId == in_session_id) { + // jesli PID jest jednym z istotnych procesow systemowych - NIE UBIJAJ + 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(pid_exe_name, 64, pe.szExeFile); + processes_count++; + break; + } + } + } while (Process32NextW(hSnap, &pe)); + } + if (processes_count > 1) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Odnaleziono %lu procesow.", + function_name, + processes_count + ); + } + log_line(LOG_TYPE_DEBUG, + L"[%s] Skorelowano sesje RDP z procesem: %s, PID: %lu, ID sesji RDP: %lu", + function_name, + pid_exe_name, + *pid, + in_session_id + ); + return TRUE; +} +/* +FIND_SESSION_STATUS find_remote_domain_user_session(PSID user_sid, PUNICODE_STRING domain_username, DWORD *out_session_id) { + PWTS_SESSION_INFO session_info = NULL; + DWORD session_count = 0; + + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + 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 FIND_SESSION_ERROR; + } + + BOOL is_rdp_session_empty = TRUE; + for (int i = 0; i < MAX_RDP_SESSIONS; i++) { + if (remote_interactive_sessions[i].active) { + is_rdp_session_empty = FALSE; + } + } + WCHAR sid_string[128] = { 0 }; + check_SID(user_sid, sid_string, ARRAYSIZE(sid_string)); + + if (!is_rdp_session_empty) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Wykryto istniejace sesje RDP...", function_name); + for (int i = 0; i < MAX_RDP_SESSIONS; i++) { + if (compare_unicode_with_wchar(domain_username, remote_interactive_sessions[i].domain_username) + && wcscmp(sid_string, remote_interactive_sessions[i].user_sid) == 0) + { + + for (DWORD j = 0; j < session_count; j++) { + DWORD session_Id = session_info[j].SessionId; + USHORT* protocol = NULL; + DWORD bytesReturned = 0; + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientProtocolType, (LPWSTR*)&protocol, &bytesReturned)) { + if (*protocol == WTS_PROTOCOL_RDP) { + + WTS_CLIENT_ADDRESS* address_ptr = NULL; + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientAddress, (LPWSTR*)&address_ptr, &bytesReturned)) { + + WCHAR client_ip[INET_ADDRSTRLEN] = { 0 }; + + struct sockaddr_in sa; + ZeroMemory(&sa, sizeof(sa)); + sa.sin_family = AF_INET; + CopyMemory(&sa.sin_addr, &address_ptr->Address[2], 4); + + if (!InetNtopW(AF_INET, &sa.sin_addr, client_ip, INET_ADDRSTRLEN)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad konwersji IP w InetNtopW", function_name); + WTSFreeMemory(address_ptr); + WTSFreeMemory(protocol); + return FIND_SESSION_ERROR; + } + /* + log_line(LOG_TYPE_DEBUG, + L"[%s] Przed konwersja IP...", function_name); + + + if (wcscmp(client_ip, remote_interactive_sessions[i].ip_address) != 0) { + WTSFreeMemory(address_ptr); + WTSFreeMemory(protocol); + return FIND_SESSION_ERROR; + } + /*log_line(LOG_TYPE_DEBUG, + L"[%s] Po konwersji IP...", function_name); + + WCHAR user_name[64] = { 0 }; + PWTSCLIENTW pClient = NULL; + DWORD bytes = 0; + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientInfo, (LPWSTR*)&pClient, &bytes) && pClient) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Dla konta: %s, z IP: %s, SID: %s juz istnieje zapoczatkowana sesja RDP!", + function_name, + pClient->UserName, + client_ip, + sid_string); + WTSFreeMemory(pClient); + } + WTSFreeMemory(address_ptr); + WTSFreeMemory(protocol); + + return FIND_SESSION_FOUND; + } + } + WTSFreeMemory(protocol); + } + } + } + } + } + + for (DWORD i = 0; i < session_count; i++) { + DWORD session_Id = session_info[i].SessionId; + + USHORT* protocol = NULL; + DWORD bytesReturned = 0; + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientProtocolType, (LPWSTR*)&protocol, &bytesReturned)) { + if (*protocol == WTS_PROTOCOL_RDP) { + LPWSTR data_buffer = NULL; + + WCHAR user_name[64] = { 0 }; + WCHAR domain_name[64] = { 0 }; + WCHAR client_name[64] = { 0 }; + WCHAR protocol_type[16] = { 0 }; + WCHAR client_ip[INET_ADDRSTRLEN] = { 0 }; + + WTS_CLIENT_ADDRESS* address_ptr = NULL; + + copy_lpwstr_string(remote_protocol_type_to_string(*protocol), protocol_type, ARRAYSIZE(protocol_type)); + + retrieve_session_data(session_Id, WTSUserName, user_name, ARRAYSIZE(user_name)); + retrieve_session_data(session_Id, WTSDomainName, domain_name, ARRAYSIZE(domain_name)); + retrieve_session_data(session_Id, WTSClientName, client_name, ARRAYSIZE(client_name)); + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientAddress, (LPWSTR*)&address_ptr, &bytesReturned)) { + if (address_ptr->AddressFamily == AF_INET) { + struct sockaddr_in sa; + ZeroMemory(&sa, sizeof(sa)); + sa.sin_family = AF_INET; + CopyMemory(&sa.sin_addr, &address_ptr->Address[2], 4); + + if (!InetNtopW(AF_INET, &sa.sin_addr, client_ip, INET_ADDRSTRLEN)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad konwersji IP w InetNtopW", function_name); + WTSFreeMemory(protocol); + WTSFreeMemory(address_ptr); + return FIND_SESSION_ERROR; + } + } + WTSFreeMemory(address_ptr); + } + + PWTSCLIENTW pClient = NULL; + DWORD bytes = 0; + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_Id, WTSClientInfo, (LPWSTR*)&pClient, &bytes) && pClient) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Przechwycono sesje RemoteInteractive: Nazwa konta: %s, Domena: %s, Nazwa maszyny: %s, IP: %s, Protokol: %s", + function_name, + pClient->UserName, + pClient->Domain, + pClient->ClientName, + client_ip, + protocol_type); + } + + for (int i = 0; i < MAX_RDP_SESSIONS; i++) { + if (!remote_interactive_sessions[i].active) { + remote_interactive_sessions[i].active = TRUE; + StringCchCopyW(remote_interactive_sessions[i].user_sid, ARRAYSIZE(remote_interactive_sessions[i].user_sid), sid_string); + StringCchCopyW(remote_interactive_sessions[i].domain_username, ARRAYSIZE(remote_interactive_sessions[i].domain_username), pClient->UserName); + StringCchCopyW(remote_interactive_sessions[i].ip_address, ARRAYSIZE(remote_interactive_sessions[i].ip_address), client_ip); + + log_line(LOG_TYPE_DEBUG, L"[%s] Dodano sesje RDP do kolejki... Dane sesji: User SID: %s, Nazwa konta: %s, IP: %s", + function_name, + remote_interactive_sessions[i].user_sid, + remote_interactive_sessions[i].domain_username, + remote_interactive_sessions[i].ip_address); + WTSFreeMemory(pClient); + WTSFreeMemory(protocol); + WTSFreeMemory(session_info); + + *out_session_id = session_Id; + + return FIND_SESSION_NOT_FOUND; + } + } + WTSFreeMemory(pClient); + } + WTSFreeMemory(protocol); + } + } + WTSFreeMemory(session_info); + return FIND_SESSION_ERROR; +} +*/ +BOOL retrieve_session_data(DWORD session_id, WTS_INFO_CLASS info, WCHAR* out_buff, size_t out_size) { + LPWSTR data_buffer = NULL; + DWORD bytes_returned = 0; + + if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, info, &data_buffer, &bytes_returned)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad przy pozyskiwaniu WTS_INFO_CLASS, kod: %lu...", + L"retrieve_session_data", + DWORD(info)); + return FALSE; + } + + if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, info, &data_buffer, &bytes_returned)) { + if (data_buffer != NULL && bytes_returned > sizeof(WCHAR)) { + copy_lpwstr_string(data_buffer, out_buff, out_size); + } + else { + copy_lpwstr_string((LPWSTR)NULL, out_buff, out_size); + } + WTSFreeMemory(data_buffer); + return TRUE; + } + + copy_lpwstr_string((LPWSTR)NULL, out_buff, out_size); + return TRUE; +} + +BOOL convert_ip_addr_to_string(WTS_CLIENT_ADDRESS *ip, WCHAR *ip_data) { + if (ip->AddressFamily == AF_INET) { + struct sockaddr_in sa; + ZeroMemory(&sa, sizeof(sa)); + sa.sin_family = AF_INET; + CopyMemory(&sa.sin_addr, &ip->Address[2], 4); + + if (!InetNtopW(AF_INET, &sa.sin_addr, ip_data, INET_ADDRSTRLEN)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad konwersji IP w InetNtopW", L"convert_ip_addr_to_string"); + return FALSE; + } + } + else { + WCHAR buffer[512] = { 0 }; + WCHAR temp[8]; + + for (int i = 0; i < 20; i++) { + StringCchPrintfW(temp, ARRAYSIZE(temp), L"%02X ", ip->Address[i]); + StringCchCatW(buffer, ARRAYSIZE(buffer), temp); + } + + log_line(LOG_TYPE_WARNING, L"[%s] Nieobslugiwany format adresu, kod: %lu, zawartosc addressFamily: %s...", + L"convert_ip_addr_to_string", + ip->AddressFamily, + buffer); + return FALSE; + } + return TRUE; +} + + +void print_kerberos_module_functions(HMODULE kerberos_module) { + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + BYTE* base_address = (BYTE*)kerberos_module; + IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)base_address; + + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) + return; + + IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(base_address + dos_header->e_lfanew); + if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) + return; + + IMAGE_DATA_DIRECTORY exportDir = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (exportDir.VirtualAddress == 0) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Brak eksportow w kerberos.dll", + function_name + ); + return; + } + IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)(base_address + exportDir.VirtualAddress); + + DWORD* namesRVA = (DWORD*)(base_address + exportDirectory->AddressOfNames); + WORD* ordinals = (WORD*)(base_address + exportDirectory->AddressOfNameOrdinals); + DWORD* functions = (DWORD*)(base_address + exportDirectory->AddressOfFunctions); + + log_line(LOG_TYPE_DEBUG, + L"[%s] Lista eksportowanych funkcji w kerberos.dll: ", + function_name + ); + + for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) { + char* funcName = (char*)(base_address + namesRVA[i]); + + WCHAR funcNameW[256]; + MultiByteToWideChar(CP_ACP, 0, funcName, -1, funcNameW, ARRAYSIZE(funcNameW)); + + WORD ordinal = ordinals[i]; + DWORD funcRVA = functions[ordinal]; + void* funcAddress = base_address + funcRVA; + + log_line(LOG_TYPE_DEBUG, + L"[%s] %s at ordinal %d, adres: %p", + function_name, + funcNameW, + ordinal + exportDirectory->Base, + funcAddress + ); + } +} + +void test_load_library(LPCWSTR dll_name, LPCWSTR rust_library) { + HMODULE h_lib = LoadLibraryW(dll_name); + if (h_lib) { + log_line(LOG_TYPE_INFO, + L"[%s] Zaladowano modul DLL %s", + L"test_load_library", + dll_name + ); + typedef int (*PFN_Run)(); + PFN_Run pRun = (PFN_Run)GetProcAddress(h_lib, "Run"); + if (pRun) { + int result = pRun(); + log_line(LOG_TYPE_INFO, + L"[%s]rezultat z zaladowanej DLL: %d", + L"test_load_library", + result + ); + } + FreeLibrary(h_lib); + } + else { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w LoadLibraryW: %lu", L"test_load_library", GetLastError()); + } + HMODULE h_rust_lib = LoadLibraryW(rust_library); + + if (h_rust_lib) { + log_line(LOG_TYPE_INFO, + L"[%s] Zaladowano DLL stworzona w Rust %s", + L"test_load_library", + rust_library + ); + typedef int (*PFN_Run)(); + PFN_Run rust_run = (PFN_Run)GetProcAddress(h_rust_lib, "Run"); + if (rust_run) { + int result = rust_run(); + log_line(LOG_TYPE_INFO, + L"[%s]rezultat z biblioteki w Rust: %d", + L"test_load_library", + result + ); + } + FreeLibrary(h_rust_lib); + } + else { + log_line(LOG_TYPE_ERROR, L"[%s] Blad w LoadLibraryW dla biblioteki Rust: %lu", L"test_load_library", GetLastError()); + } +} + + +BOOL initialize_rdp_sessions_array() { + rdp_sessions.session_data = (RDP_SESSION_DATA*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + INITIAL_RDP_SESSIONS * sizeof(RDP_SESSION_DATA)); + + if (!rdp_sessions.session_data) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad alokacji pamieci dla sesji RDP", L"initialize_rdp_sessions_array"); + return FALSE; + } + + rdp_sessions.session_count = 0; + rdp_sessions.capacity = INITIAL_RDP_SESSIONS; + + log_line(LOG_TYPE_INFO, L"[%s] Poprawnie zaalokowano pamiec dla sesji RDP...", L"initialize_rdp_sessions_array"); + + return TRUE; +} + +void free_rdp_sessions_array() { + if (rdp_sessions.session_data) { + if (rdp_sessions.session_data->processes) { + HeapFree(GetProcessHeap(), 0, rdp_sessions.session_data->processes); + log_line(LOG_TYPE_INFO, L"[%s] Zwalnianie pamieci po sesjach RDP - procesy...", L"free_rdp_sessions_array"); + } + HeapFree(GetProcessHeap(), 0, rdp_sessions.session_data); + log_line(LOG_TYPE_INFO, L"[%s] Zwalnianie pamieci po sesjach RDP...", L"free_rdp_sessions_array"); + } + ZeroMemory(&rdp_sessions, sizeof(rdp_sessions)); +} + +MATCH_SESSION_STATUS match_existing_rdp_sessions(DWORD in_session_id, DWORD *out_session_id) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + log_line(LOG_TYPE_INFO, + L"[%s] ilosc sesji RDP = %lu", + function_name, + rdp_sessions.session_count); + + if (rdp_sessions.session_count == 0) { + //utworz nowa sesje + log_line(LOG_TYPE_INFO, + L"[%s] Wykryto nowa sesje RDP - Brak aktywnych sesji RDP uzytkownikow domenowych, dodawanie nowej...", + function_name); + *out_session_id = in_session_id; + + return SESSION_CREATE_NEW; + } + if (rdp_sessions.session_count != 0) { + for (DWORD i = 0; i < rdp_sessions.session_count; i++) { + RDP_SESSION_DATA* sess = &rdp_sessions.session_data[i]; + + /* + * w przypadku gdy id sesji zgadza sie z juz istniejaca : + * sprawdz czy jest valid - jesli jest valid, to znaczy ze MFA + * zostalo we wczesniejszej zaakceptowane i zaktualizuj proces wazny dla sesji RDP + * jesli nie zostalo zaakceptowane - ubij procesy + */ + + if (sess->session_id == in_session_id) { + *out_session_id = sess->session_id; + if (sess->valid) { + log_line(LOG_TYPE_INFO, + L"[%s] Wykryto istniejaca sesje RDP, ID sesji = %lu, aktualizacja stanu polaczenia...", + function_name, + in_session_id); + return SESSION_UPDATE_EXISTING; + } + else { + /* + DWORD pid = 0; + WCHAR proc_name[128] = { 0 }; + + DWORD processes_count = 0; + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad CreateToolhelp32Snapshot", function_name); + //return FALSE; + } + + PROCESSENTRY32W pe; + pe.dwSize = sizeof(pe); + + if (Process32FirstW(hSnap, &pe)) { + do { + DWORD procSessionId = 0; + if (ProcessIdToSessionId(pe.th32ProcessID, &procSessionId)) { + if (procSessionId == in_session_id) { + // jesli PID jest jednym z istotnych procesow systemowych - NIE UBIJAJ + 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; + } + //processes_count++; + log_line(LOG_TYPE_DEBUG, + L"[%s] Odnaleziono proces: %s, PID: %lu", + function_name, + pe.szExeFile, + pe.th32ProcessID + ); + } + } + } while (Process32NextW(hSnap, &pe)); + } + if (processes_count > 1) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Odnaleziono %lu procesow.", + function_name, + processes_count + ); + } + */ + log_line(LOG_TYPE_INFO, + L"[%s] Sesja RDP ID = %lu juz istnieje i zostala odrzucona...", + function_name, + in_session_id); + return SESSION_TERMINATE_EXISTING; + } + } + } + } + log_line(LOG_TYPE_ERROR, + L"[%s] Wystapil blad sesji RDP, ID sesji: %lu, sesja o nieznanym statusie...", + function_name, + in_session_id); + return SESSION_STATUS_UNKNOWN; +} + +BOOL create_new_rdp_session(PSID user_psid, DWORD session_id) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + RDP_SESSION_DATA new_session = { 0 }; + + new_session.processes = (RELATED_PROCESSES*)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(RELATED_PROCESSES)); + + if (!new_session.processes) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad alokacji pamieci dla sesji RDP - alokacja danych procesu", function_name); + return FALSE; + } + + new_session.processes->process = (RELATED_PROCESS*)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + INITIAL_PROCESSES_COUNT * sizeof(RELATED_PROCESS)); + if (!new_session.processes->process) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad alokacji pamieci dla sesji RDP - alokacja danych PID", function_name); + HeapFree(GetProcessHeap(), 0, new_session.processes); + return FALSE; + } + new_session.processes->count = 0; + + //log_line(LOG_TYPE_DEBUG, L"[%s] processes ptr: %p", function_name, new_session.processes); + //log_line(LOG_TYPE_DEBUG, L"[%s] processes->process ptr: %p", function_name, new_session.processes->process); + //log_line(LOG_TYPE_DEBUG, L"[%s] proc_name ptr: %p", function_name, proc_name); + + if (!retrieve_rdp_session_info(session_id, &new_session, user_psid)) { + log_line(LOG_TYPE_ERROR, + L"[%s] Nie utworzono nowej sesji RDP...", + function_name); + return FALSE; + } + + //zinkrementuj licznik sesji + rdp_sessions.session_count++; + + log_line(LOG_TYPE_INFO, + L"[%s] Przechwycono sesje %s -- SID konta: %s, IP maszyny: %s, Nazwa konta: %s, Nazwa DNS: %s, Nazwa klienta: %s, ID sesji: %lu", + function_name, + L"RemoteInteractive", + new_session.user_sid, + new_session.client_ip, + new_session.user_name, + new_session.domain_name, + new_session.client_name, + new_session.session_id + ); + + /* + * dane z sesji uzyskane - teraz czas na mfa + * najpierw przygotuj bufor JSON do wyslania do serwera + */ + + char buff[192] = { 0 }; + format_data_for_connection(new_session.session_id, buff); + NTSTATUS mfa_result = manage_mfa_session(buff); + + /* + * dalsza obsluga sesji zalezy od rezultatu mfa + * jesli nastapi zaakceptowanie polaczenia - ustaw flage valid na true + * ponadto - dodaj informacje o procesie ktory kontroluje RDP + * jesli nastapi odrzucenie w mfa - ustaw flage valid na false i ubij polaczenie i nie dodawaj sesji do listy + * kazdy status inny niz STATUS_SUCCESS (mozliwe jest np. zerwanie polaczenia w trakcie negocjacji tcp, blad w http, itp. + * powoduje zamkniecie sesji) + */ + + if (mfa_result != STATUS_SUCCESS) { + log_line(LOG_TYPE_ERROR, + L"[%s] MFA nie powiodlo sie, odrzucanie polaczenia...", + function_name); + new_session.valid = FALSE; + /* + if (get_PIDs_from_sessionID(session_id, new_session.processes, FALSE)) { + //terminate_remaining_processes(new_session.processes, session_id); + }*/ + } else { + log_line(LOG_TYPE_ERROR, + L"[%s] MFA zaakceptowane, procedowanie polaczenia...", + function_name); + new_session.valid = TRUE; + } + + if (get_PIDs_from_sessionID(session_id, new_session.processes, FALSE)) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Dodano procesy zwiazane z sesja RDP...", + function_name + ); + } + /* + * Procesowanie sesji, dodaj sesje do listy + */ + if (add_session_to_list(&new_session)) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Dodano poprawnie sesje do listy, ID sesji RDP = %lu...", + function_name, + new_session.session_id + ); + } + + return TRUE; +} + +BOOL update_existing_rdp_session(DWORD session_id) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + for (DWORD i = 0; i < rdp_sessions.session_count; i++) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Liczba sesji RDP: %lu", + function_name, + rdp_sessions.session_count + ); + RDP_SESSION_DATA* sess = &rdp_sessions.session_data[i]; + if (sess->session_id == session_id) { + /* + * sprawdzam czy dla sesji sa juz zarejestrowane procesy + */ + + if (get_PIDs_from_sessionID(session_id, sess->processes, TRUE)) + { + + } + + if (!sess->valid) { + terminate_remaining_processes(sess->processes, session_id); + } + } + } + return TRUE; +} + +BOOL terminate_remaining_processes(RELATED_PROCESSES* session_processes, DWORD sess_id) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + /* + * zakoncz procesy dla danej sesji + */ + if (session_processes->count != 0) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Konczenie procesow dla sesji o ID = %lu, ilosc procesow: %lu", + function_name, + sess_id, + session_processes->count + ); + for (DWORD i = 0; i < session_processes->count; i++) { + RELATED_PROCESS proc = session_processes->process[i]; + DWORD proc_id = proc.pid; + if (WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE, proc_id, 1)) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Zakonczono - %s -> PID: %lu", + function_name, + proc.process_name, + proc_id + ); + } + else { + log_line(LOG_TYPE_ERROR, + L"[%s] Blad WTSTerminateProcess...", + function_name + ); + return FALSE; + } + } + } + else { + log_line(LOG_TYPE_DEBUG, + L"[%s] Nie odnaleziono procesow dla sesji RDP o ID = %lu", + function_name + ); + return FALSE; + } + return TRUE; +} + +BOOL add_session_to_list(const RDP_SESSION_DATA *session) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + if (!rdp_sessions.session_data) { + log_line(LOG_TYPE_ERROR, + L"[%s] Blad w dostepie do listy sesji RDP...", + function_name); + return FALSE; + } + if (rdp_sessions.session_count >= rdp_sessions.capacity) { + DWORD new_capacity = rdp_sessions.capacity * 2; + RDP_SESSION_DATA* resized = (RDP_SESSION_DATA*)HeapReAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + rdp_sessions.session_data, + new_capacity * sizeof(RDP_SESSION_DATA)); + if (!resized) { + log_line(LOG_TYPE_ERROR, + L"[%s] Nie udalo sie zrealokowac pamieci, blad HeapReAlloc...", + function_name); + return FALSE; + } + + rdp_sessions.session_data = resized; + rdp_sessions.capacity = new_capacity; + } + + rdp_sessions.session_data[rdp_sessions.session_count++] = *session; + + return TRUE; +} + +BOOL remove_session_from_list(DWORD sess_id) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + for (DWORD i = 0; i < rdp_sessions.session_count; i++) { + RDP_SESSION_DATA* sess = &rdp_sessions.session_data[i]; + if (sess->session_id == sess_id) { + log_line(LOG_TYPE_DEBUG, + L"[%s] Usuwanie sesji RDP: %lu z listy --> PSID: %s, IP: %s, Nazwa konta: %s...", + function_name, + sess_id, + sess->user_sid, + sess->client_ip, + sess->domain_name + ); + if (!terminate_remaining_processes(sess->processes, sess_id)) { + return FALSE; + } + + /* + * procesy ubite, wyczysc dane po sesji + */ + if (sess->processes) { + if (sess->processes->process) { + log_line(LOG_TYPE_DEBUG, L"[%s] Wyczyszczono sess->processes->process...", function_name); + HeapFree(GetProcessHeap(), 0, sess->processes->process); + } + log_line(LOG_TYPE_DEBUG, L"[%s] Wyczyszczono sess->processes...", function_name); + HeapFree(GetProcessHeap(), 0, sess->processes); + } + + rdp_sessions.session_count--; + break; + } + } + return TRUE; +} + +BOOL retrieve_rdp_session_info(DWORD session_id, RDP_SESSION_DATA *session_data, PSID user_psid) { + WCHAR function_name[40] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + if (!session_data) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad przy pozyskiwaniu danych nowej sesji RDP...", function_name); + return FALSE; + } + //ZeroMemory(session_data, sizeof(RDP_SESSION_DATA)); + + DWORD bytesReturned = 0; + + session_data->session_id = session_id; + + session_data->protocol_type = WTS_PROTOCOL_RDP; + + check_SID(user_psid, session_data->user_sid, ARRAYSIZE(session_data->user_sid)); + + if (!retrieve_session_data(session_id, WTSUserName, session_data->user_name, ARRAYSIZE(session_data->user_name))) + return FALSE; + + if (!retrieve_session_data(session_id, WTSDomainName, session_data->domain_name, ARRAYSIZE(session_data->domain_name))) + return FALSE; + + if (!retrieve_session_data(session_id, WTSClientName, session_data->client_name, ARRAYSIZE(session_data->client_name))) + return FALSE; + + WTS_CLIENT_ADDRESS* address_ptr = NULL; + if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSClientAddress, (LPWSTR*)&address_ptr, &bytesReturned)) { + log_line(LOG_TYPE_ERROR, L"[%s] Blad przy pozyskiwaniu adresu IP...", function_name); + return FALSE; + } + + if (!convert_ip_addr_to_string(address_ptr, session_data->client_ip)) + return FALSE; + + + //kiedys trzeba dodac szersza obsluge Console + + return TRUE; +} + +void format_data_for_connection(DWORD session_id, char *buffer) { + char dns[64] = { 0 }; + char user[64] = { 0 }; + for (DWORD i = 0; i < rdp_sessions.session_count; i++) { + RDP_SESSION_DATA* sess = &rdp_sessions.session_data[i]; + if (sess->session_id == session_id) { + WideCharToMultiByte(CP_UTF8, 0, sess->domain_name, -1, dns, sizeof(dns), NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, sess->user_name, -1, user, sizeof(user), NULL, NULL); + } + } + StringCchPrintfA(buffer, 192, "{\"Domena\":\"%s\",\"Nazwa konta\":\"%s\"}", dns, user); +} \ No newline at end of file diff --git a/SSP_DLL/interprocessSSP.h b/SSP_DLL/interprocessSSP.h new file mode 100644 index 0000000..ee2a029 --- /dev/null +++ b/SSP_DLL/interprocessSSP.h @@ -0,0 +1,115 @@ +#include "main.h" + +#include "utilsSSP.h" + +#include +#include + +#include + +#define WTSUserSid ((WTS_INFO_CLASS)29) + +const int INITIAL_RDP_SESSIONS = 4; +const int INITIAL_PROCESSES_COUNT = 5; + +typedef struct { + BOOL active; + WCHAR user_sid[128]; + WCHAR ip_address[INET_ADDRSTRLEN]; + WCHAR domain_username[64]; +} EXISTING_RDP_SESSION; + +typedef enum _FIND_SESSION_STATUS { + FIND_SESSION_ERROR = -1, + FIND_SESSION_NOT_FOUND = 0, + FIND_SESSION_FOUND = 1 +} FIND_SESSION_STATUS; + +typedef enum _MATCH_SESSION_STATUS { + SESSION_CREATE_NEW = 0, + SESSION_UPDATE_EXISTING = 1, + SESSION_TERMINATE_EXISTING = 2, + + SESSION_STATUS_UNKNOWN = 98, + SESSION_UNINITALIZED = 99 +} MATCH_SESSION_STATUS; + +typedef struct _RELATED_PROCESS { + DWORD pid; + WCHAR process_name[128]; +} RELATED_PROCESS; + +typedef struct _RELATED_PROCESSES { + RELATED_PROCESS* process; + DWORD count; +} RELATED_PROCESSES; + +typedef struct _RDP_SESSION_DATA { + DWORD session_id; + WCHAR user_name[64]; + WCHAR user_sid[128]; + WCHAR domain_name[64]; + WCHAR client_name[64]; + WCHAR client_ip[INET_ADDRSTRLEN]; + USHORT protocol_type; + BOOL valid; //w przypadku gdy MFA zostanie odrzucone ustaw na FALSE + RELATED_PROCESSES* processes; +} RDP_SESSION_DATA; + +typedef struct _RDP_SESSION_ARRAY { + RDP_SESSION_DATA* session_data; + DWORD capacity; + DWORD session_count; +} RDP_SESSION_ARRAY; + +extern RDP_SESSION_ARRAY rdp_sessions; + + +const int MAX_RDP_SESSIONS = 16; +extern EXISTING_RDP_SESSION remote_interactive_sessions[MAX_RDP_SESSIONS]; + + + +const LPCWSTR RublonUser2 = L"S-1-5-21-1865802264-3486384077-2187269939-1109"; // tylko do celow testowych - RublonUser2 + +PSID convert_sidstring_to_sid(LPCWSTR sid_str = RublonUser2); + +void get_LUID_string(const PLUID luid, PWSTR out, size_t out_len); + +BOOL get_PIDs_from_sessionID(DWORD in_session_id, RELATED_PROCESSES* session_processes, BOOL update_flag); + +BOOL get_PID_from_SessionID(DWORD in_session_id, DWORD* pid, WCHAR* pid_exe_name); + +/* RDP SESSIONS */ + +// do celow testowych +//FIND_SESSION_STATUS find_remote_domain_user_session(PSID user_sid, PUNICODE_STRING domain_username, DWORD* out_session_id); + +BOOL retrieve_session_data(DWORD session_id, WTS_INFO_CLASS info, WCHAR* out_buff, size_t out_size); +//RDP SESSIONS + + +void print_kerberos_module_functions(HMODULE kerberos_module); + +void test_load_library(LPCWSTR dll_name, LPCWSTR rust_library); + +BOOL initialize_rdp_sessions_array(); +void free_rdp_sessions_array(); + +BOOL create_new_rdp_session(PSID user_psid, DWORD session_id); + +BOOL update_existing_rdp_session(DWORD session_id); + +BOOL terminate_remaining_processes(RELATED_PROCESSES* session_processes, DWORD sess_id); + +BOOL add_session_to_list(const RDP_SESSION_DATA* session); + +BOOL remove_session_from_list(DWORD sess_id); + +MATCH_SESSION_STATUS match_existing_rdp_sessions(DWORD in_session_id, DWORD *out_session_id); + +BOOL retrieve_rdp_session_info(DWORD session_id, RDP_SESSION_DATA* session_data, PSID user_psid); + +BOOL convert_ip_addr_to_string(WTS_CLIENT_ADDRESS* ip, WCHAR* ip_data); + +void format_data_for_connection(DWORD session_id, char* buffer); \ No newline at end of file diff --git a/SSP_DLL/kerberos_lib.h b/SSP_DLL/kerberos_lib.h new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/SSP_DLL/kerberos_lib.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/SSP_DLL/main.h b/SSP_DLL/main.h new file mode 100644 index 0000000..04fda97 --- /dev/null +++ b/SSP_DLL/main.h @@ -0,0 +1,37 @@ +#pragma once +/* +* =========== UWAGA !!!! ================= +* POD ZADNYM POZOREM NIE ZMIENIAC KOLEJNOSCI NAGLOWKOW ANI DEFINICJI MAKR +* MA TO KLUCZOWE ZNACZENIE PODCZAS BUDOWANIA BIBLIOTEKI +* +*/ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ + +#include +#include + +#include +#define SECURITY_WIN32 +#define CINTERFACE +#define COBJMACROS + +typedef long NTSTATUS; + +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +//#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) + +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) + +#include +#include +#include + +#include +#include + +/***/ \ No newline at end of file diff --git a/SSP_DLL/rublonLSA.cpp b/SSP_DLL/rublonLSA.cpp new file mode 100644 index 0000000..e69de29 diff --git a/SSP_DLL/rublonSSP.cpp b/SSP_DLL/rublonSSP.cpp new file mode 100644 index 0000000..4e870da --- /dev/null +++ b/SSP_DLL/rublonSSP.cpp @@ -0,0 +1,630 @@ +#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"); +} + diff --git a/SSP_DLL/rublonSSP.h b/SSP_DLL/rublonSSP.h new file mode 100644 index 0000000..3916a51 --- /dev/null +++ b/SSP_DLL/rublonSSP.h @@ -0,0 +1,147 @@ +#include "utilsSSP.h" + +typedef NTSTATUS(WINAPI* KerbMakeKdcCall_t)(PVOID a, PVOID b, PVOID c); + +KerbMakeKdcCall_t Original_KerbMakeKdcCall = NULL; + +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 +); + + +NTSTATUS NTAPI Rublon_ssp_SpLsaModeInitialize( + ULONG LsaVersion, + PULONG PackageVersion, + PSECPKG_FUNCTION_TABLE* ppTables, + PULONG pcTables +); + +NTSTATUS NTAPI Rublon_ssp_SpInitialize( + ULONG_PTR PackageId, + PSECPKG_PARAMETERS Parameters, + PLSA_SECPKG_FUNCTION_TABLE FunctionTable +); + +NTSTATUS NTAPI Rublon_ssp_SpGetInfo( + PSecPkgInfoW PackageInfo +); + +NTSTATUS NTAPI Rublon_ssp_SpShutDown( + void +); + +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 +); + +NTSTATUS NTAPI Rublon_ssp_SpAcceptCredentials( + SECURITY_LOGON_TYPE LogonType, + PUNICODE_STRING AccountName, + PSECPKG_PRIMARY_CRED PrimaryCredentials, + PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials +); + +NTSTATUS NTAPI Rublon_ssp_SpAcquireCredentialsHandle( + PUNICODE_STRING PrincipalName, + ULONG CredentialUseFlags, + PLUID LogonId, + PVOID AuthorizationData, + PVOID GetKeyFn, + PVOID GetKeyArgument, + PLSA_SEC_HANDLE CredentialHandle, + PTimeStamp ExpirationTime +); + +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 +); + +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 +); + +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 +); + +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 +); + +NTSTATUS NTAPI Rublon_ssp_LsaApInitializePackage( + ULONG AuthenticationPackageId, + PLSA_DISPATCH_TABLE LsaDispatchTable, + PSTRING Database, + PSTRING Confidentiality, + PSTRING* PackageName +); + +NTSTATUS WINAPI Hooked_KerbMakeKdcCall(PVOID a, PVOID b, PVOID c); \ No newline at end of file diff --git a/SSP_DLL/rublonssp.def b/SSP_DLL/rublonssp.def new file mode 100644 index 0000000..f8f9965 --- /dev/null +++ b/SSP_DLL/rublonssp.def @@ -0,0 +1,15 @@ +LIBRARY "RublonSSP" +EXPORTS + SpLsaModeInitialize = Rublon_ssp_SpLsaModeInitialize + SpInitialize = Rublon_ssp_SpInitialize + SpGetInfo = Rublon_ssp_SpGetInfo + SpShutDown = Rublon_ssp_SpShutDown + + SpAcquireCredentialsHandle = Rublon_ssp_SpAcquireCredentialsHandle + + SpInitLsaModeContext = Rublon_ssp_SpInitLsaModeContext + SpAcceptLsaModeContext = Rublon_ssp_SpAcceptLsaModeContext + + LsaApLogonUserEx2 = Rublon_ap_SpLogonUserEx2 + + LsaApInitializePackage = Rublon_ssp_LsaApInitializePackage \ No newline at end of file diff --git a/SSP_DLL/utilsSSP.cpp b/SSP_DLL/utilsSSP.cpp new file mode 100644 index 0000000..7b0057d --- /dev/null +++ b/SSP_DLL/utilsSSP.cpp @@ -0,0 +1,247 @@ +#include "utilsSSP.h" + +const char* LOG_TYPE_STRINGS[LOG_TYPE_COUNT] = { + "INFO", + "WARNING", + "ERROR", + "DEBUG" +}; + +PCWSTR W_LOG_TYPE_STRINGS[LOG_TYPE_COUNT] = { + L"INFO", + L"WARNING", + L"ERROR", + L"DEBUG" +}; + +//mapowanie nazw ze struktury SECURITY_LOGON_TYPE +const char* LOGON_TYPE_STRINGS[] = { + "UndefinedLogonType", + "UnknownLogonType1", + "Interactive", + "Network", + "Batch", + "Service", + "Proxy", + "Unlock", + "NetworkCleartext", + "NewCredentials", + "RemoteInteractive", + "CachedInteractive", + "CachedRemoteInteractive", + "CachedUnlock" +}; + +PCWSTR W_LOGON_TYPE_STRINGS[] = { + L"UndefinedLogonType", + L"UnknownLogonType1", + L"Interactive", + L"Network", + L"Batch", + L"Service", + L"Proxy", + L"Unlock", + L"NetworkCleartext", + L"NewCredentials", + L"RemoteInteractive", + L"CachedInteractive", + L"CachedRemoteInteractive", + L"CachedUnlock" +}; + +HANDLE log_file = NULL; +BOOL g_logfile_lock_initialized = FALSE; + +CRITICAL_SECTION g_logfile_lock; + +const WCHAR rublon_log_filepath[] = L"C:\\RublonSSP.log"; + +#ifdef _DEBUG +void send_to_interprocess_pipe(const char* msg) { + HANDLE hPipe = CreateFileA( + "\\\\.\\pipe\\sspmonitor", + GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (hPipe != INVALID_HANDLE_VALUE) { + DWORD bytesWritten; + WriteFile(hPipe, msg, (DWORD)strlen(msg), &bytesWritten, NULL); + CloseHandle(hPipe); + } +} +#endif //_DEBUG + +void init_logfile_lock() { + if (!g_logfile_lock_initialized) { + InitializeCriticalSection(&g_logfile_lock); + g_logfile_lock_initialized = TRUE; + } +} + +BOOL create_log_file(LPCWSTR log_filename) { + if (log_file != NULL && log_file != INVALID_HANDLE_VALUE) { + return TRUE; + } + bool if_new_file = GetFileAttributesW(log_filename) == INVALID_FILE_ATTRIBUTES; + + log_file = CreateFileW(log_filename, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (log_file == INVALID_HANDLE_VALUE) { + log_file = NULL; + return FALSE; + } + if (if_new_file) { + WORD bom = 0xFEFF; + DWORD written; + WriteFile(log_file, &bom, sizeof(bom), &written, NULL); + } + + WCHAR function_name[64] = { 0 }; + MultiByteToWideChar(CP_ACP, 0, __FUNCTION__, -1, function_name, ARRAYSIZE(function_name)); + + log_line(LOG_TYPE_INFO, + L"[%s] Utworzono plik log: %s", + function_name, + log_filename + ); + + get_process_details(); + return TRUE; +} + +void log_line(LOG_TYPE msg_type, PCWSTR msg_fmt, ...) { + SYSTEMTIME st; + WCHAR date_type_buff[128] = { 0 }; + WCHAR var_args[896] = { 0 }; + WCHAR log_buff[MAX_LOG_LINE] = { 0 }; + + GetLocalTime(&st); + + StringCchPrintfW(date_type_buff, ARRAYSIZE(date_type_buff), + L"[%s][%04d-%02d-%02d %02d:%02d:%02d.%03d]", + W_LOG_TYPE_STRINGS[msg_type], + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + /* + wsprintfW(date_type_buff, + L"[%s][%04d-%02d-%02d %02d:%02d:%02d.%03d] ", + W_LOG_TYPE_STRINGS[msg_type], + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);*/ + + va_list args; + va_start(args, msg_fmt); + StringCchVPrintfW(var_args, ARRAYSIZE(var_args), msg_fmt, args); + va_end(args); + + StringCchPrintfW(log_buff, ARRAYSIZE(log_buff), L"%s%s\r\n", date_type_buff, var_args); + + DWORD written = 0; + WriteFile(log_file, log_buff, lstrlenW(log_buff) * sizeof(WCHAR), &written, NULL); +} + + +void get_process_details() { + WCHAR buff[256] = { 0 }; + DWORD pid = GetCurrentProcessId(); + WCHAR path[MAX_PATH]; + + if (!GetModuleFileNameW(NULL, path, MAX_PATH)) + { + lstrcpyW(path, L""); + } + + wsprintfW(buff, L"PID procesu: %lu, Sciezka do pliku: %s", pid, path); + log_line(LOG_TYPE_INFO, L"%s", buff); +} + +PCWSTR check_unicode_string(PUNICODE_STRING u_str) { + return (u_str && u_str->Buffer && u_str->Length > 0) ? u_str->Buffer : L""; +} + +LPCWSTR check_string(LPCWSTR str) { + return (str != NULL && *str != L'\0') ? str : L""; +} + +BOOL compare_unicode_with_wchar(PUNICODE_STRING u_str, WCHAR* name) { + if (!u_str || !u_str->Buffer || !name) + return FALSE; + + size_t unicode_str_len = u_str->Length / sizeof(WCHAR); + const WCHAR* ptr1 = u_str->Buffer; + const WCHAR* ptr2 = name; + + //log_line(LOG_TYPE_DEBUG, L"[%s] str1 = %s, str2 = %s", L"compare_unicode_with_wchar", u_str->Buffer, name); + size_t name_len = 0; + if (!SUCCEEDED(StringCchLengthW(name, STRSAFE_MAX_CCH, &name_len))) + return FALSE; + + if (unicode_str_len != name_len) + return FALSE; + + for (size_t i = 0; i < unicode_str_len; i++) { + if (ptr1[i] != ptr2[i]) { + //log_line(LOG_TYPE_DEBUG, L"[%s] Porownywane ciagi znakow sa rozne...", L"compare_unicode_with_wchar"); + return FALSE; + } + } + /* + log_line(LOG_TYPE_DEBUG, + L"[%s] Porownywane ciagi znakow sa identyczne...", L"compare_unicode_with_wchar"); + */ + return TRUE; +} + +void copy_lpwstr_string(LPWSTR in, WCHAR* out, size_t out_size) { + if (out == NULL || out_size == 0) + return; + if (in != NULL && *in != L'\0') { + StringCchCopyW(out, out_size, in); + } + else { + StringCchCopyW(out, out_size, L""); + } +} + +void copy_lpwstr_string(LPCWSTR in, WCHAR* out, size_t out_size) { + if (out == NULL || out_size == 0) + return; + if (in != NULL && *in != L'\0') { + StringCchCopyW(out, out_size, in); + } + else { + StringCchCopyW(out, out_size, L""); + } +} + +void check_SID(PSID psid, PWSTR out_buff, size_t out_buff_size) { + if (!psid || !IsValidSid(psid)) { + StringCchCopyW(out_buff, out_buff_size, L""); + return; + } + LPWSTR sid_string = nullptr; + if (ConvertSidToStringSidW(psid, &sid_string)) { + StringCchCopyW(out_buff, out_buff_size, sid_string); + LocalFree(sid_string); + } + else { + StringCchCopyW(out_buff, out_buff_size, L""); + } +} + +LPCWSTR remote_protocol_type_to_string(USHORT proto) { + switch (proto) { + case WTS_PROTOCOL_CONSOLE: + return L"Console"; + case WTS_PROTOCOL_SHADOW: + return L"Shadow"; + case WTS_PROTOCOL_RDP: + return L"RDP"; + default: + return L""; + } +} diff --git a/SSP_DLL/utilsSSP.h b/SSP_DLL/utilsSSP.h new file mode 100644 index 0000000..1b24e79 --- /dev/null +++ b/SSP_DLL/utilsSSP.h @@ -0,0 +1,60 @@ +#pragma once + +#include "main.h" + +#include + +constexpr int MAX_LOG_LINE = 2048; + +constexpr size_t LOGON_TYPE_COUNT = 14; + +typedef enum _LOG_TYPE { + LOG_TYPE_INFO = 0, + LOG_TYPE_WARNING, + LOG_TYPE_ERROR, + LOG_TYPE_DEBUG, + LOG_TYPE_COUNT +} LOG_TYPE; + +typedef enum _WTS_PROTOCOL_TYPE { + WTS_PROTOCOL_CONSOLE = 0, + WTS_PROTOCOL_SHADOW = 1, + WTS_PROTOCOL_RDP = 2, + WTS_PROTOCOL_OTHER = 99 +} WTS_PROTOCOL_TYPE; + +extern const char* LOG_TYPE_STRINGS[LOG_TYPE_COUNT]; +extern PCWSTR W_LOG_TYPE_STRINGS[LOG_TYPE_COUNT]; + +extern const char* LOGON_TYPE_STRINGS[LOGON_TYPE_COUNT]; +extern PCWSTR W_LOGON_TYPE_STRINGS[LOGON_TYPE_COUNT]; + +extern HANDLE log_file; +extern BOOL g_logfile_lock_initialized; +extern CRITICAL_SECTION g_logfile_lock; +extern const WCHAR rublon_log_filepath[]; + +#ifdef _DEBUG + void send_to_interprocess_pipe(const char* msg); +#else + #define send_to_interprocess_pipe(x) ((void)0) +#endif //_DEBUG + +void init_logfile_lock(); + +BOOL create_log_file(LPCWSTR log_filename); +void log_line(LOG_TYPE msg_type, PCWSTR msg_fmt, ...); + +void get_process_details(); + +PCWSTR check_unicode_string(PUNICODE_STRING u_str); +LPCWSTR check_string(LPCWSTR str); + +BOOL compare_unicode_with_wchar(PUNICODE_STRING u_str, WCHAR *name); + +void copy_lpwstr_string(LPWSTR in, WCHAR *out, size_t out_size); +void copy_lpwstr_string(LPCWSTR in, WCHAR *out, size_t out_size); + +void check_SID(PSID psid, PWSTR out_buff, size_t out_buff_size); + +LPCWSTR remote_protocol_type_to_string(USHORT proto); \ No newline at end of file