I came across the "secure desktop" concept used in Google Chrome and some password managers like KeePass. In Chrome the secure desktop is a access limited desktop for the Chrome processes and well secured, in KeePass the so called secure desktop is for the master password dialog. But in KeePass it seems that they just create another desktop without setting any DACL to really secure it. For me a secure desktop is something that any other process running at the same desktop is not able to open and enter.
I asked myself if it is possible to have a separate desktop where you can start an application and separate it from other processes. This includes e.g. an harvested application which is misused by an attacker to collect keystrokes or the screen.
With the API functions CreateDesktop, ConvertStringSecurityDescriptorToSecurityDescriptor and SetUserObjectSecurity I am able to create another desktop and also to reduce access rights. But if I am too strict I am not able to start a process in there, and if I am too careless the newly created desktop is too open, so an attacker could open the desktop and switch his/her thread into it.
Does anyone of you guys know a SecurityDescriptor string combination I can use, so that the newly created desktop is really secured, so no other application other than the Creator-Process and its child processes who run processes in the secured desktop are able to switch and create processes in there?
Any suggestions or hint is highly welcome.
Assumptions:
Here is my code I am currently using:
#include <windows.h>
#include <stdio.h>
#include <Sddl.h>
#include <AclAPI.h>
#include <time.h>
static const unsigned char nameCharTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-[]()<>@~#.:%&$ยง=";
// create new desktop or open an already existing one
HDESK CreateHiddenDesktop(CHAR *desktop_name)
{
CHAR explorer_path[MAX_PATH];
HDESK hNewDesktop = NULL, hOldDesktop;
STARTUPINFOA startup_info = { 0 };
PROCESS_INFORMATION process_info = { 0 };
ExpandEnvironmentStringsA("%windir%\\notepad.exe", explorer_path, MAX_PATH - 1);
hNewDesktop = OpenDesktopA(desktop_name, NULL, FALSE, GENERIC_ALL);
if (!hNewDesktop)
{
hNewDesktop = CreateDesktopA(desktop_name, NULL, NULL, 0, GENERIC_ALL, NULL);
if (hNewDesktop)
{
hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
if (SetThreadDesktop(hNewDesktop))
{
BOOL bRet = FALSE;
PSECURITY_DESCRIPTOR SecDes = NULL;
// just for us to obtain hex values we can use with ConvertStringSecurityDescriptorToSecurityDescriptor
DWORD access = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS | ACCESS_SYSTEM_SECURITY;
access = DESKTOP_ENUMERATE | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
printf("Access mask in hex: 0x%08x.\n", access);
//bRet = ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:P(D;OICI;GARCSDWDWO;;;WD)(A;OICI;GAGRGWGXRCSDWDWOWPCCCR;;;CO)"), SDDL_REVISION_1, &SecDes, NULL);
bRet = ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:P(OD;OICI;0x010c0040;;;WD)(OA;OICI;0xffffffff;;;WD)"), SDDL_REVISION_1, &SecDes, NULL);
if (bRet)
{
BOOL bSaclDefaulted = FALSE;
BOOL bSaclPresent = FALSE;
PACL SecACL = NULL;
SECURITY_INFORMATION si;
si = DACL_SECURITY_INFORMATION;
if (SetUserObjectSecurity(hNewDesktop, &si, SecDes)) {
printf("SetUserObjectSecurity succeeded.\n");
}
}
// create process and wait until it is initialized and ready
startup_info.cb = sizeof(startup_info);
startup_info.lpDesktop = desktop_name;
CreateProcessA(explorer_path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info);
WaitForInputIdle(process_info.hProcess, INFINITE);
// handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
SetThreadDesktop(hOldDesktop);
}
}
}
return hNewDesktop;
}
int main(int argc, char **argv) {
HDESK hOldDesktop, hNewDesktop;
MSG msg = { 0 };
char desktopName[128] = { 0 };
BOOLEAN binNewDesktop = FALSE;
srand((unsigned int)time(NULL));
for (int i = 0; i < 8; i++) {
desktopName[i] = nameCharTable[rand() % (sizeof(nameCharTable)-1)];
}
// just for debugging and testing: print the desktop's name
printf("Desktop's name: %s\n", desktopName);
hNewDesktop = CreateHiddenDesktop(desktopName);
hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
printf("Entering the hidden desktop\n");
// switch thread into context of new desktop to register hotkeys
SetThreadDesktop(hNewDesktop);
SwitchDesktop(hNewDesktop);
binNewDesktop = TRUE;
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
while (GetMessage(&msg, NULL, 0, 0) != 0) {
if (msg.message==WM_HOTKEY) {
// switch Desktop hotkey
if (msg.wParam == 0) {
if (binNewDesktop) {
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SetThreadDesktop(hOldDesktop);
SwitchDesktop(hOldDesktop);
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
binNewDesktop = FALSE;
}
else {
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SetThreadDesktop(hNewDesktop);
SwitchDesktop(hNewDesktop);
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
binNewDesktop = TRUE;
}
}
// switch Quit hotkey
if (msg.wParam == 1) {
printf("Exiting hidden desktop\n");
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SwitchDesktop(hOldDesktop);
SetHandleInformation(hNewDesktop, 0, 0);
SwitchDesktop(hOldDesktop);
CloseDesktop(hNewDesktop);
CloseDesktop(hOldDesktop);
//getchar();
break;
}
}
}
return 0;
}
User contributions licensed under CC BY-SA 3.0