Registry access blocked when running desktop app from c# aspx application - c#

I have an ASPX web application written in C# in which I call a desktop application running on the cloud web server machine from a button on the web page using a ProcessStartInfo object. The application (SetTags) was failing with a security violation when trying to access a Registry key in HKCU/Software. To get around this, I changed the ProcessStartInfo verb from 'open' to 'runas' and set UseShellExecute to true, which should start the desktop application with Administrator privilege. UAC has been turned off on the cloud server machine. However, the desktop application crashes with a security exception recorded in the event log as follows
Exception Info: System.Security.SecurityException
at System.ThrowHelper.ThrowSecurityException(System.ExceptionResource)
at Microsoft.Win32.RegistryKey.OpenSubKey(System.String, Boolean)
at Global.Common..cctor()
Exception Info: System.TypeInitializationException
at Global.Common.ShowUserError(System.String, System.String)
at SetTagsNS.Program.Main(System.String[])
The crash happens before any data can be written to a log file and the Common.ShowUserError code does not contain any explicit Registry calls. It is as follows:
public static void ShowUserError(string sMsg, string sCaption = "")
{
if (CallingArgs == null) MessageBox.Show(sMsg, sCaption);
else
if (CallingArgs.GetUpperBound(0) != -1)
{
if(sErrFile!="")
{
StreamWriter Err = new StreamWriter(sErrFile,true); // 2nd param = true to append error
// Redirect standard error from the console to the error file.
Console.SetError(Err);
Err.Close();
}
else Console.Error.Write(sMsg);
}
else MessageBox.Show(sMsg, sCaption);
}
The desktop application is built in C# using VS2013 as Windows application rather than a console application, but with the option of not showing any windows if it is launched with command line arguments. A console is attached to the application to record messages when the application is launched with command line arguments. This is done in order to use the same code base for a web application and a desktop application.
The desktop application can be run successfully on the cloud web server (Server2016 OS) from an administrator account from a .bat file using the same parameters as used when it is called from aspx page. runas /trustlevel=0x20000 is used to make the application run with only basic user privilege
What can I do to allow to allow the desktop application access to the Registry when it is called from an aspx page?

The key to allowing executables running on a web server to behave like the same executable running on the desktop and using the registry is to give the Application Pool in which the web app runs the Identity a privileged account, such as Administrator, rather than the default of ApplicationPoolIdentity. This allows access to the Registry, but other things which desktop apps may use, such as special folder locations (eg AppData) may still be different. (It may be opening a security hole but in my case the server contains no sensitive data.) Then using the runas verb in Process.StartInfo allows the executable to behave as a desktop executable does.
In retrospect, the suggestion that the web app should simply share some of the code base (as suggested) would probably have been less work, but as I am very familiar with desktop app development I thought that the best approach would be simply to remove the UI when running the exe from a command line, and just let the web app deal with the interface. As ever, experience keeps a dear school. Once the pitfalls are known (registry access, special folders, any UI interaction) it's certainly possible to operate in this way. Judging from the number of people wanting to find out why bat files run on a web server desktop but not when run from a web app these differences should be more widely known.

Related

How to run ftp-deployed exe as admin from web request?

