chef / mixlib-shellout

mixin library for subprocess management, output collection
Apache License 2.0
132 stars 76 forks source link

Cannot launch process with elevated token on Windows #142

Closed smurawski closed 7 years ago

smurawski commented 7 years ago

When providing alternate credentials and the alternate user is in the administrators group, the process being shelled out to does not have an administrative token and cannot perform actions that require elevation.

Repro:

Requires a user in the administrators group. In the example, there is a local user account tester which is in the local Administrators group.

admin_check = <<-EOH
ZgB1AG4AYwB0AGkAbwBuACAAVABlAHMAdAAtAEEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIAIAAgAAoAewAgACAACgAgACAAIAAgACQAdQBzAGUAcgAgAD0AIABbAFMAZQBjAHUAcgBpAHQAeQAuAFAAcgBpAG4AYwBpAHAAYQBsAC4AVwBpAG4AZABvAHcAcwBJAGQAZQBuAHQAaQB0AHkAXQA6ADoARwBlAHQAQwB1AHIAcgBlAG4AdAAoACkAOwAKACAAIAAgACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwBlAGMAdQByAGkAdAB5AC4AUAByAGkAbgBjAGkAcABhAGwALgBXAGkAbgBkAG8AdwBzAFAAcgBpAG4AYwBpAHAAYQBsACAAJAB1AHMAZQByACkALgBJAHMASQBuAFIAbwBsAGUAKABbAFMAZQBjAHUAcgBpAHQAeQAuAFAAcgBpAG4AYwBpAHAAYQBsAC4AVwBpAG4AZABvAHcAcwBCAHUAaQBsAHQAaQBuAFIAbwBsAGUAXQA6ADoAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgApACAAIAAKAH0ACgB0AGUAcwB0AC0AYQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgA=
EOH

whoami = Mixlib::ShellOut.new("powershell.exe -noprofile -encodedcommand \"#{admin_check}\"", :user => "tester", :password => "P2ssw0rd!")
whoami.run_command.stdout

This will return "true" if elevated, "false" if not.

NimishaS commented 7 years ago

I created a user and added it to the Administrators group.

  1. Ran the following commands from powershell console: Note: The code below returns True if the user has Administrator role.

    $identity  = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object System.Security.Principal.WindowsPrincipal( $identity )
    Write-Output $principal.IsInRole( [System.Security.Principal.WindowsBuiltInRole]::Administrator )

    It returned False. According to the issue it should have returned True.

  2. Ran the same code using mixlib-shellout and got False again.

  3. Also tried running the code shared by @smurawski:

    
    admin_check = <<-EOH
    ZgB1AG4AYwB0AGkAbwBuACAAVABlAHMAdAAtAEEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIAIAAgAAoAewAgACAACgAgACAAIAAgACQAdQBzAGUAcgAgAD0AIABbAFMAZQBjAHUAcgBpAHQAeQAuAFAAcgBpAG4AYwBpAHAAYQBsAC4AVwBpAG4AZABvAHcAcwBJAGQAZQBuAHQAaQB0AHkAXQA6ADoARwBlAHQAQwB1AHIAcgBlAG4AdAAoACkAOwAKACAAIAAgACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwBlAGMAdQByAGkAdAB5AC4AUAByAGkAbgBjAGkAcABhAGwALgBXAGkAbgBkAG8AdwBzAFAAcgBpAG4AYwBpAHAAYQBsACAAJAB1AHMAZQByACkALgBJAHMASQBuAFIAbwBsAGUAKABbAFMAZQBjAHUAcgBpAHQAeQAuAFAAcgBpAG4AYwBpAHAAYQBsAC4AVwBpAG4AZABvAHcAcwBCAHUAaQBsAHQAaQBuAFIAbwBsAGUAXQA6ADoAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgApACAAIAAKAH0ACgB0AGUAcwB0AC0AYQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgA=
    EOH

whoami = Mixlib::ShellOut.new("powershell.exe -noprofile -encodedcommand \"#{admin_check}\"", :user => "tester", :password => "P2ssw0rd!") whoami.run_command.stdout


This too returned `False`.

4. Running any `Start-Process` command from the powershell console with this user gives UAC prompt.

Since the behavior is same while using either powershell console or `mixlib-shellout`, this seems like a default behavior of Windows and not related to `mixlib-shellout`.

@mwrock , @btm , please review.
NimishaS commented 7 years ago

Got a response from Gary: https://github.com/chef/chef/issues/6086#issuecomment-311966406

I didn't run Powershell console as Administrator.

NimishaS commented 7 years ago

@mwrock , I need some input. If we decode the admin_check above, we get:

$user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)  

The code above already has GetCurrent() user in it. And we are passing user and password again in this line:

whoami = Mixlib::ShellOut.new("powershell.exe -noprofile -encodedcommand \"#{admin_check}\"", :user => "tester", :password => "P2ssw0rd!")

Is this required? This returns False. If we execute just whoami = Mixlib::ShellOut.new("powershell.exe -noprofile -encodedcommand \"#{admin_check}\""), then we get True while running via the alternate user too.

@btm, @mwrock , please suggest if this is an expected behavior.

mwrock commented 7 years ago

What that tells me is that the logon token mixlib-shellout creates is not an elevated token. Taking a look at the mixlib-shellout code that starts the new process, It calls CreateProcessWithLogonW unless it is being called from inside a service in which case it calls CreateProcessAsUser. In the scenario you are testing with - just running from a local console - its using CreateProcessWithLogonW which will use the "filtered" logon token and not the one with full admin privileges.

As it happens, this is something I'm going to have to investigate for Habitat soon but I think using CreateProcessAsUser may be what you need but I'm not certain. That does require alot of extra "goo" to work in an interactive console.

mwrock commented 7 years ago

I had to do some research around this topic today for Habitat and learned that CreateProcessAsUser can indeed use an elevated token but not for interactive logons. So when calling the LogonUserW, you must use either LOGON32_LOGON_BATCH or LOGON32_LOGON_SERVICE.

So the bottom line is you cannot use CreateProcessWithLogonW and instead must create a token with LogonUserW and then use that token with CreateProcessAsUser. The tricky thing here is getting the DACL of the windows station and desktop configured propperly. While CreateProcessWithLogonW does this for you under the hood, CreateProcessAsUser requires you to do it yourself in an interactive context.

Basically you will need to generate the equivilent of this C++ code via FFI.

NimishaS commented 7 years ago

Fixed in https://github.com/chef/mixlib-shellout/pull/149. @btm, @mwrock , please close this.

btm commented 7 years ago

This is in Chef 13.3.18+