Using reg.exe in code with limited privileges - c#

I need to get installed software list under restricted user.
I use this code:
string fullString = string.Format("EXPORT \"{0}\\{1}\" \"{2}\" /y", hiveString, keyPath, Path.GetTempFileName());
Log(fullString);
var p = Process.Start(new ProcessStartInfo("reg.exe", fullString) {RedirectStandardOutput = true, UseShellExecute = false,WorkingDirectory = Directory.GetCurrentDirectory()});
Log("Output: " + p.StandardOutput.ReadToEnd());
p.WaitForExit();
On my dev machine I see normal output:
operation completed successfully
No matter what account I use - admin or restricted user.
Then I ran this app on Windows XP under restricted user. And see next in log:
"Output: "
Empty line, yes.
When I run similiar query in cmd - it works fine. I can not understand, what I'm doing wrong.
Why doesn't reg.exe write anything?

You can't call reg.exe without admin privileges. At least not unless you are on Windows Millennium (that's why it doesn't even appear on MSFT Web Site). Imagine what one could do if it were possible...

Related

windows cli from c#: how to run as admin user without password?

I'm writing a simple Windows form that runs some commands through cmd.exe in C#. The first code works correctly because I used the process.StartInfo.Verb = "runas" statement.
During execution I agreed to running as administrator without any password.
Now I'm modifying the code because, sometimes, the commands return a choice (like [y/n]) so I want to examine the output and, eventually, send a choice.
To do this, I need to redirect in/out flow (StandardInput/StandardOutput) and set process.StartInfo.UseShellExecute = false. This results in Windows not asking me to open as administrator. To solve this, I used the following:
process.StartInfo.Domain = "DESKTOP-2K....";
process.StartInfo.UserName = "Marco";
SecureString password = new SecureString();
process.StartInfo.Password = password;
I get information with command -> wmic useraccount list full.
Unfortunately, this doesn't work.
The curious things is that, with wmic command, I not read that "Marco" is administrator account but I read that "Administrator" is an administrator account. Therefore, Marco doesn't require a password instead Administrator requires a password.
Other curious thing is that Marco is an administrator account if I go to -> Control Panel -> Accounts -> User Accounts
Please help me.
regards

C# start process as user from a different domain

