WinRb / winrm-elevated

Runs PowerShell commands as elevated over Windows Remote Management (WinRM) via a scheduled task
Apache License 2.0
27 stars 17 forks source link

Path assumptions #21

Open jimbobmcgee opened 7 years ago

jimbobmcgee commented 7 years ago

There are some assumptions made with regards either to installation paths, or to applications being on the PATH variable...

  1. /lib/winrm/shells/elevated.rb, line 71

    • For instance, I have an old server instance that has been through the OS upgrade + virtualisation mill, so is actually limping along with a Windows path of E:\WINNT...
    • perhaps replace c:/windows with path determined by remote system, e.g. ask the Powershell shell for the Windows path before uploading the script:

      • Sticking with WINDIR\Temp:

        $uploaddir = [IO.Path]::Combine(($env:SYSTEMROOT, $env:WINDIR, 'c:\windows' -ne $null)[0], 'temp')

        (i.e. falling back to c:\windows if neither variable is set)

      • alternatively, use the common (all users) AppData folder in case of a write-permissons failure to C:\Windows (i.e if using an non-admin account)

        $uploaddir = ([Environment]::GetFolderPath('CommonApplicationData'), 'c:\windows\temp' -ne $null)[0]
  2. /lib/winrm-elevated/scripts/elevated_shell.ps1, line 54

    • If the PATH variable is trimmed, the literal string cmd will not work (or may allow someone to place another exe called 'cmd.com' in the way, which will be run instead);
    • You can reasonably ask Powershell where cmd.exe is using $env:COMSPEC or [IO.Path]::Combine([Environment]::SystemDirectory, 'cmd.exe')
  3. /lib/winrm-elevated/scripts/elevated_shell.ps1, line 61

    • Similarly, if not on the PATH, the literal string powershell.exe may not work as intended
    • Again, you can ask Powershell where powershell.exe, e.g. "$PSHOME\powershell.exe"
    • If any of the paths folded into your $arguments end up with spaces or special characters in them, you will need to double-quote the path, but you should not double-quote if they don't need it — you are, of course, fighting both Scheduled Tasks's quoting requirements, cmd.exe's quoting requirements and Powershell's quoting requirements all at once...

      $psexe = if ($PSHOME -match '\s') { "`"$PSHOME\powershell.exe`"" } else { "$PSHOME\powershell.exe" }

PS: if you are building up XML in Powershell, using user-supplied parameters, you might want to escape them first. Easiest way I can think of is passing through XText, e.g.

Add-Type -AssemblyName System.Xml.Linq
$arguments = "/c $psexe ... 2>&1"
$arguments = (New-Object Xml.Linq.XText($arguments)).ToString()
#> outputs: /c E:\WINNT\system32\WindowsPowerShell\v1.0\powershell.exe ... 2>&1

# or...
$task_xml = $task_xml.Replace("{username}", (New-Object Xml.Linq.XText($username)).ToString())