![]() |
Show Changes |
![]() |
Edit |
![]() |
|
![]() |
Recent Changes |
![]() |
Subscriptions |
![]() |
Lost and Found |
![]() |
Find References |
![]() |
Rename |
| Search |
History
| 11/21/2004 4:17:34 PM |
![]() |
List all versions |
Daemons (WhatIsADaemon) normally run in noninteractive window stations (WhatIsAWindowStation). So, if you want to display a user interface from daemon code, you've got a couple of options. Option one is to get yourself into the interactive window station, and option two is to have a process already in the interactive window station display a UI for you.
Let me describe a couple of ways to achieve the first option. An easy way to put a daemon in the interactive window station (WinSta0) so it can have its own user interface is to package it as a service that runs as SYSTEM and check the box that says, "Allow service to interact with the desktop." This tells the SCM to launch your service process in the SYSTEM logon session (WhatIsALogonSession) and to attach your process to WinSta0 instead of the noninteractive window station in which the SYSTEM daemons normally run, Service-0x0-0x3e7$. Another way is to dynamically migrate your process from a noninteractive window station into WinSta0 by calling SetProcessWindowStation, but ACLs (WhatIsAnAccessControlList) on WinSta0 allow only processes running as SYSTEM to do this sort of thing.
I'm not going to go into great detail on how to accomplish option one; instead, I will implore you to avoid it. Avoid putting daemons in WinSta0, especially if they run as SYSTEM. There's an inherent vulnerability to which you expose yourself by putting daemon processes in the same windowing environment as the interactive user: the threat of window message attacks that are even nastier than the luring attack I described in WhatIsALuringAttack. In the past there were successful attacks against interactive services, attacks that allowed the interactive user to inject and run arbitrary code in an interactive service’s process. The most popular attack was named "shatter"1 and basically involved sending a WM_COPYDATA message, copying exploit code into the address space of a highly privileged interactive service process followed by a WM_TIMER message, causing the service process to execute the exploit code. This elevation-of-privilege attack could have been carried out either by a user who had physical access to the machine or by a remote user logged in via Terminal Services. Microsoft issued a patch to change the way WM_TIMER worked to inhibit this particular flavor of attack, but that doesn't mean another avenue won't be found. Avoid doing this. Don't build interactive services. Having highly privileged code in the same sandbox as a restricted interactive user is just plain silly.2
What you should consider instead is option two: Use two processes instead of just one. One process must be launched in the interactive user's logon session and WinSta0. It should contain all the user interface elements you need, and it can connect to your daemon process using any secure form of interprocess communication you're comfortable with, such as "COM"3. Just don't try to use window messages to communicate; it won't work, as you'll see shortly. You should realize that, unless your daemon is running as SYSTEM, it's not likely to have enough privilege to start the GUI program directly. If you use COM, you can configure the GUI program to run as Interactive User (HowToConfigureProcessIdentityForACOMServerApp), and the COM SCM does this tricky work for you. (The SCM runs as SYSTEM and therefore is allowed to do sensitive things like injecting code into someone else's logon session.) The best choice is to simply have the user start the GUI program manually whenever it's needed or, if it's always to be running, have it auto-start when the user logs on. This can be as simple as dropping a shortcut to the program in the user's Startup folder the first time the user launches your program.
If your GUI simply consists of a message you need to send to the interactive user, you don't even need to write a second program. There's already infrastructure in Windows that pops up a message box on behalf of a daemon; it’s built in to the client-server subsystem csrss.exe (which runs in WinSta0) and is exposed via MessageBox in the .NET Framework. Here's an example of some C# code from a daemon that asks csrss.exe to show a message box.
DialogResult AskQuestionFromDaemon(string text) {
return MessageBox.Show(text, "Keith's Daemon",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2,
MessageBoxOptions.ServiceNotification);
}
Note the use of MessageBoxOptions.ServiceNotification. This tells user32.dll not to display the dialog box directly but have csrss.exe display it instead. And you don't need any special privileges to do this. There are two things to note about this technique. First, the dialog will be displayed even if no user is logged in at the console. This means that your dialog might show up on top of the logon prompt! If you don't want this to happen, use the MessageBoxOptions.DefaultDesktopOnly option instead. Second, you should know that csrss.exe queues up requests like these and executes them one at a time. So, if two threads (possibly from two different processes) make this call at the same time, only one message box shows up. The second message appears immediately after the user dismisses the first message. Also note that MessageBox.Show won’t return until your message box has been dismissed by the user. Don't be surprised by this.
You might wonder why you can't inject an arbitrary dialog into the interactive user's window station using a similar technique. Apparently Microsoft considered a simple message box to be a fairly benign beast. A daemon can't use it to ask the user for information (the classic attack here is to ask the user for his password — users fall for this one so easily). Remember, the idea behind window stations is to have a clean separation between daemons and interactive users. We want to prevent both daemons and the interactive user from elevating privileges by leaching off one other, especially highly privileged daemons or interactive users. Allowing even a message box blurs this boundary — I can imagine a daemon using a simple message to lure the user into taking an action that the daemon isn't authorized to perform. Remember that the weakest link in a secure system is usually that warm body sitting behind the console, the “wetware”.
1 Google for "shatter attack windows security" for more details.
2 I've heard rumors that Microsoft may eventually stop supporting interactive services entirely as a feature. This would be a good move, in my opinion.
3 You could also use .NET Remoting if you can secure it (HowToAddCIAToDotNETRemoting). What you need is authentication support so you can limit who can use your interface.
Keith's first book-in-a-wiki. If you would like to read the book online or order a physical copy to throw at annoying coworkers, surf to the HomePage. Please note that due to overwhelming wikispam, this particular wiki is no longer editable.
About FlexWiki.
Recent Topics