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
Related
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();
}
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);
I've an exe which runs a process to open the DeviceManager. But unfortunately, it asks for a confirmation to provide 'yes' or 'No' which waits for user input for long time and does not continue with execution.
How to get rid of this? I do not want to provide a confirmation again as I do not want to pause the EXE run with this.
StartInfo.CreateWindow = false would not hold for this as it just for starting in another cmd window.
Code below:
Process p = new Process();
p.StartInfo.FileName = "devcon.exe";
p.StartInfo.CreateNoWindow = false;
p.Start();
The messagebox you are seeing is UAC (User Account Control) which was implemented since Vista.
To bypass the box you might be able to try providing the credentials programmatically before launching the process, I can't test but something like this:
var processInfo = new ProcessStartInfo
{
FileName = "devcon.exe",
UserName = "Administrator",
Domain = "yourdomain or leave blank",
Password = adminpassword,
UseShellExecute = false,
};
Process.Start(processInfo);
Otherwise the user will have to have admin rights, or the password!
The other option would be to disable UAC. However that wouldn't allow the user to do anything they couldn't do normally, it will probably tell you that you can't make any changes without the process running as admin.
The parent process should be run by administrator account.
Also show all code please.
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?
I am using the following code to fire the iexplore process. This is done in a simple console app.
public static void StartIExplorer()
{
var info = new ProcessStartInfo("iexplore");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
string password = "password";
SecureString securePassword = new SecureString();
for (int i = 0; i < password.Length; i++)
securePassword.AppendChar(Convert.ToChar(password[i]));
info.UserName = "userName";
info.Password = securePassword;
info.Domain = "domain";
try
{
Process.Start(info);
}
catch (System.ComponentModel.Win32Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The above code is throwing the error The system cannot find the file specified. The same code when run without specifying the user credentials works fine. I am not sure why it is throwing this error.
Can someone please explain?
Try to replace your initialization code with:
ProcessStartInfo info
= new ProcessStartInfo(#"C:\Program Files\Internet Explorer\iexplore.exe");
Using non full filepath on Process.Start only works if the file is found in System32 folder.
You can't use a filename like iexplore by itself because the path to internet explorer isn't listed in the PATH environment variable for the system or user.
However any path entered into the PATH environment variable allows you to use just the file name to execute it.
System32 isn't special in this regard as any directory can be added to the PATH variable. Each path is simply delimited by a semi-colon.
For example I have c:\ffmpeg\bin\ and c:\nmap\bin\ in my path environment variable, so I can do things like new ProcessStartInfo("nmap", "-foo") or new ProcessStartInfo("ffplay", "-bar")
The actual PATH variable looks like this on my machine.
%SystemRoot%\system32;C:\FFPlay\bin;C:\nmap\bin;
As you can see you can use other system variables, such as %SystemRoot% to build and construct paths in the environment variable.
So - if you add a path like "%PROGRAMFILES%\Internet Explorer;" to your PATH variable you will be able to use ProcessStartInfo("iexplore");
If you don't want to alter your PATH then simply use a system variable such as %PROGRAMFILES% or %SystemRoot% and then expand it when needed in code. i.e.
string path = Environment.ExpandEnvironmentVariables(
#"%PROGRAMFILES%\Internet Explorer\iexplore.exe");
var info = new ProcessStartInfo(path);
Also, if your PATH's dir is enclosed in quotes, it will work from the command prompt but you'll get the same error message
I.e. this causes an issue with Process.Start() not finding your exe:
PATH="C:\my program\bin";c:\windows\system32
Maybe it helps someone.
I had the same problem, but none of the solutions worked for me, because the message The system cannot find the file specified can be misleading in some special cases.
In my case, I use Notepad++ in combination with the registry redirect for notepad.exe. Unfortunately my path to Notepad++ in the registry was wrong.
So in fact the message The system cannot find the file specified was telling me, that it cannot find the application (Notepad++) associated with the file type(*.txt), not the file itself.
I know it's a bit old and although this question have accepted an answer, but I think its not quite answer.
Assume we want to run a process here C:\Program Files\SomeWhere\SomeProcess.exe.
One way could be to hard code absolute path:
new ProcessStartInfo(#"C:\Program Files\SomeWhere\SomeProcess.exe")
Another way (recommended one) is to use only process name:
new ProcessStartInfo("SomeProcess.exe")
The second way needs the process directory to be registered in Environment Variable Path variable. Make sure to add it in System Variables instead of Current User Variables, this allows your app to access this variable.
You can use the folowing to get the full path to your program like this:
Environment.CurrentDirectory