Goal:
I periodically upload new .exe file to windows server 2003 via FTP and I want to run it manually by hitting Url of a web site on same server. Exe needs to be run under an Admin account, and not the NETWORK SERVICE account.
What I achieved so far:
I have been able to successfully run applications like notepad under the Admin account on the server via a web request by using any of these:
PsExec,
.net process.Start() with credentials supplied to process.StartInfo and even
by impersonating admin and then using process.Start without credentials (http://www.f4cio.com/programmatically-impersonate-in-csharp)
The problem:
The above methods run my exe but Task Manager, or a call to System.Security.Principal.WindowsIdentity.GetCurrent().Name shows me that it is running under NETWORK SERVICE.
I suspect that this file has added security constraints because it arrived from ftp link. Checking run-as-administrator in properties of file is not an option because file will be replaced periodically and all needs to be automated. Also manual server configuration should be minimal or ideally non-existent. Code-only single-web-page solution is ideal. Editing both that asp.net web page and exe is ok. (I tried something with exe self-restarting).
Not sure about this, but I suspect this has to do with you website running under the NETWORK SERVICE user. Whatever privileges your website-user has, the same are probably granted / passed on as you try to run your executable.
Is this server on an internal network or protected in some other way? (I should hope so!). If so, you might try changing App Pool that the website is running under to an admin account (in IIS, right click the App Pool running the site, select Advanced Settings, and look for the Identity setting). If I'm right, that will allow you to run your executable as an admin too.
Be aware however, that this may increase the security risk of your setup: Allowing your site to run under an admin account means easier access to your entire server if anyone is able to penetrate whatever security measures you have in place. Make sure access to this server is tightly limited, and preferably, that it in turn does not have access to other systems, since that would in turn make them vulnerable by extension.

Run a process/URI from IIS in a desktop session

I have an ASP.NET web application running within IIS. The app pool and the web application are both set to run as a user I created (not NETWORKSERVICE). This user has all the proper permissions (like a pseudo-administrator).
The application calls Process.Start() with a magnet URI. There is an application installed on the webserver which can automatically launch and begin processing the magnet URI. If I enter the magnet URI into the webserver's "Run" box, everything works as expected: the application launches and begins processing the URI in the background. The same happens if I debug the application from within Visual Studio - it works as expected because the IIS Express instance is also running within the same session.
When I invoke the process from my web application when it's in IIS, though, it doesn't throw any exceptions or errors, but it doesn't invoke the application. I'm assuming this is because IIS is executing the application from within a different session that the application lives in, so the application cannot respond to the URI invocation, so the process just quits.
How can I change this line of code to run within the same context as a desktop session so that the application can respond to and process the URI appropriately?
Process.Start("magnet:?xt=urn:btih:0123456789ABCDEF");
If the desktop session does not exist (e.g. that user has not logged into the server), I would expect some sort of catchable exception to be thrown so that a friendly error could be displayed on the website.
ASP.NET Web page and server control code executes in the context of
the ASP.NET worker process on the Web server. If you use the Start
method in an ASP.NET Web page or server control, the new process
executes on the Web server with restricted permissions. The process
does not start in the same context as the client browser, and does not
have access to the user desktop. http://msdn.microsoft.com/de-de/library/e8zac0ca.aspx
When you use Process.Start on IIS 7+, it would start a new process as a service in a 'Session 0' and you can't do anything interactive with that session even you will login with same account on the server. You can however see the process running in the Task Manager (Show processes from all users).
If magnet links are not associated then you can just pass the magnet link as an argument
Process.Start("C:\...\Torrent.exe", "magnet:?...")
If process of the associated exe does not start at all - redirect its output (example) and see what was the problem.
In general, running an external process from web applications is not a good idea and you could consider either a Scheduled Task or Windows Service that polls a common storage repository to see if a batch job should be run and execute your application from there.
Example:
Use aspx to write "magnet:?xt=..." to a text file (c:\magnet.txt)
Create a .bat file with the following content
FOR /F %%x IN (c:\\magnet.txt) DO START %%x
DEL /F c:\magnet.txt
Create a scheduled task that opens the .bat file e.g. every minute
Done!
You can try creating a dedicated regular user account on your server, then use
Process.Start(fileName, userName, password, domain)
to start your process under that user credentials.
Another idea, create a self-hosted WCF service and run it under a logged-in desktop user session. The WCF service would start your "magnet:" app. Call the WCF service from your ASP.NET code (via localhost).
Instead of Process.Start() try using CreateProcessWithLogonW.
Similar question answered in SO: Process.Start() under asp.net?

process start on dll in c# [duplicate]

I have written a Windows service that allows me to remotely run and stop applications. These applications are run using CreateProcess, and this works for me because most of them only perform backend processing. Recently, I need to run applications that present GUI to the current log in user. How do I code in C++ to allow my service to locate the currently active desktop and run the GUI on it?
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
But most importantly, if an application will suddenly appear on a user's desktop, this may very well occur at a bad time (either because the user simply isn't expecting it, or because you're trying to launch the app when the session isn't quite initialized yet, in the process of shutting down, or whatever).
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Also, this shortcut can be moved/disabled by administrators as desired, which will make deployment of your application much easier, since it doesn't deviate from the standards used by other Windows apps...
The short answer is "You don't", as opening a GUI program running under another user context is a security vulnerability commonly known as a Shatter Attack.
Take a look at this MSDN article: Interactive Services. It gives some options for a service to interact with a user.
In short you have these options:
Display a dialog box in the user's session using the WTSSendMessage function.
Create a separate hidden GUI application and use the CreateProcessAsUser function to run the application within the context of the interactive user. Design the GUI application to communicate with the service through some method of interprocess communication (IPC), for example, named pipes. The service communicates with the GUI application to tell it when to display the GUI. The application communicates the results of the user interaction back to the service so that the service can take the appropriate action. Note that IPC can expose your service interfaces over the network unless you use an appropriate access control list (ACL).
If this service runs on a multiuser system, add the application to the following key so that it is run in each session: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the application uses named pipes for IPC, the server can distinguish between multiple user processes by giving each pipe a unique name based on the session ID.
WTSEnumerateSessions and CreateProcessAsUser.
Several people suggested WTSEnumerateSessions and CreateProcessAsUser. I wonder why no one suggested WTSGetActiveConsoleSessionId, since you said you only want to target one logged in user.
Several people sure are right to suggest CreateProcessAsUser though. If you call plain old CreateProcess the way you said, then the application's GUI will run with your service's privileges instead of the user's privileges.
That problems Session 0 , Interactive Services ,
Windows Service Allow Service To Interact With Desktop
on Windows 7 or Windows Vista
You can read this article
http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
I try explained here it's working on Windows 7
On Win2K, XP and Win2K3 the console user is logged on in Session 0, the same session the services live in. If a service is configured as interactive, it'll be able to show the UI on the user's desktop.
However, on Vista, no user can be logged on in Session 0. Showing UI from a service there is a bit trickier. You need to enumerate the active sessions using WTSEnumerateSessions API, find the console session and create the process as that user. Of course, you need also a token or user credentials to be able to do that. You can read more details about this process here.
I think as long as you have only one user logged in, it will automatically display on that user's desktop.
Anyway, be very careful when having a service start an exe.
If the write access to the folder with the exe is not restricted, any user can replace that exe with any other program, which will then be run with sytem rights. Take for example cmd.exe (available on all windows sytems). The next time the service tries to start your exe, you get a command shell with system rights...
If you launch a GUI from your service it will show up on the currently active desktop.
But only if you adjusted the service permissions: You need to allow it to interact with the desktop.
Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.
This is taken from : http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx

