I'm currently working in a very restrictive work environment. I know about all the good practices involving SSH: keys, ssh-agent, etc., unfortunately for various reasons I wouldn't really want to go into right now I'm forced to worked within the very strict environment provided.
I realize the "quality" of the work environment and if you read further please try to treat this question as a purely technical question and maybe even a technical challenge (basically don't ask about the politics behind the current situation :) ) .
A Windows VM with a very limited set of tools available. Limited to no access to the Internet and no approval for installing third-party anythings (extra tools, libraries, etc.).
So, the things I have available are:
Using these tools I'd like to automate a very restrictive SSH workflow that looks like this, most of the time:
password based-SSH login using personal account (no SSH keys allowed)
only sudo su - application_account to access the application account (no access to /etc/sudoers, no access to additional sudoers commands, I can only su to the application account)
scripts must prompt for password for each execution
I got a working automation setup with Python + Fabric + prompt automation that did almost everything I wanted. Unfortunately for various reasons this setup is in a "gray area" and it might be blacklisted.
So now I'm trying to use only the tools available within the VM, currently Powershell + plink.exe. Unfortunately I can't seem to get to the final step of the automation, running sudo su - application_account.
I've tried everything I could think of, almost everything based on using System.Diagnostics.Process to launch plink.exe and then:
Either redirect stdin and send a series of commands, including responding to prompts like this:
$process.StandardInput.WriteLine($password)
Or send the password using heredocs:
a)
# One-line heredoc.
echo $password | sudo su - application_account<<< ls
b)
# Multi-line heredoc.
echo $password | sudo -S su - <<END
ls
END
c) or almost any combination involving sudo parameters such as -k, -S, heredoc formats, etc.
Or use the -m parameter of plink.exe to create a file containing the list of commands including a sudo su heredoc execution.
Or trying to use event-based inputs.
...
And many, many others.
I either can't control the process if I redirect all input/output (if I redirect both the process locks and debugging is really hard since I don't have a ton of tools on the VM and I can't see why it's locking).
Or sudo plainly just doesn't accept the password input, as the final deathblow step.
Is it really impossible to control plink.exe in such a restrictive context? I have to note that without access to the application account automation is impossible (i.e. simple personal SSH user automation was achieved long time ago and is not enough).
I'm interested in possible solutions using Powershell or any other tools that come directly with Windows on in advice debugging the setup. Basically how could I see why the process deadlocks. Or any idea, really, that does not involve changing administrative settings anywhere or installing extra tools/apps/libraries.
To add insult to injury, my password contains special characters which the shell doesn't seem to like (I think). Any recommendations for escaping them in Powershell/bash?
$procInfo = New-Object System.Diagnostics.ProcessStartInfo
$procInfo.RedirectStandardInput = $true
$procInfo.FileName="C:\Tools\PuTTY\plink.exe"
$procInfo.Arguments = "-t $sshHost"
$procInfo.UseShellExecute = $false
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $procInfo
[void]$process.Start()
Start-Sleep -m 1000
$process.StandardInput.WriteLine($sshUser)
Start-Sleep -m 1000
$process.StandardInput.WriteLine($password)
Start-Sleep -m 1000
$process.StandardInput.WriteLine("sudo su - $applicationUser")
Start-Sleep -m 5000
$process.StandardInput.WriteLine($password)
It is probably the Windows EOL sequence, that the WriteLine
emits, that does not play nicely with the sudo
. Try using the CR (*nix EOL) explicitly:
$process.StandardInput.Write("sudo su - $applicationUser`n")
$process.StandardInput.Write(($password + "`n"))