Start runas as subprocess and write password to stdin? - c#

I am trying to write a C# program that is supposed to call the runas tool from windows and input the password automatically.
What I tried:
Process runas = new Process();
runas.StartInfo.FileName = "runas";
runas.StartInfo.UseShellExecute = false;
runas.StartInfo.RedirectStandardInput = true;
runas.StartInfo.Arguments = "\"/user:domain\\username\" \"cmd.exe\"";
runas.Start();
StreamWriter stream = runas.StandardInput;
stream.WriteLine("our super secret password");
stream.Flush();
stream.Close();
runas.WaitForExit();
runas.Close();
What happended:
I get the following output.
Please enter the password for "...":
Trying to execute cmd.exe as user "kfz\dummy"...
RUNAS-ERROR: cmd.exe could not be executed
1326: Authentication failed: unknown username or password.
(translated by me from my german windows)
Yes, I quadrupel checked the password and username. Entering everything by hand in the command line works fine.
What I experimented with:
I tried redirecting the Output as well and reading from it, no success.
I tried different variants of writing to the stream:
stream.Write("our super secret password");
stream.Write("our super secret password\n");
stream.Write("our super secret password\r\n");
All results in the same behaviour.
What I noticed:
The runas process seems not to wait for me to write to the stream.
I added a Sleep before writing and I immediately got the above output.
I am afraid runas uses some nonstd-input.....
Research result:
Upon trying to find out what kind of input runas uses I was not successfull.
I found an alternative to the windows builtin runas here however I would prefer not to use it although I might fall back to it if it is impossible to do.
EDIT:
Ok I found sources that say microsoft deliberately prevented people from doing that.....
I hate it when someone does that! If I WANT to use something that is not secure then who is microsoft to keep me from that!
Sorry I got off topic.
One question remains... Can we still get around it somehow? Can we hack runas? ;)

The whole reason why you're not supposed to do that is because there's an API for that.
No need to use runas.
ProcessStartInfo lets you specify the UserName and Password directly.
For example:
var psi = new ProcessStartInfo();
psi.Domain = "YourDomain";
psi.UserName = "YourUserName";
psi.Password = securePassword;
psi.FileName = "cmd.exe";
Process.Start(psi);

Related

Process.Start with username of 'Everyone'?