Opening a text file on the local system from an asp.net web application

OK to add clarification after the comments posted and the fact I realise my original question was massively confusing. This is what I am trying to achieve....
This will be an web application running on a local intranet and not over the internet. Ultimately I want to be open a network folder location from within the the web application. So for example the web application creates folders on the file server with a set structure i.e:
\server\jobnumber\exhibitreference\image1
\server\jobnumber\exhibitreference\image2
I want the user to be able to navigate to the record and click a link to open it's matching folder location. The users, web server and file server are all on the same domain.
The code below was just used as an example to try and get it working for a file/folder on my local machine before I moved off to trying a remote folder. I appreciate this was confusing.
Original question
I have created .Net/C# web application and I want to open a text file at a specified location. The code below is working fine when run on IIS Express but once published to IIS it does not work.
At present IIS Express and IIS 7 are running on my local machine. The IIS application pool is configured to run under my domain account (had to do this as we have a double hop issue of authentication to SQL server) So far I have the following code:
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.WorkingDirectory = #"C:\Users\pcustance\Desktop\";
processStartInfo.FileName = #"notepad.exe";
processStartInfo.Arguments = "test.txt";
processStartInfo.WindowStyle = ProcessWindowStyle.Maximized;
processStartInfo.CreateNoWindow = true;
Process process = Process.Start(processStartInfo);
Watching the system processes through task manager I can see that the process "notepad.exe" gets created successfully but no window opens. It says the process is running under "pcustance" account but I can only see it when I select "show processes from all users" in task manager.
Is the window not launching because somehow it is being run under the wrong account?
I have also tried:
Process.Start("C:\Users\pcustance\Desktop\test.txt");
As before, this works in IIS Express but not on IIS7.
Any help is greatly appreciated.
Solution
At the moment I have had to resort to using Internet Explorer which supports the use of local links out the box. The browser can be pointed at a network location with the following:
file:///\\server\folder\location
or
file://///server/folder/location
All your code runs within asp.net which is hosted in a server (via IIS).
The code you have written will execute in the context of where your asp.net app is hosted.
While doing web development using visual studio, the "server" and the "client" (i.e. the browser) is usually the same computer. The code executes in the context of a localized development server. Your browser will make requests to "that" server. Therefore the code you wrote is bound to give you the illusion that you've started the process - notepad.exe
The stuff you've actually implemented about doesn't apply for web applications in general. It isn't even feasible. Since the "server" and "client" are two different machines now. The closest you can get into implementing this requirement is serving up the file as response. To the end user, this is equivalent to downloading (in most cases).
Edit:
Your options are serving up the file as-is shown in the code:
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", _
"attachment; filename=""" & filename & """");
This will force user to download the file on the client with a default name as specified by value in filename. Actually you can vary the Content-Disposition part to instruct the browser how to load. However, it depends on the target browser. Here is a small example:
FileStream MyFileStream = new FileStream(#"d:\inetpub\wwwroot\small.txt", FileMode.Open);
long FileSize;
FileSize = MyFileStream.Length;
byte[] Buffer = new byte[(int)FileSize];
MyFileStream.Read(Buffer, 0, (int)MyFileStream.Length);
MyFileStream.Close();
Response.ContentType="text/plain";
Response.AddHeader( "content-disposition","inline; filename=sample.txt");
Response.BinaryWrite(Buffer);
You should research a few articles and experiment. Here are some links to start with:
Content-Disposition:What are the differences between "inline" and "attachment"?
http://www.nullskull.com/articles/20011006.asp
http://www.windowsdevcenter.com/pub/a/dotnet/2002/04/01/asp.html
The intent of your question is still not clear.
Are you...
A. trying to connect to a web application (hosted with IIS) from a client browser and access a file from a network share (relative to the server) for the client to consume?
B. trying to connect to a web application (hosted with IIS) from a client browser and have the application access a file from the network to be used by the server (like a .txt file containing information that the application needs for some processing)?
C. trying to connect to a web application (hosted with IIS) from a client browser and have the hosted application access a file from a network share (relative to the client) for the server to consume?
My assumption is you are attempting (B) and if so, you should use System.IO and access your files programmatically instead of trying to launch a process.
UPDATED BELOW
If you are trying to connect to a web application, and launch a local process (such as notepad.exe) on the client you cannot do so by launching a process. Otherwise MyVirus.com could launch local processes on my machine and that would be a nightmare. The web application is only going to launch processes on the server, never the client.
The best you can do is open the file (from the server) and send a Response back to the client with the contents of the file or send the path and file name to the client and open it via javascript or an HTML5 FileReader.
ADDITIONAL UPDATE
You should be able to open an image (or other content consumable in a browser) from a UNC path as long as you are your Application Pool Identity has permissions and also, are you using impersonation (identity impersonate="true" userName="someaccount" password="somepassword")?
ONE LAST UPDATE
Unfortunately even opening a folder location requires a local process to launch (explorer.exe). That's simply not going to happen with modern browsers for security reasons. You could cook up something wonky like a local windows service on each client machine that checks a database and if it finds x it launches the local explorer.exe to the path stored in the database... but it would have to be checking every second and that sounds like a really bad idea.
Other than that maybe something like this File Explorer Control from Telerik or this File View Control would serve your purposes. (Disclaimer, I don't know anything about either of these controls just thought they might help).
please see this page
http://msdn.microsoft.com/en-us/library/58wxa9w5(v=vs.100).aspx
Most importantly this line
Use when you are working with an existing project or your site targets an older version of IIS, such as IIS 6, and it is not very important that your testing environment match the production environment closely. This server option is the default in Visual Studio. However, the Visual Studio Development Server runs in a different security context than full IIS, and may fail to reveal errors that can occur when you deploy to a production version of IIS.
The issue is that IISExpress and the local dev server run under your security context. This allows them much more freedom to start processes and have access to files on the local system.
IIS however runs in a much stricter security context and has a limited access to the machine at hand. Imagine if IIS could do what you are proposing above. you could basically run any arbitrary code on the webserver.

File System watcher in Windows Service or Console Application?

I am implementing a file system watcher, my requirement is to watch for a given local folder on a machine and then do a small task (for example open a certain page in web browser). The file(s) in the given directory would be generated randomly sometimes every two hours or four etc. This tool should be automated in the sense that a user does not have to start it. So my question is, Should I implement this in a windows service which always will be running or in a console application.Preference is to do it in a console application but then it would need to started by a user right? Please advice
You can automatically call any type of application (Console, Windows, etc.). What it gets down to with a Windows Service is whether you want it to be running before anyone logs in.
Only a Windows service runs while no one is logged in. A console application (while it can be set to run on login) must have someone log in in order to run.

Categories

Resources