Intended Process is not created as impersonated/logged on user. Stack: Waffle, Spring security and JNA
Asked Answered
D

0

0

When user tries to access the controller method from web application, the below code will be executed to create a process as impersonated/logged on user. Below code executed without any issues. New Notepad has been created but the process owner is server user not the logged on user. Please let me know what I am missing from the below code to create a process as impersonated user.

Note: Running eclipse/sts as Admin user and the primary token (processToken) has all the required privilege for impersonation.

public String createProcessAsUser(HttpServletRequest req) {

        // Enabled Error handler to all the functions -- No Errors
        HANDLEByReference processToken = new HANDLEByReference();
        HANDLE processHandle = Kernel32.INSTANCE.GetCurrentProcess();

        // Get Current process Handle -- Access Token of the active user
        if (!Advapi32.INSTANCE.OpenProcessToken(
                processHandle, WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY | WinNT.TOKEN_ALL_ACCESS
                        | WinNT.TOKEN_ASSIGN_PRIMARY | WinNT.TOKEN_ADJUST_PRIVILEGES | WinNT.TOKEN_IMPERSONATE,
                processToken)) {
            int rc = Kernel32.INSTANCE.GetLastError();
            if (rc != W32Errors.ERROR_NO_TOKEN) {
                throw new Win32Exception(rc);
            }
        }

        WinNT.LUID luid = null;
        WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(2);

        /*
         * Required privileges to assign token for Impersonation. 
           User doesn't have SE_ASSIGNPRIMARYTOKEN_NAME privilege, so couldn't be 
           enabled/disabled
         * 
         */
        String[] privileges = { WinNT.SE_INCREASE_QUOTA_NAME, WinNT.SE_ASSIGNPRIMARYTOKEN_NAME };

        for (int i = 0; i < privileges.length; i++) {
            luid = new WinNT.LUID();
            if (Advapi32.INSTANCE.LookupPrivilegeValue("", privileges[i], luid)) {
                tp.Privileges[i] = new LUID_AND_ATTRIBUTES(luid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
            } else {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
            }
        }

        // Enable Privileges to the existing Process handle/Token
        if (!Advapi32.INSTANCE.AdjustTokenPrivileges(processToken.getValue(), false, tp, tp.size(), null,
                new IntByReference())) {
            Win32Exception error = new Win32Exception(Kernel32.INSTANCE.GetLastError());
            System.out.println(error.getMessage());
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }

        // Impersonate logged on user
        if (!Advapi32.INSTANCE.ImpersonateLoggedOnUser(processToken.getValue())) { /* This returns true */
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }

        WinNT.HANDLEByReference primaryToken = new WinNT.HANDLEByReference();

        // Duplicate impersonated token to create a primary token to invoke the
        // CreateProcessAsUser
        if (!Advapi32.INSTANCE.DuplicateTokenEx(processToken.getValue(),
                WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY | WinNT.TOKEN_ASSIGN_PRIMARY | WinNT.TOKEN_ADJUST_DEFAULT
                        | WinNT.TOKEN_ALL_ACCESS,
                null, WinNT.SECURITY_IMPERSONATION_LEVEL.SecurityDelegation, WinNT.TOKEN_TYPE.TokenPrimary,
                primaryToken)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }

        WinBase.STARTUPINFO startupInfo = new WinBase.STARTUPINFO();
        WinBase.PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
        if (!Advapi32.INSTANCE.CreateProcessAsUser(primaryToken.getValue(), "C:\\Windows\\notepad.exe", null, null,
                null, false, WinNT.CREATE_NEW_CONSOLE | WinNT.CREATE_UNICODE_ENVIRONMENT, null, null, startupInfo,
                processInfo)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        return String.format("New Process created ");
    }

Notepad Process privileges from process explorer

Token Assign Primary

SeAssignPrimaryTokenPrivilege

User Rights Assignment

Dimeter answered 26/7, 2022 at 11:32 Comment(7)
@Daniel Widdis Thanks for your help so far! I have updated the code as above. Now OpenProcessToken , AdjustTokenPrivileges, DuplicateTokenEx , ImpersonateLoggedOnUser and CreateProcessAsUser works without any errors. Still newly created process owner is not the impersonated user. I might be missing some minor config changes or order of these function executions. Any small pointers/suggestions would be grateful. TIA!Dimeter
In addition to WinNT.SE_INCREASE_QUOTA_NAME try assigning SE_ASSIGNPRIMARYTOKEN_NAME. Also consider trying TOKEN_ALL_ACCESS to start with to see if it works, in case you've missed a TOKEN_*. (docs)Grist
Also, is Kerberos Delegation enabled?Grist
I have added TOKEN_ALL_ACCESS to the token and SE_ASSIGNPRIMARYTOKEN_NAME privilege. Since the current user doesn't have the the privilege SE_ASSIGNPRIMARYTOKEN_NAME , this can not be enabled/disabled using AdjustTokenPrivileges . But no luck, still facing the same issue. SpringBoot properties for Waffle, waffle.sso.enabled=true; waffle.sso.protocols=NTLM; waffle.sso.basic-enabled=false; I am using negotiate security package. Do I need to specify Kerberos Delegation anywhere?Dimeter
"Since the current user doesn't have the the privilege SE_ASSIGNPRIMARYTOKEN_NAME , this can not be enabled/disabled using AdjustTokenPrivileges" from the docs here for TOKEN_ASSIGN_PRIMARY this is required. As for Kerberos Delegation, I saw that mentioned as a requirement at other SO posts on the topic.Grist
As stated in the MS docs, "the process that calls the CreateProcessAsUser function must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable." . This SE_ASSIGNPRIMARYTOKEN_NAME privilege is not mandatory right ? learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/… And Also not sure that whether it will be allowed to be enabled by corporate policy. Seems the Windows OS is running on service pack 1 and it is not supported to enable this privilege.Dimeter
This has gone far beyond my Java/JNA expertise and google-fu. Sorry I can't help much more.Grist

© 2022 - 2024 — McMap. All rights reserved.