I would like to call Process.Start with some user having limited-privilege because the run program may contain malicious code. Here I think Everyone should be right to try first and I think that it does not have any associated password.
However the following code will complain about incorrect username or password (of course the username does exist, so looks like it's about the password):
var startInfo = new ProcessStartInfo("some_exe");
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.UserName = "Everyone";
startInfo.Domain = "mydomain";
startInfo.UseShellExecute = false;
Process.Start(startInfo);
If this is not possible, I have to somehow dynamically create an user account having limited-privilege with full username/password to use for Process.Start.
In .NET core, we cannot use AppDomain to create sandbox, the only recommended approach here is to try branching another process with less/limited privileged.
The SID Everyone is not a user, it's a special system SID (a bit like a group). So you can't use it to "run as".
You need to create a user specifically for that purpose.
You should specify the domain name as well, or user name in UPN format, user#DNS_domain_name, according to MSDN. Also, WorkingDirectory must be set

OS Command Injection from Process.Start

My application is using Process.Start for opening another application to run. VeraCode [a security software scanning tool] reported this command as OS Command Injection Vulnerable. I would like to get some comment. I have found a lot of information on the web regarding to filter the input or to constraint the program name; however, I am curious to see if there's any other alternatives of using Process.Start?
Edit:
Thanks for the comment, here is one of the sample, and yes, it is getting input from users:
public static void Run(string fileName, string arguments, bool waitForExit)
{
Process p = Process.Start(fileName, arguments);
if (waitForExit)
p.WaitForExit();
}
Thanks!
This is a command injection vulnerability because you have not filtered out the users input from the function and directly appended to the process.start()
Due to this, the tool has marked it as a vulnerability.
To avoid this issue you should use regex method to filter out the bad characters and depending on what that function is going to do when it gets run.
for eg. you function is created only to check from this path c:/users/docs.txt
then that function should not get executed for c:/admin/docs.txt.
This is how you need to validate before sending the user data directly into the process.
For more information refer this awesome link : https://dotnet-security-guard.github.io/SG0001.htm
or
https://www.veracode.com/security/dotnet/cwe-78
The Process class is nothing else then a Managed wrapper class the the Native Create Process and its Variations like Create Process As User .
Process MSDN
Process
SourceCode
I don't think that there is another way to start a process than this, because every other solution would also call the WinAPI function. ( because this function (or its overloads and Variations) is the only way to start a process in Windows).
Personally, I have not heard anything about a problem with Process.Start please clarify the problem
regards
I ran into this as well. You need to set the UseShellExecute property to false. Then Veracode will not consider it a vulnerability.
using (WinProcess myProcess = new WinProcess())
{
myProcess.StartInfo.FileName = "notepad.exe";
myProcess.StartInfo.Arguments = Path.GetFileName(fullPath);
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(fullPath);
myProcess.StartInfo.RedirectStandardOutput = false;
myProcess.Start();
}

How to give IIS AppPool Desktop Rights

The action I need help about, is to execute a EXE file on own servers disk from a intranet-webpage, which IIS are on same server-installation. The webpage use a business layer to execute a ProcessStart together with given parameters.
When I perform the execution from web, the taskmanager show me that the application are starting up with the IIS AppPool of webpage as user. Few seconds later it's killed. In my database logs, I can see;
The Microsoft Jet database engine cannot open the file '\\computer\pathfile.ext'. It is already opened exclusively by another user, or you need permission to view its data.
That's correct. The EXE tool are, in turn, loading files from other computers. This is a special behavior which are well studied and well working while using the tool from desktop.
My goal/question,
I want this web-function-call behave with desktop rights. Is it possible at all?
The IIS AppPool have a regular setup with account ApplicationPoolIdentity. I appeared to be "lucky unwise", without knowledge about how much IIS 7.5 and Windows Server 2008 R2 raised the security model since <=IIS6.
I tried to change the app-pool user to NetworkService, Administrator.
I tried to set the application with app-pool as exec/read right
I even tried to let webapp to run a batch-file with a call to application inside..
Then I was begin to change the ProcessStart-behavior. And here, I
don't know much of what to do. I tried to add VERB runas. Force a
password prompt is not a solution here. I tried to simulate a
username/password. No luck there. I also tried to add runas /user:
blabla as parameters with ProcessStart, after used /savecred in a
desktop command window once. No luck there.
Maybe this should work but I just don't understand the correct setup of properties. I add the ProcessStart code snippet below, also added some commented code to let you see what I tried.
public string RunProcess(ApplicationType type, int param)
{
currentSelection = GetApplicationType(type);
ProcessStartInfo info = new ProcessStartInfo(currentSelection.Path);
info.CreateNoWindow = false;
info.UseShellExecute = true;
//info.UseShellExecute = false;
//info.ErrorDialog = false;
//info.UserName = "dummyUsEr";
//info.Password = this.SecurePwd("DummyPWd");
info.WindowStyle = ProcessWindowStyle.Normal;
info.Arguments = string.Format(" {0}", param.ToString());
using (Process exec = Process.Start(info))
{
try
{
exec.WaitForExit();
}
catch
{
}
}
return output;
}
EDIT
Just to be clear, and perhaps help some another guy/girl browsing to this question, I attach the snippet of Password-generation,
protected System.Security.SecureString SecurePwd(string pwd)
{
SecureString securePwd = new SecureString();
foreach (char ch in pwd.ToCharArray())
securePwd.AppendChar(ch);
return securePwd;
}
I see that you've tried putting in a specific username and password for the process start impersonation, but you say that the process accesses files on another computer and I don't see any mention of specifying a domain name which presumably you would need to access remote files?
So like this:
info.Domain = "domainname";
info.UserName = "dummyUsEr";
info.Password = "DummyPWd";
Also, what does this.SecurePwd() do and have you tried it with just the straight password string that you're passing into it?

Send prompt input to Diagnostics.Process

I'm currently solving a problem of starting external tool from .net app.
I have this part of code:
proc.StartInfo = new ProcessStartInfo(_app, _args);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
But, after starting application I get an error to StandartError output witn promt confirmation answer "enter y/n".
I've already tried to input "y" via standart input, right after starting process, but still get the same error.
var standartInput = proc.StandardInput;
standartInput.AutoFlush = true;
standartInput.WriteLine("y");
standartInput.Close();
I'd really appreciate any help. Thanks.
PS: PuTTY Secure Copy client - is the external app I'm using from code. There is a confirmation promt, when running app for first time to save servers fingerprint in system registry.
The code looks OK to me. Maybe you need to sleep for a second or something before writing the "y". I would imagine that the program takes a little while to ask the user for input

strange behaviour on another process via Process.Start(startInfo)

Our C# (V3.5) application needs to call another C++ executable which is from another company. we need to pass a raw data file name to it, it will process that raw data (about 7MB) file and generate 16 result files (about 124K for each).
The code to call that executable is this:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = exePath;
startInfo.Arguments = rawDataFileName;
try
{
Process correctionProcess = Process.Start(startInfo);
correctionProcess.WaitForExit();
}
catch(nvalidOperationException ex)
{
....
}
catch(...)
...
It works fine. Now we have new raw data. After replace the old raw data with the new raw data file. That executable process never return to us. It will hang forever. If we kill our C# application, those result files will be generated in the target directoy. It looks like the executable does create those result files but has issue to write to the disk and return to us until the process is terminated.
It is NOT like this with the old raw data file.
When we run the executable with the new raw data directly (no from our C# app call), it works fine. This means this executable has no problem with the new raw data.
My question 1: what's the possible causes for this behaviour?
Now I change our code with startInfo.UseShellExecute = true; and add startInfo.WorkingDirectory= ..., and disabled
//startInfo.RedirectStandardError = true;
//startInfo.RedirectStandardOutput = true;
Then it works.
My question 2: why use Windows Shell solve this issue?
My question 3: why it works before without using Shell?
My question 4: when we should use Shell and When shouldn't?
thanks,
Several possibilities:
You are redirecting output and error but not reading it. The process will stall when its stdout or stderr buffer fills up to capacity.
The program might be displaying an error message and waiting for a keypress. You are not redirecting input nor check stderr, that keypress will never come.
Some programs, xcopy.exe is a very good example, require stdin to be redirected when you redirect stdout. Although the failure mode for xcopy.exe is an immediate exit without any diagnostic.
Seeing it fixed when you kill your C# program makes the first bullet the likeliest reason.
I know this, it is a very common problem. I has to do with the output, which must be handled asynchronously. You just can't WaitForExit when output exceeds certain amount of data.
You need to add
myStdErr= correctionProcess.StandardError.ReadToEnd();
Only once usually works, if you want to overkill this works ("P" being my Process)
while (!P.HasExited)
stdErr+= P.StandardError.ReadToEnd();
If you don't need the stdout/stderr, just turn the Redirect* properties to false.

Categories