I am trying to open some locally installed applications from my home computer but run them using my work Windows account. I need to run them using my work account because they authenticate with Windows Authentication and there are natural restrictions using my local home Windows user.
For example, I can successfully run SSMS using my work account if I run this command:
runas /netonly /noprofile /user:MYWORKDOMAIN\MYWORKUSERNAME "C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\ssms.exe"
My home computer is connected via a VPN but otherwise it is not under my work domain. The above command NEEDS the /netonly option to work.
However, I have a number of other apps that need this functionality and I am trying to write a small C# app that can run these apps without needing to enter my password each time. I have tried using the below snippet without success - I get an error saying the username and password are incorrect (they aren't).
var process = new System.Diagnostics.Process
{
StartInfo =
{
Domain = "MYWORKDOMAIN",
FileName = AppPath,
Password = password,
UserName = username,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Normal,
}
};
process.Start();
Can someone tell me what I'm missing please?
EDIT 1 - results for nickpeq's answer
After implementing the code from the provided link, I used it like this:
Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);
using (new Impersonator("MYWORKUSERNAME", "MYWORKDOMAIN", "MYWORKPASSWORD"))
{
Console.WriteLine("During impersonation: " + WindowsIdentity.GetCurrent().Name);
}
Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
And these were the results:
Before impersonation: DESKTOP-WIN11\mark
During impersonation: DESKTOP-WIN11\mark
After impersonation: DESKTOP-WIN11\mark
There was no error thrown (so I guess that's progress 😅)
Check this answer: https://stackoverflow.com/a/11672293/7292986
I see many unanswered StackOverflow threads trying to do the same thing, but it looks like this answer may actually achieve what you are looking for (albeit with significant complexity).

c# run application as another user fails with System.ComponentModel.Win32Exception

I work with emergency services and they have an application that uses map files to let them know where they need to go and it uses GPS to let them know where they are. We have to update the map files as things change and before I started here they were being done through VB scripts which started to fail. I decided to code my own app in C# to do this which works fine.
I created a package in SCCM 2012 that caches all of the files locally and then it compares the files in the cache to what is on the machine and then replaces any older files. This all works fine but the application they use called MobileCAD locks the files so I have to kill this process and then do the file copy and start the application again. We never know when an emergency happens so this update may start when they are on the road so it is important that it starts the application again as soon as possible. If it does not start the application then the emergency services people may try to do so manually but if core files are being updated then it may not start or cause issues.
I coded my application which uses an app manifest to force it to run as an administrator for the file copy. This application is run through SCCM which uses the local 'System' account to do all of the work and killing MobileCAD and copying files which works great. What I originally found was that it does start MobileCAD but it does so under the System account and the process would be there but it was not visible. I think this is the same problem they were originally having so the emergency services people would need to reboot the computer and wait for it to log back in and then start the wireless service so they could get back into MobileCAD.
To address this issue I did research and found that I could use the ProcessStartInfo in .NET and force it to use another account. As we use an automatic logon for these machines the users name, password, and domain are all in the registry so it was easy to pull it out and inject it into the code. Awesome, looks like it is easy enough so I code it up and sure enough it works perfectly when run under my admin account. In my basic testing everything worked perfectly until I try the same in SCCM, now it fails with the following error message.
System.ComponentModel.Win32Exception (0x80004005): Access is denied
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at UpdateFDM.Program.StartProcess(String processName)
I am sorry for all of the words but I believe it helps if you have a good understanding of the issue and what I am trying to do. I have also hard coded the user information into the code instead of pulling it from the registry but I get the same error. Again, this works fine under my admin account but fails when it is pushed through SCCM and it is only launching MobileCAD that fails.
This is the code I am using for launching MobleCAD, do you see where my issue may lie? I know SCCM confuses it but SCCM basically runs things just as you would from the command line but it uses the local System account.
Thanks for any help.
// Declares the new start instance
ProcessStartInfo process = new ProcessStartInfo();
// Gets the process to start
process.FileName = processName;
// Maximizes the process windows at start-up
process.WindowStyle = ProcessWindowStyle.Maximized;
// Gets the user name from the autologon information
process.UserName = GetDefaultUserInfo("DefaultUserName");
// Gets the domain for the user
process.Domain = GetDefaultUserInfo("DefaultDomainName");
// Holds the password for the default user
SecureString password = new SecureString();
// Gets the raw password from the registry
string rawPassword = GetDefaultUserInfo("DefaultPassword");
// Copies the password in a secure string
foreach (char ch in rawPassword)
{
password.AppendChar(ch);
}
// Sets the password
process.Password = password;
// Needed to launch the app as the logged on user
process.LoadUserProfile = true;
process.UseShellExecute = false;
// Starts the process
Process.Start(process);
// Process started, return true
return true;

Getting "Access to path... denied" even when app.manifest is set to to run program as administrator

I'm trying to delete a folder off the desktop when I get the error that the path is denied. I've even made my app.manifest start the program as administrator. Now with the code below I can delete the folder successfully, but it seems so unnecessary.
string folder = "c:\\users\\jim\\desktop\\Proto";
ProcessStartInfo process = new ProcessStartInfo("cmd.exe", #"/C " + #"rmdir " + folder + " /s /q");
process.Verb = "runas";
Process p = Process.Start(process);
p.WaitForExit();
Im trying to use ...
string folder = "c:\\users\\jim\\desktop\\Proto";
Directory.Delete(folder, true);
Is it possible to to make that method "runas"?
As far as I know it's impossible to elevate just a single call/command. You'll have to launch a new process that might get blocked by UAC. Some programs seem to do so otherwise (e.g. different Windows dialogs), but they just call another process (or their own executable) with different parameters in background.
Besides that: By default, you should have full access to everything on your own desktop. Or are you trying to modify some other user's desktop?
Well for a start, the user running the application should be able to create a folder on their own desktop.
If the above is the case get rid of the stuff you put in the manifest but don't use a hard coded path
String desktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
Directory.Delete(Path.Combine(desktopFolder,"proto");
If this folder is being deleted for another other user (and admin is another user, elevated or not), then you have to run with elevated all the time, (not a good idea) , or as you are kick off another process with elevated rights to do the elevated stuff.
Take a look at this, it shows you how to run a single method as Admin user

Network Authentication when running exe from WMI

I have a C# exe that needs to be run using WMI and access a network share. However, when I access the share I get an UnauthorizedAccessException. If I run the exe directly the share is accessible. I am using the same user account in both cases.
There are two parts to my application, a GUI client that runs on a local PC and a backend process that runs on a remote PC. When the client needs to connect to the backend it first launches the remote process using WMI (code reproduced below). The remote process does a number of things including accessing a network share using Directory.GetDirectories() and reports back to the client.
When the remote process is launched automatically by the client using WMI, it cannot access the network share. However, if I connect to the remote machine using Remote Desktop and manually launch the backend process, access to the network share succeeds.
The user specifed in the WMI call and the user logged in for the Remote Desktop session are the same, so the permissions should be the same, shouldn't they?
I see in the MSDN entry for Directory.Exists() it states "The Exists method does not perform network authentication. If you query an existing network share without being pre-authenticated, the Exists method will return false." I assume this is related? How can I ensure the user is authenticated correctly in a WMI session?
ConnectionOptions opts = new ConnectionOptions();
opts.Username = username;
opts.Password = password;
ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Process", remoteHost));
ManagementScope scope = new ManagementScope(path, opts);
scope.Connect();
ObjectGetOptions getOpts = new ObjectGetOptions();
using (ManagementClass mngClass = new ManagementClass(scope, path, getOpts))
{
ManagementBaseObject inParams = mngClass.GetMethodParameters("Create");
inParams["CommandLine"] = commandLine;
ManagementBaseObject outParams = mngClass.InvokeMethod("Create", inParams, null);
}
Having followed the link suggested by Isalamon above (thanks) I followed Jestro's advice and have rewritten using psexec.exe (which can be downloaded from http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx) instead of WMI. It feels like a bit of a kludge to do it this way, but it seems to work.
New code for anyone who is experiencing similar problems:
Process proc = new Process();
proc.StartInfo.FileName = "PsExec.exe";
proc.StartInfo.Arguments = string.Format("\\\\{0} -d -u {1}\\{2} -p {3} {4}",
remoteHost,
domain,
username,
password,
commandLine);
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
WMI just uses impersonation when executing the remote process, which does not give you network access. If you are ok going outside managed code, you can just map a UNC path in the remote process WMI started using whatever credentials you want. Then, you have the network access you want. I use NetUseAdd and NetUseDel from netapi32.dll to map the UNC path. See http://pinvoke.net/ for details on the using the APIs.
I know you've sorted it by using PSEXEC, which is a fantastic program, but if you did want to go back to WMI, have you tried enabling the following in your ConnectionOptions:
The flag EnablePrivileges
setting the Impersonation to ImpersonationLevel.Impersonate
Which does the following:
Gets or sets a value indicating whether user privileges need to be
enabled for the connection operation. This property should only be
used when the operation performed requires a certain user privilege to
be enabled (for example, a machine restart).
http://msdn.microsoft.com/en-us/library/system.management.connectionoptions.enableprivileges.aspx
Gets or sets the COM impersonation level to be used for operations in this connection.
http://msdn.microsoft.com/en-us/library/system.management.connectionoptions.impersonation.aspx
I think they should tell your WMI to actually allow the program to have the correct credentials and thus access your network share
You can write all you commands to batch file to the remote machine which includes net use (no need to use a drive letter) to do an authentication. Works fine that way. I am still working on an alternative.

Categories

Resources