1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-11 11:08:02 -06:00

Windows: Fix possible local privilege escalation vulnerability during execution of VeraCrypt Expander (CVE-2019-19501)

This commit is contained in:
Mounir IDRASSI
2019-12-03 22:23:09 +01:00
parent c6ff31be1c
commit ade8e3f8cb
3 changed files with 233 additions and 23 deletions

View File

@@ -300,6 +300,7 @@ HMODULE hntmartadll = NULL;
HMODULE hwinscarddll = NULL; HMODULE hwinscarddll = NULL;
HMODULE hmsvcrtdll = NULL; HMODULE hmsvcrtdll = NULL;
HMODULE hWinTrustLib = NULL; HMODULE hWinTrustLib = NULL;
HMODULE hAdvapi32Dll = NULL;
#define FREE_DLL(h) if (h) { FreeLibrary (h); h = NULL;} #define FREE_DLL(h) if (h) { FreeLibrary (h); h = NULL;}
@@ -336,6 +337,18 @@ typedef HRESULT (STDAPICALLTYPE *SHStrDupWPtr)(LPCWSTR psz, LPWSTR *ppwsz);
// ChangeWindowMessageFilter // ChangeWindowMessageFilter
typedef BOOL (WINAPI *ChangeWindowMessageFilterPtr) (UINT, DWORD); typedef BOOL (WINAPI *ChangeWindowMessageFilterPtr) (UINT, DWORD);
typedef BOOL (WINAPI *CreateProcessWithTokenWFn)(
__in HANDLE hToken,
__in DWORD dwLogonFlags,
__in_opt LPCWSTR lpApplicationName,
__inout_opt LPWSTR lpCommandLine,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCWSTR lpCurrentDirectory,
__in LPSTARTUPINFOW lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
SetDllDirectoryPtr SetDllDirectoryFn = NULL; SetDllDirectoryPtr SetDllDirectoryFn = NULL;
SetSearchPathModePtr SetSearchPathModeFn = NULL; SetSearchPathModePtr SetSearchPathModeFn = NULL;
SetDefaultDllDirectoriesPtr SetDefaultDllDirectoriesFn = NULL; SetDefaultDllDirectoriesPtr SetDefaultDllDirectoriesFn = NULL;
@@ -350,6 +363,7 @@ SetupOpenInfFileWPtr SetupOpenInfFileWFn = NULL;
SHDeleteKeyWPtr SHDeleteKeyWFn = NULL; SHDeleteKeyWPtr SHDeleteKeyWFn = NULL;
SHStrDupWPtr SHStrDupWFn = NULL; SHStrDupWPtr SHStrDupWFn = NULL;
ChangeWindowMessageFilterPtr ChangeWindowMessageFilterFn = NULL; ChangeWindowMessageFilterPtr ChangeWindowMessageFilterFn = NULL;
CreateProcessWithTokenWFn CreateProcessWithTokenWPtr = NULL;
typedef LONG (WINAPI *WINVERIFYTRUST)(HWND hwnd, GUID *pgActionID, LPVOID pWVTData); typedef LONG (WINAPI *WINVERIFYTRUST)(HWND hwnd, GUID *pgActionID, LPVOID pWVTData);
typedef CRYPT_PROVIDER_DATA* (WINAPI *WTHELPERPROVDATAFROMSTATEDATA)(HANDLE hStateData); typedef CRYPT_PROVIDER_DATA* (WINAPI *WTHELPERPROVDATAFROMSTATEDATA)(HANDLE hStateData);
@@ -758,6 +772,7 @@ void AbortProcessDirect (wchar_t *abortMsg)
FREE_DLL (hntmartadll); FREE_DLL (hntmartadll);
FREE_DLL (hwinscarddll); FREE_DLL (hwinscarddll);
FREE_DLL (hmsvcrtdll); FREE_DLL (hmsvcrtdll);
FREE_DLL (hAdvapi32Dll);
exit (1); exit (1);
} }
@@ -808,6 +823,7 @@ void AbortProcessSilent (void)
FREE_DLL (hntmartadll); FREE_DLL (hntmartadll);
FREE_DLL (hwinscarddll); FREE_DLL (hwinscarddll);
FREE_DLL (hmsvcrtdll); FREE_DLL (hmsvcrtdll);
FREE_DLL (hAdvapi32Dll);
// Note that this function also causes localcleanup() to be called (see atexit()) // Note that this function also causes localcleanup() to be called (see atexit())
exit (1); exit (1);
@@ -3014,6 +3030,7 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
AbortProcess ("INIT_DLL"); AbortProcess ("INIT_DLL");
LoadSystemDll (L"Riched20.dll", &hRichEditDll, FALSE, SRC_POS); LoadSystemDll (L"Riched20.dll", &hRichEditDll, FALSE, SRC_POS);
LoadSystemDll (L"Advapi32.dll", &hAdvapi32Dll, FALSE, SRC_POS);
#if !defined(SETUP) #if !defined(SETUP)
if (!VerifyModuleSignature (modPath)) if (!VerifyModuleSignature (modPath))
@@ -3047,6 +3064,9 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
#endif #endif
} }
// Get CreateProcessWithTokenW function pointer
CreateProcessWithTokenWPtr = (CreateProcessWithTokenWFn) GetProcAddress(hAdvapi32Dll, "CreateProcessWithTokenW");
/* Save the instance handle for later */ /* Save the instance handle for later */
hInst = hInstance; hInst = hInstance;
@@ -3271,6 +3291,7 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
FREE_DLL (hntmartadll); FREE_DLL (hntmartadll);
FREE_DLL (hwinscarddll); FREE_DLL (hwinscarddll);
FREE_DLL (hmsvcrtdll); FREE_DLL (hmsvcrtdll);
FREE_DLL (hAdvapi32Dll);
exit (1); exit (1);
} }
#endif #endif
@@ -3316,6 +3337,7 @@ void FinalizeApp (void)
FREE_DLL (hntmartadll); FREE_DLL (hntmartadll);
FREE_DLL (hwinscarddll); FREE_DLL (hwinscarddll);
FREE_DLL (hmsvcrtdll); FREE_DLL (hmsvcrtdll);
FREE_DLL (hAdvapi32Dll);
} }
void InitHelpFileName (void) void InitHelpFileName (void)
@@ -5101,7 +5123,7 @@ void OpenVolumeExplorerWindow (int driveNo)
// Force explorer to discover the drive // Force explorer to discover the drive
SHGetFileInfo (dosName, 0, &fInfo, sizeof (fInfo), 0); SHGetFileInfo (dosName, 0, &fInfo, sizeof (fInfo), 0);
ShellExecute (NULL, L"open", dosName, NULL, NULL, SW_SHOWNORMAL); SafeOpenURL (dosName);
} }
static BOOL explorerCloseSent; static BOOL explorerCloseSent;
@@ -10499,25 +10521,37 @@ void ConfigReadCompareString (char *configKey, char *defaultValue, char *str, in
void OpenPageHelp (HWND hwndDlg, int nPage) void OpenPageHelp (HWND hwndDlg, int nPage)
{ {
int r = (int)ShellExecuteW (NULL, L"open", szHelpFile, NULL, NULL, SW_SHOWNORMAL); if (IsAdmin ())
if (r == ERROR_FILE_NOT_FOUND)
{ {
// Try the secondary help file if (FileExists (szHelpFile))
r = (int)ShellExecuteW (NULL, L"open", szHelpFile2, NULL, NULL, SW_SHOWNORMAL); SafeOpenURL (szHelpFile);
else if (FileExists (szHelpFile2))
SafeOpenURL (szHelpFile2);
else
Applink ("help");
}
else
{
int r = (int)ShellExecuteW (NULL, L"open", szHelpFile, NULL, NULL, SW_SHOWNORMAL);
if (r == ERROR_FILE_NOT_FOUND) if (r == ERROR_FILE_NOT_FOUND)
{ {
// Open local HTML help. It will fallback to online help if not found. // Try the secondary help file
Applink ("help"); r = (int)ShellExecuteW (NULL, L"open", szHelpFile2, NULL, NULL, SW_SHOWNORMAL);
return;
}
}
if (r == SE_ERR_NOASSOC) if (r == ERROR_FILE_NOT_FOUND)
{ {
if (AskYesNo ("HELP_READER_ERROR", MainDlg) == IDYES) // Open local HTML help. It will fallback to online help if not found.
OpenOnlineHelp (); Applink ("help");
return;
}
}
if (r == SE_ERR_NOASSOC)
{
if (AskYesNo ("HELP_READER_ERROR", MainDlg) == IDYES)
OpenOnlineHelp ();
}
} }
} }
@@ -11021,13 +11055,29 @@ void Applink (const char *dest)
CorrectURL (url); CorrectURL (url);
} }
r = (int) ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL); if (IsAdmin ())
if (((r == ERROR_FILE_NOT_FOUND) || (r == ERROR_PATH_NOT_FOUND)) && buildUrl)
{ {
// fallbacl to online resources if (buildUrl && !FileExists (url))
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page); {
ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL); // fallbacl to online resources
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
SafeOpenURL (url);
}
else
{
SafeOpenURL (url);
}
}
else
{
r = (int) ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
if (((r == ERROR_FILE_NOT_FOUND) || (r == ERROR_PATH_NOT_FOUND)) && buildUrl)
{
// fallbacl to online resources
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
}
} }
Sleep (200); Sleep (200);
@@ -14036,6 +14086,165 @@ Cleanup:
return bSuccess; return bSuccess;
} }
// Based on sample code from:
// https://blogs.msdn.microsoft.com/aaron_margosis/2009/06/06/faq-how-do-i-start-a-program-as-the-desktop-user-from-an-elevated-app/
// start a program non-elevated as the desktop user from an elevated app
static bool RunAsDesktopUser(
__in const wchar_t * szApp,
__in wchar_t * szCmdLine)
{
HANDLE hThreadToken = NULL, hShellProcess = NULL, hShellProcessToken = NULL, hPrimaryToken = NULL;
HWND hwnd = NULL;
DWORD dwPID = 0;
BOOL ret;
DWORD dwLastErr;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
bool retval = false;
SecureZeroMemory(&si, sizeof(si));
SecureZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
// locate CreateProcessWithTokenW in Advapi32.dll
if (!CreateProcessWithTokenWPtr)
{
return false;
}
if (!ImpersonateSelf (SecurityImpersonation))
{
return false;
}
if (!OpenThreadToken (GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &hThreadToken))
{
return false;
}
else
{
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid);
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hThreadToken, FALSE, &tkp, 0, NULL, NULL);
dwLastErr = GetLastError();
if (ERROR_SUCCESS != dwLastErr)
{
goto cleanup;
}
}
// From this point down, we have handles to close, so make sure to clean up.
// Get an HWND representing the desktop shell.
// CAVEATS: This will fail if the shell is not running (crashed or terminated), or the default shell has been
// replaced with a custom shell. This also won't return what you probably want if Explorer has been terminated and
// restarted elevated.
hwnd = GetShellWindow();
if (NULL == hwnd)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Get the PID of the desktop shell process.
GetWindowThreadProcessId(hwnd, &dwPID);
if (0 == dwPID)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Open the desktop shell process in order to query it (get the token)
hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
if (!hShellProcess)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Get the process token of the desktop shell.
ret = OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken);
if (!ret)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Duplicate the shell's process token to get a primary token.
// Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID;
ret = DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken);
if (!ret)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Start the target process with the new token.
ret = CreateProcessWithTokenWPtr(
hPrimaryToken,
0,
szApp,
szCmdLine,
0,
NULL,
NULL,
&si,
&pi);
if (!ret)
{
dwLastErr = GetLastError();
goto cleanup;
}
// Make sure to close HANDLEs return in the PROCESS_INFORMATION.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
retval = true;
cleanup:
// Clean up resources
if (hShellProcessToken) CloseHandle(hShellProcessToken);
if (hPrimaryToken) CloseHandle(hPrimaryToken);
if (hShellProcess) CloseHandle(hShellProcess);
if (hThreadToken) CloseHandle(hThreadToken);
RevertToSelf ();
if (!retval)
SetLastError (dwLastErr);
return retval;
}
// This function always loads a URL in a non-privileged mode
// If current process has admin privileges, we execute the command "rundll32 url.dll,FileProtocolHandler URL" as non-elevated
void SafeOpenURL (LPCWSTR szUrl)
{
if (IsAdmin ())
{
WCHAR szRunDllPath[TC_MAX_PATH];
WCHAR szUrlDllPath[TC_MAX_PATH];
WCHAR szSystemPath[TC_MAX_PATH];
LPWSTR szCommandLine = new WCHAR[1024];
if (!GetSystemDirectory(szSystemPath, MAX_PATH))
StringCbCopyW(szSystemPath, sizeof(szSystemPath), L"C:\\Windows\\System32");
StringCbPrintfW(szRunDllPath, sizeof(szRunDllPath), L"%s\\%s", szSystemPath, L"rundll32.exe");
StringCbPrintfW(szUrlDllPath, sizeof(szUrlDllPath), L"%s\\%s", szSystemPath, L"url.dll");
StringCchPrintfW(szCommandLine, 1024, L"%s,FileProtocolHandler %s", szUrlDllPath, szUrl);
RunAsDesktopUser (szRunDllPath, szCommandLine);
delete [] szCommandLine;
}
else
{
ShellExecuteW (NULL, L"open", szUrl, NULL, NULL, SW_SHOWNORMAL);
}
}
#if !defined(SETUP) && defined(_WIN64) #if !defined(SETUP) && defined(_WIN64)
#define RtlGenRandom SystemFunction036 #define RtlGenRandom SystemFunction036

View File

@@ -545,6 +545,7 @@ void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, B
BOOL GetSetupconfigLocation (wchar_t* path, DWORD cchSize); BOOL GetSetupconfigLocation (wchar_t* path, DWORD cchSize);
BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void* pattern, size_t patternLen); BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void* pattern, size_t patternLen);
BOOL EnableProcessProtection(); BOOL EnableProcessProtection();
void SafeOpenURL (LPCWSTR szUrl);
#ifdef _WIN64 #ifdef _WIN64
void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed); void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed);
#endif #endif

View File

@@ -957,7 +957,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
if (lw == IDM_HOMEPAGE ) if (lw == IDM_HOMEPAGE )
{ {
ArrowWaitCursor (); ArrowWaitCursor ();
ShellExecute (NULL, L"open", L"https://www.veracrypt.fr", NULL, NULL, SW_SHOWNORMAL); SafeOpenURL (L"https://www.veracrypt.fr");
Sleep (200); Sleep (200);
NormalCursor (); NormalCursor ();