diff --git a/CHANGELOG.md b/CHANGELOG.md index a88739ff..6969c0e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add template "BlockAccessWMI" to prevent sandboxed processes from accessing system information through WMI. - Add template "BlockLocalConnect" to prevent sandboxed processes from sending network packs to loaclhost to breakout sandbox. - Add new option "AllowCoverTaskbar" for [#3975](https://github.com/sandboxie-plus/Sandboxie/issues/3975) +- added RPC Port message filter mechanism to block unsafe RDP calls via the driver [#3930](https://github.com/sandboxie-plus/Sandboxie/issues/3930) + - Usage: "RpcPortFilter=Port,ID,Label" label is optional ### Changed - Extend "Temp Template" to make it could delete local template section. @@ -43,7 +45,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - when it is set, a prompt pops up before launching a new program into the sandbox using "Start.exe" and checks if the program that started "Start.exe" is a Sandboxie component itself, if it is not, a warning pops up - added option for EditAdminOnly in SetupWizard - ### Changed - splited the advanced new box wizard page in two - reorganized box options a bit diff --git a/Sandboxie/common/str_util.c b/Sandboxie/common/str_util.c index fb533071..146c1281 100644 --- a/Sandboxie/common/str_util.c +++ b/Sandboxie/common/str_util.c @@ -65,7 +65,7 @@ const WCHAR* SbieDll_GetTagValue(const WCHAR* str, const WCHAR* strEnd, const WC // check if tag contains a string in quotations if ((alt = (*str == L'\"')) || (*str == L'\'')) { - WCHAR* end = wcschr(str + 1, alt ? L'\"' : L'\''); + const WCHAR* end = wcschr(str + 1, alt ? L'\"' : L'\''); if (!end) return NULL; // error invalid string *value = str + 1; @@ -160,7 +160,7 @@ BOOLEAN SbieDll_FindTagValuePtr(const WCHAR* string, const WCHAR* tag_name, cons TagFindProcParam tagFindProcParam = { tag_name, - wcslen(tag_name), + (ULONG)wcslen(tag_name), NULL, 0 }; @@ -175,7 +175,7 @@ BOOLEAN SbieDll_FindTagValuePtr(const WCHAR* string, const WCHAR* tag_name, cons BOOLEAN SbieDll_FindTagValue(const WCHAR* string, const WCHAR* tag_name, WCHAR* value, ULONG value_size, WCHAR eq, WCHAR sep) { - WCHAR* value_ptr; + const WCHAR* value_ptr; ULONG value_len; if (!SbieDll_FindTagValuePtr(string, tag_name, &value_ptr, &value_len, eq, sep)) return FALSE; diff --git a/Sandboxie/core/dll/config.c b/Sandboxie/core/dll/config.c index 31b23c8a..966527ca 100644 --- a/Sandboxie/core/dll/config.c +++ b/Sandboxie/core/dll/config.c @@ -544,6 +544,17 @@ BOOLEAN SbieDll_MatchImage(const WCHAR* pat_str, const WCHAR* test_str, const WC BOOLEAN SbieDll_GetStringForStringList(const WCHAR* string, const WCHAR* boxname, const WCHAR* setting, WCHAR* value, ULONG value_size) +{ + return SbieDll_GetStringsForStringList(string, boxname, setting, 0, value, value_size); +} + + +//--------------------------------------------------------------------------- +// SbieDll_GetStringsForStringList +//--------------------------------------------------------------------------- + + +SBIEDLL_EXPORT BOOLEAN SbieDll_GetStringsForStringList(const WCHAR* string, const WCHAR* boxname, const WCHAR* setting, int pos, WCHAR* value, ULONG value_size) { BOOLEAN found = FALSE; WCHAR buf[CONF_LINE_LEN]; @@ -557,15 +568,21 @@ BOOLEAN SbieDll_GetStringForStringList(const WCHAR* string, const WCHAR* boxname // check specific value *ptr++ = L'\0'; if (_wcsicmp(buf, string) == 0) { - wcscpy_s(value, value_size / sizeof(WCHAR), ptr); - found = TRUE; - break; + if (pos == 0) { + wcscpy_s(value, value_size / sizeof(WCHAR), ptr); + found = TRUE; + break; + } + pos--; } } else if (!found) { // default value - wcscpy_s(value, value_size / sizeof(WCHAR), buf); - found = TRUE; + if (pos == 0) { + wcscpy_s(value, value_size / sizeof(WCHAR), buf); + found = TRUE; + } + pos--; } } else if (status != STATUS_BUFFER_TOO_SMALL) diff --git a/Sandboxie/core/dll/sbiedll.h b/Sandboxie/core/dll/sbiedll.h index 2759f446..0beecf6a 100644 --- a/Sandboxie/core/dll/sbiedll.h +++ b/Sandboxie/core/dll/sbiedll.h @@ -226,6 +226,7 @@ SBIEDLL_EXPORT ULONG SbieDll_InjectLow(HANDLE hProcess, ULONG init_flags, BOOLE SBIEDLL_EXPORT BOOLEAN SbieDll_MatchImage(const WCHAR* pat_str, const WCHAR* test_str, const WCHAR* BoxName); SBIEDLL_EXPORT BOOLEAN SbieDll_GetStringForStringList(const WCHAR* string, const WCHAR* boxname, const WCHAR* setting, WCHAR* value, ULONG value_size); +SBIEDLL_EXPORT BOOLEAN SbieDll_GetStringsForStringList(const WCHAR* string, const WCHAR* boxname, const WCHAR* setting, int pos, WCHAR* value, ULONG value_size); SBIEDLL_EXPORT BOOLEAN SbieDll_CheckStringInList(const WCHAR* string, const WCHAR* boxname, const WCHAR* setting); SBIEDLL_EXPORT BOOLEAN SbieDll_CheckStringInListA(const char* string, const WCHAR* boxname, const WCHAR* setting); diff --git a/Sandboxie/core/drv/api_defs.h b/Sandboxie/core/drv/api_defs.h index 81ab1288..425608ff 100644 --- a/Sandboxie/core/drv/api_defs.h +++ b/Sandboxie/core/drv/api_defs.h @@ -469,6 +469,8 @@ API_ARGS_BEGIN(API_OPEN_DYNAMIC_PORT_ARGS) API_ARGS_FIELD(WCHAR*,port_name) API_ARGS_FIELD(HANDLE,process_id) API_ARGS_FIELD(WCHAR*,port_id) +API_ARGS_FIELD(ULONG,filter_num) +API_ARGS_FIELD(ULONG*,filter_ids) API_ARGS_CLOSE(API_OPEN_DYNAMIC_PORT_ARGS) diff --git a/Sandboxie/core/drv/ipc.h b/Sandboxie/core/drv/ipc.h index 12240911..a0a5e27c 100644 --- a/Sandboxie/core/drv/ipc.h +++ b/Sandboxie/core/drv/ipc.h @@ -34,6 +34,9 @@ typedef struct _IPC_DYNAMIC_PORT { WCHAR wstrPortId[DYNAMIC_PORT_ID_CHARS]; WCHAR wstrPortName[DYNAMIC_PORT_NAME_CHARS]; + + ULONG FilterCount; + UCHAR FilterIDs[0]; } IPC_DYNAMIC_PORT; typedef struct _IPC_DYNAMIC_PORTS { diff --git a/Sandboxie/core/drv/ipc_lsa.c b/Sandboxie/core/drv/ipc_lsa.c index 3f2c9e0a..6c9039e8 100644 --- a/Sandboxie/core/drv/ipc_lsa.c +++ b/Sandboxie/core/drv/ipc_lsa.c @@ -220,8 +220,6 @@ _FX NTSTATUS Ipc_CheckPortRequest_LsaEP( ULONG len = msg->u1.s1.DataLength; UCHAR* ptr = (UCHAR*)((UCHAR*)msg + sizeof(PORT_MESSAGE)); - int i = 0; - int rc = -2; ProbeForRead(ptr, len, sizeof(WCHAR)); diff --git a/Sandboxie/core/drv/ipc_port.c b/Sandboxie/core/drv/ipc_port.c index d650fa97..c3717d24 100644 --- a/Sandboxie/core/drv/ipc_port.c +++ b/Sandboxie/core/drv/ipc_port.c @@ -132,6 +132,9 @@ NTSTATUS Ipc_CheckPortRequest_PowerManagement( NTSTATUS Ipc_CheckPortRequest_SpoolerPort( PROCESS *proc, OBJECT_NAME_INFORMATION *Name, PORT_MESSAGE *msg); +NTSTATUS Ipc_CheckPortRequest_Dynamic( + PROCESS *proc, OBJECT_NAME_INFORMATION *Name, PORT_MESSAGE *msg); + static NTSTATUS Ipc_Api_GetRpcPortName_2( PEPROCESS ProcessObject, WCHAR* pDstPortName); @@ -248,6 +251,8 @@ _FX NTSTATUS Ipc_CheckPortRequest( status = Ipc_CheckPortRequest_PowerManagement(proc, Name, msg); if (status == STATUS_BAD_INITIAL_PC) status = Ipc_CheckPortRequest_SpoolerPort(proc, Name, msg); + if (status == STATUS_BAD_INITIAL_PC) + status = Ipc_CheckPortRequest_Dynamic(proc, Name, msg); if (status == STATUS_BAD_INITIAL_PC) status = STATUS_SUCCESS; @@ -650,7 +655,7 @@ _FX NTSTATUS Ipc_Api_OpenDynamicPort(PROCESS* proc, ULONG64* parms) if (port == NULL) { - port = Mem_AllocEx(Driver_Pool, sizeof(IPC_DYNAMIC_PORT), TRUE); + port = Mem_AllocEx(Driver_Pool, sizeof(IPC_DYNAMIC_PORT) + sizeof(UCHAR) * pArgs->filter_num.val, TRUE); if (!port) Log_Msg0(MSG_1104); else @@ -661,7 +666,20 @@ _FX NTSTATUS Ipc_Api_OpenDynamicPort(PROCESS* proc, ULONG64* parms) if (_wcsicmp(port->wstrPortId, L"spooler") == 0) Ipc_Dynamic_Ports.pSpoolerPort = port; - List_Insert_After(&Ipc_Dynamic_Ports.Ports, NULL, port); + port->FilterCount = pArgs->filter_num.val; + if (port->FilterCount > 0) + { + try { + ProbeForRead(pArgs->filter_ids.val, sizeof(UCHAR) * port->FilterCount, sizeof(UCHAR)); + memcpy(port->FilterIDs, pArgs->filter_ids.val, sizeof(UCHAR) * port->FilterCount); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + } + + if (NT_SUCCESS(status)) + List_Insert_After(&Ipc_Dynamic_Ports.Ports, NULL, port); } } @@ -694,6 +712,84 @@ _FX NTSTATUS Ipc_Api_OpenDynamicPort(PROCESS* proc, ULONG64* parms) } +//--------------------------------------------------------------------------- +// Ipc_CheckPortRequest_Dynamic +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Ipc_CheckPortRequest_Dynamic( + PROCESS* proc, OBJECT_NAME_INFORMATION* Name, PORT_MESSAGE* msg) +{ + NTSTATUS status = STATUS_BAD_INITIAL_PC; + + if (Ipc_Dynamic_Ports.pPortLock) + { + KeEnterCriticalRegion(); + ExAcquireResourceSharedLite(Ipc_Dynamic_Ports.pPortLock, TRUE); + + // + // find the port + // + + IPC_DYNAMIC_PORT* port = List_Head(&Ipc_Dynamic_Ports.Ports); + while (port) + { + if (_wcsicmp(Name->Name.Buffer, port->wstrPortName) == 0) + { + // + // examine message + // + + status = STATUS_SUCCESS; + + if (port->FilterCount > 0) + { + __try { + + ProbeForRead(msg, sizeof(PORT_MESSAGE), sizeof(ULONG_PTR)); + + if (Driver_OsVersion >= DRIVER_WINDOWS_7) { + + ULONG len = msg->u1.s1.DataLength; + UCHAR* ptr = (UCHAR*)((UCHAR*)msg + sizeof(PORT_MESSAGE)); + + ProbeForRead(ptr, len, sizeof(WCHAR)); + + UCHAR uMsg = ptr[20]; + + // + // apply filter + // + + for (ULONG i = 0; i < port->FilterCount; i++) { + if (port->FilterIDs[i] == uMsg) { + status = STATUS_ACCESS_DENIED; + break; + } + } + + //DbgPrint("%S message ID: %d (%d)\n", port->wstrPortId, uMsg, NT_SUCCESS(status)); + } + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + } + + break; + } + + port = List_Next(port); + } + + ExReleaseResourceLite(Ipc_Dynamic_Ports.pPortLock); + KeLeaveCriticalRegion(); + } + + return status; +} + + //--------------------------------------------------------------------------- // Ipc_Api_GetDynamicPortFromPid //--------------------------------------------------------------------------- diff --git a/Sandboxie/core/drv/ipc_sam.c b/Sandboxie/core/drv/ipc_sam.c index 4b320132..fc07f312 100644 --- a/Sandboxie/core/drv/ipc_sam.c +++ b/Sandboxie/core/drv/ipc_sam.c @@ -68,8 +68,6 @@ _FX NTSTATUS Ipc_CheckPortRequest_Sam( ULONG len = msg->u1.s1.DataLength; UCHAR* ptr = (UCHAR*)((UCHAR*)msg + sizeof(PORT_MESSAGE)); - int i = 0; - int rc = -2; ProbeForRead(ptr, len, sizeof(WCHAR)); diff --git a/Sandboxie/core/drv/ipc_spl.c b/Sandboxie/core/drv/ipc_spl.c index bf75d4e4..fd4eec60 100644 --- a/Sandboxie/core/drv/ipc_spl.c +++ b/Sandboxie/core/drv/ipc_spl.c @@ -128,8 +128,8 @@ _FX NTSTATUS Ipc_CheckPortRequest_SpoolerPort( ULONG len = msg->u1.s1.DataLength; UCHAR* ptr = (UCHAR*)((UCHAR*)msg + sizeof(PORT_MESSAGE)); - int i = 0; - int rc = -2; + //int i = 0; + //int rc = -2; ProbeForRead(ptr, len, sizeof(WCHAR)); diff --git a/Sandboxie/core/svc/EpMapperServer.cpp b/Sandboxie/core/svc/EpMapperServer.cpp index 512babb1..744800c3 100644 --- a/Sandboxie/core/svc/EpMapperServer.cpp +++ b/Sandboxie/core/svc/EpMapperServer.cpp @@ -27,6 +27,8 @@ #include "core/dll/sbiedll.h" #include "common/defines.h" #include "core/drv/api_defs.h" +#include +#include "common/str_util.h" //--------------------------------------------------------------------------- // Constructor @@ -84,6 +86,8 @@ MSG_HEADER *EpMapperServer::EpmapperGetPortNameHandler(MSG_HEADER *msg) WCHAR pwszServiceName [81]; *pwszServiceName = 0; + WCHAR buf[MAX_PATH]; + if (_wcsicmp(req->wszPortId, SPOOLER_PORT_ID) == 0) { if (SbieApi_QueryConfBool(boxname, L"ClosePrintSpooler", FALSE)) return SHORT_REPLY(E_ACCESSDENIED); @@ -116,7 +120,6 @@ MSG_HEADER *EpMapperServer::EpmapperGetPortNameHandler(MSG_HEADER *msg) return SHORT_REPLY(E_INVALIDARG);*/ else { - WCHAR buf[MAX_PATH]; if (SbieDll_GetStringForStringList(req->wszPortId, boxname, L"RpcPortBindingIfId", buf, sizeof(buf))) { unsigned short uuid[37]; @@ -223,14 +226,33 @@ MSG_HEADER *EpMapperServer::EpmapperGetPortNameHandler(MSG_HEADER *msg) // So, since here we only open non critical ports, we will use PID 0 to open them globally // instead of only for the one process. Todo: make it per sandbox instead // + // Note: Filter is only support for globaly open ports, i.e. when process_id == 0 + // Todo: Add per process ALPC message filter + // + + std::vector FilterIDs; + + for (int i = 0; SbieDll_GetStringsForStringList(req->wszPortId, boxname, L"RpcPortFilter", i, buf, sizeof(buf)); i++) + { + WCHAR* test_value = NULL; + ULONG test_len = 0; + if (SbieDll_GetTagValue(buf, NULL, (const WCHAR**)&test_value, &test_len, L',')) { + test_value[test_len] = L'\0'; + FilterIDs.push_back((UCHAR)_wtoi(test_value)); + } + } // Param 1 is dynamic port name (e.g. "LRPC-f760d5b40689a98168"), WCHAR[DYNAMIC_PORT_NAME_CHARS] // Param 2 is the process PID for which to open the port, can be 0 when port is special // Param 3 is the port type/identifier - rpl->h.status = SbieApi_Call(API_OPEN_DYNAMIC_PORT, 3, + // Param 4 Filter ID count, array count + // Param 5 Filter ID buffer, UCHAR Array + rpl->h.status = SbieApi_Call(API_OPEN_DYNAMIC_PORT, 5, (ULONG_PTR)rpl->wszPortName, (ULONG_PTR)0, - (ULONG_PTR)req->wszPortId); + (ULONG_PTR)req->wszPortId, + (ULONG_PTR)FilterIDs.size(), // count + (ULONG_PTR)FilterIDs.data()); } return (MSG_HEADER *)rpl; diff --git a/Sandboxie/core/svc/SboxSvc.vcxproj b/Sandboxie/core/svc/SboxSvc.vcxproj index 96e56de7..db50e587 100644 --- a/Sandboxie/core/svc/SboxSvc.vcxproj +++ b/Sandboxie/core/svc/SboxSvc.vcxproj @@ -393,6 +393,16 @@ true true + + true + true + true + true + true + true + true + true + NotUsing NotUsing diff --git a/Sandboxie/core/svc/SboxSvc.vcxproj.filters b/Sandboxie/core/svc/SboxSvc.vcxproj.filters index dacf74ec..2c220903 100644 --- a/Sandboxie/core/svc/SboxSvc.vcxproj.filters +++ b/Sandboxie/core/svc/SboxSvc.vcxproj.filters @@ -87,6 +87,9 @@ common + + common + diff --git a/Sandboxie/core/svc/includes.cpp b/Sandboxie/core/svc/includes.cpp index e96d7d03..177e7935 100644 --- a/Sandboxie/core/svc/includes.cpp +++ b/Sandboxie/core/svc/includes.cpp @@ -46,6 +46,8 @@ extern "C" { #include "common/stream.c" +#include "common/str_util.c" + #include "common/verify.c" #ifdef __cplusplus diff --git a/Sandboxie/install/Templates.ini b/Sandboxie/install/Templates.ini index b5cc3e3f..9ac9eac5 100644 --- a/Sandboxie/install/Templates.ini +++ b/Sandboxie/install/Templates.ini @@ -3890,6 +3890,18 @@ UseRpcMgmtSetComTimeout=WINNSI.DLL,n RpcPortBinding=WinHttp.dll,'ncalrpc:',Resolve=WPAD,TimeOut=y RpcPortBindingSvc=WPAD,WinHttpAutoProxySvc +#RpcPortFilter=WPAD,1,WinHttpResetAutoProxy +RpcPortFilter=WPAD,2,AutoProxySaveProxyCredentials +RpcPortFilter=WPAD,3,AutoProxyStoreSavedProxyCredentialsForClient +RpcPortFilter=WPAD,4,AutoProxyDeleteSavedProxyCredentials +#RpcPortFilter=WPAD,5,AutoProxyReindicateAllProxies +#RpcPortFilter=WPAD,6,ReadProxySettingsInternal +RpcPortFilter=WPAD,7,WinHttpWriteProxySettings +RpcPortFilter=WPAD,8,WinHttpSetProxySettingsPerUser +#RpcPortFilter=WPAD,9,WinHttpConnectionUpdateIfIndexTable +RpcPortFilter=WPAD,10,WinHttpConnectionSetPolicyEntries +RpcPortFilter=WPAD,11,WinHttpConnectionDeletePolicyEntries + # windows 10 game port #Tmpl.ScanService=??? RpcPortBinding=resourcepolicyclient.dll,{00000000-0000-0000-0000-000000000000},Resolve=GamePort