CVE-2022-24750: Improper Privilege Management (CWE-269)
value: UltraVNC is a free and open source remote pc access software. A vulnerability has been found in versions prior to 1.3.8.0 in which the DSM plugin module, which allows a local authenticated user to achieve local privilege escalation (LPE) on a vulnerable system. The vulnerability has been fixed to allow loading of plugins from the installed directory. Affected users should upgrade their UltraVNC to 1.3.8.1. Users unable to upgrade should not install and run UltraVNC server as a service. It is advisable to create a scheduled task on a low privilege account to launch WinVNC.exe instead. There are no known workarounds if winvnc needs to be started as a service.
CWE description: The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.
CVSS v3 base score: 7.8
Published: 2022-03-10T21:15Z
Repository: https://github.com/ultravnc/UltraVNC
Language: C++
Files changed: winvnc/winvnc/vncproperties.cpp
Commit date: 2022-03-08 20:04:12 +0100
Commit message: security fix

Diff: diff --git a/winvnc/winvnc/vncproperties.cpp b/winvnc/winvnc/vncproperties.cpp
index 36af421d..88806293 100644
--- a/winvnc/winvnc/vncproperties.cpp
+++ b/winvnc/winvnc/vncproperties.cpp
@@ -41,10 +41,11 @@
 #include "vncOSVersion.h"
 #include "common/win32_helpers.h"
 #include "vncConnDialog.h"
 
 #include "Localization.h" // ACT : Add localization on messages
+#include "shlwapi.h"
 
 //extern HINSTANCE g_hInst;
 
 bool RunningAsAdministrator ();
 const char WINVNC_REGISTRY_KEY [] = "Software\\ORL\\WinVNC3";
@@ -717,11 +718,11 @@ vncProperties::DialogProc(HWND hwnd,
 			else
 				SendMessage(hPlugins, CB_SELECTSTRING, 0, (LPARAM)_this->m_server->GetDSMPluginName());
 
 			// Modif sf@2002
 			SendMessage(GetDlgItem(hwnd, IDC_PLUGIN_CHECK), BM_SETCHECK, _this->m_server->IsDSMPluginEnabled(), 0);
-			EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON), _this->m_server->IsDSMPluginEnabled());
+			EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON),  (_this->m_server->AuthClientCount() == 0 ? _this->m_server->IsDSMPluginEnabled(): false));
 
 			// Query window option - Taken from TightVNC advanced properties 
 			BOOL queryEnabled = (_this->m_server->QuerySetting() == 4);
 			SendMessage(GetDlgItem(hwnd, IDQUERY), BM_SETCHECK, queryEnabled, 0);
 			EnableWindow(GetDlgItem(hwnd, IDQUERYTIMEOUT), queryEnabled);
@@ -1283,12 +1284,13 @@ vncProperties::DialogProc(HWND hwnd,
 			}
 
 		// sf@2002 - DSM Plugin
 		case IDC_PLUGIN_CHECK:
 			{
-				EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON),
-					SendMessage(GetDlgItem(hwnd, IDC_PLUGIN_CHECK), BM_GETCHECK, 0, 0) == BST_CHECKED);
+				EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON), _this->m_server->AuthClientCount() == 0 
+						? SendMessage(GetDlgItem(hwnd, IDC_PLUGIN_CHECK), BM_GETCHECK, 0, 0) == BST_CHECKED 
+						: BST_UNCHECKED);
 			}
 			return TRUE;
 			// Marscha@2004 - authSSP: moved MSLogon checkbox back to admin props page
 			// Reason: Different UI for old and new mslogon group config.
 		case IDC_MSLOGON_CHECKD:
@@ -1366,10 +1368,12 @@ vncProperties::DialogProc(HWND hwnd,
 				HWND hPlugin = GetDlgItem(hwnd, IDC_PLUGIN_CHECK);
 				if (SendMessage(hPlugin, BM_GETCHECK, 0, 0) == BST_CHECKED)
 				{
 					TCHAR szPlugin[MAX_PATH];
 					GetDlgItemText(hwnd, IDC_PLUGINS_COMBO, szPlugin, MAX_PATH);
+					PathStripPathA(szPlugin);
+
 					if (!_this->m_server->GetDSMPluginPointer()->IsLoaded())
 						_this->m_server->GetDSMPluginPointer()->LoadPlugin(szPlugin, false);
 					else
 					{
 						// sf@2003 - We check if the loaded plugin is the same than

Vulnerable code: 			EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON), _this->m_server->IsDSMPluginEnabled());
				EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON),
					SendMessage(GetDlgItem(hwnd, IDC_PLUGIN_CHECK), BM_GETCHECK, 0, 0) == BST_CHECKED);
Fixed code: #include "shlwapi.h"
			EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON),  (_this->m_server->AuthClientCount() == 0 ? _this->m_server->IsDSMPluginEnabled(): false));
				EnableWindow(GetDlgItem(hwnd, IDC_PLUGIN_BUTTON), _this->m_server->AuthClientCount() == 0 
						? SendMessage(GetDlgItem(hwnd, IDC_PLUGIN_CHECK), BM_GETCHECK, 0, 0) == BST_CHECKED 
						: BST_UNCHECKED);
					PathStripPathA(szPlugin);