-1

I need to invoke windows process by another user with primary token, using jna (java). I am able to peform:

  1. Login with username, domain & password
  2. Duplicate token, to generate primary token with dwDesiredAccess set to 33554432 . I'm not sure on the value, this may be the culprit here. Please guide what's the correct value for this. I need to give MAXIMUM_ALLOWED permission, not sure what's equivalent for that in terms of java Integer
  3. Invoking some random windows command.

On step 3, i'm getting issue that A required privilege is not held by the client. I have tried different ways, OpenThreadToken and AdjustTokenPrivilege, but that didn't work for me.

Can someone please guide me on how to invoke a process using jna with below code.

Note: I need to invoke multiple commands thus, need to use primary token way.


public static void main(String[] args) throws Exception {

    HANDLE loginToken = null;

    HANDLE primaryToken = null;

    try {

        loginToken = performLogin("username", "domain", "password");

        setThreadToken(loginToken);

        primaryToken = createPrimaryToken(loginToken, 33554432);

        invokeCommand(primaryToken);

    } catch (ProcessCreationException e) {

        e.printStackTrace();

    } finally {

        if (loginToken != null)

            Kernel32.INSTANCE.CloseHandle(loginToken);

        if (primaryToken != null)

            Kernel32.INSTANCE.CloseHandle(primaryToken);

    }

}


private static HANDLE performLogin(String username, String domain, String password) throws ProcessCreationException {

   HANDLEByReference pointer = new HANDLEByReference();

   invokeWindowsMethod("login", () -> Advapi32.INSTANCE.LogonUser(username, domain,
 password, WinBase.LOGON32_LOGON_NETWORK, WinBase.LOGON32_PROVIDER_DEFAULT, pointer));

    return pointer.getValue();

}


private static HANDLE createPrimaryToken(HANDLE loginToken, int desiredAccess) throws ProcessCreationException {

    System.out.println("dwDesiredAccess:" + desiredAccess);

    HANDLEByReference pointer = new HANDLEByReference();

    invokeWindowsMethod("duplicated", () -> Advapi32.INSTANCE.DuplicateTokenEx(

            loginToken,

            desiredAccess,

            null,

            SECURITY_IMPERSONATION_LEVEL.SecurityDelegation,

            TOKEN_TYPE.TokenPrimary,

            pointer

    ));

    return pointer.getValue();

}

private static void invokeCommand(HANDLE primaryToken) throws ProcessCreationException {

    STARTUPINFO si = new STARTUPINFO();

    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

    pi.clear();


    invokeWindowsMethod("invokeCommand", () -> Advapi32.INSTANCE.CreateProcessAsUser(

            primaryToken,
            null,

            "whoami",

            null,

            null,

            true,

            1024,

            null,

            null,

            si,

            pi));

}


private static void invokeWindowsMethod(String method, Supplier<Boolean> processor) throws ProcessCreationException {

    Boolean res = processor.get();

    System.out.println(method + " : " + res);

    if (!res) {

        throw lastErrorProcessCreationException(method, Kernel32.INSTANCE.GetLastError());

    }

}


private static ProcessCreationException lastErrorProcessCreationException(String context, int errorCode) {

    return new ProcessCreationException(String.format("[%s] %s", context,
 Kernel32Util.formatMessageFromLastErrorCode(errorCode)));

}

Ravi Soni
  • 953
  • 1
  • 7
  • 17

1 Answers1

0

You are

Invoking some random windows command.

And you need

A required privilege is not held by the client

The Windows API generally tells you what privileges each command needs.

I assume you found the value 33554432 in someone's code somewhere. It's generally more readable if you use the appropriate constant corresponding to its meaning. A decimal to hex converter tells me that's 0x2000000 which is WSManFlagSkipRevocationCheck. Define that constant and use it in your code ... if indeed that's the one you need. But what you really need is shown by the docs for the command you are running:

The "Random Command" you chose is CreateProcessAsUser which tells you exactly how to handle this error:

Typically, 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.

So your calling process doesn't have the right privileges. You need to enable those. See this answer for how to enable a privelege on the current process using Java/JNA code (change the SE_DEBUG_NAME to the privilege you are requesting).

Further, the CreateProcessAsUser docs continue:

If this function fails with ERROR_PRIVILEGE_NOT_HELD (1314), use the CreateProcessWithLogonW function instead. CreateProcessWithLogonW requires no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use CreateProcessWithLogonW to create a process with alternate credentials.

Requiring no special privilege seems a better option for you to use than a "Random windows command" that needs other steps.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63