Creating a secure desktop on current Windows Session (Winsta0\default)

2

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:

  • User with standard (non-admin) privileges
  • System is protected by SRPs/AppLocker
  • No malware process is stared as separate process only as part of an exploit in an attacked process (e.g. in browser, office, or pdf viewer).

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;
}
windows
winapi
asked on Stack Overflow Dec 1, 2018 by (unknown user) • edited Dec 2, 2018 by (unknown user)

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0