Impersonate SYSTEM (or equivalent) from Administrator Account - c++

This question is a follow up and continuation of this question about a Privilege problem I'm dealing with currently.
Problem Summary:
I'm running a program under a Domain Administrator account that does not have Debug programs (SeDebugPrivilege) privilege, but I need it on the local machine.
Klugey Solution:
The program can install itself as a service on the local machine, and start the service. Said service now runs under the SYSTEM account, which enables us to use our SeTCBPrivilege privilege to create a new access token which does have SeDebugPrivilege. We can then use the newly created token to re-launch the initial program with the elevated rights.
I personally do not like this solution. I feel it should be possible to acquire the necessary privileges as an Administrator without having to make system modifications such as installing a service (even if it is only temporary).
I am hoping that there is a solution that minimizes system modifications and can preferably be done on the fly (ie: Not require restarting itself). I have unsuccessfully tried to LogonUser as SYSTEM and tried to OpenProcessToken on a known SYSTEM process (such as csrss.exe) (which fails, because you cannot OpenProcess with PROCESS_QUERY_INFORMATION to get a handle to the process without the privileges I'm trying to acquire).
I'm just at my wit's end trying to come up with an alternative solution to this problem. I was hoping there was an easy way to grab a privileged token on the host machine and impersonate it for this program, but I haven't found a way.
If anyone knows of a way around this, or even has suggestions on things that might work, please let me know. I really appreciate the help, thanks!

By design, no process is allowed to achieve NT AUTHORITY\SYSTEM rights, unless it is started by another process with NT AUTHORITY\SYSTEM rights. The service is a workaround because the Service Control Manager itself is started by the Kernel at system start.
Unfortunately, the operating system is designed to prevent exactly what you're trying to do. If you want to be able to remove your service afterwards, simply grant the user in question SeDebugPrivilege for the local machine and then have the service uninstall itself.
Better yet, have the program whose memory is to be modified change DACLs to allow your administrator access to it's memory without SeDebugPrivilege. Then you don't need to take privilege at all.
EDIT2: And even better yet, just use shared memory in the first place. That's what it's for.

Related

Debugging Windows service failure before main() (error 1053 when run by LocalSystem user)

I have a Windows service that works perfectly when run via a user account, but fails with error 1053 when run by the Local System account. Unfortunately, whatever is going wrong happens before my main() function is called, which means I can't even insert logging calls to track down where things go wrong.
How can I debug Windows service startup failures when it's happening in pre-main() code?
Any ideas why it might fail specifically when it's run by the Local System user?
NOTE: Not sure if it's relevant, but I'm compiling with GCC, and the code depends on Cygwin.
This won't be complete answer because without actually having event log it would not be possible.
Since this happens pre-main this would be related to what your user account can do and what local system cannot.
In service property panel, for Local System account you have "Allow Service To interact with desktop". Many times this can be the reason.
The other of course is, your service is loading some libraries which are off limits to it - because of network\group security (local system cannot access network so far as I know).
You will need to eliminate one piece at time to see what happens. Or other way round - make service empty remove all dependencies and play 20 questions.

access mapped network drive through impersonation

Is it impossible to access the mapped network drive( mapped in user session) from service after impersonating the current user by using ImpersonateLoggedOnUser Windows API?
Yes, this is impossible. Drive mappings are only established during an interactive logon. The ImpersonateLoggedOnUser function does not impersonate the user's entire logon session, just their security context. This is only one of the many things that cannot be done using impersonation.
I suppose you might be able to do this by duplicating the user's login token (obtained from one of their interactive processes), and then using that to call the CreateProcessAsUser function. You would then launch a process that would work with the mapped network drive(s). I'm not absolutely certain that this will work, as I've never done it, but it seems theoretically possible.
Of course, it begs the question of why you need to follow such a circuitous route. It would be eminently more sensible to just run your code in the user's interactive process to begin with, as a standard Windows application.
This is not something that a service is designed to do. Services do not support mapped network drives. If you want to access a network resource from within a service, you should just use the UNC path.

Alternative to disabling UAC

I am looking for a method to use as an alternative to disabling UAC to keep application persistence throughout the lifetime of the system.
My application runs every time the system starts up, and it requires elevated privileges, so when UAC is enabled it asks the user whether or not to run my application, every time the system is rebooted. This is very tedious and can become annoying if it happens every time. If UAC is disabled this warning no longer appears but of course that is very harmful to the user as it could lead to threats on their computer.
My question is; In C++ how can I programmatically allow file/application persistence throughout any event on the users' PC just for my application without getting the UAC warnings each time!
I am looking for ANY possible method, an exploit, a bypass method, anything, I'm really desperate at the moment as I've been stuck with this program for several days now and I'm just 99.9% done my project. I really need to get this through. THANK YOU SO MUCH FOR ANY ADVICE you may offer me!
The first step is to determine whether your program really needs admin privilege at all. Sometimes a program only runs with admin privilege, but for trivial reasons: a log file is being generated in the wrong place, for example, or a file that should be being opened for read-only access is being opened for full access. If that's the case you can fix the problem and avoid any further structural changes.
Secondly, ask whether your program needs admin privilege all the time, or only when the user performs certain actions. In the latter case, you should probably only elevate when it becomes necessary to do so; as well as meaning that the user does not need to approve the program launch on every reboot, it also helps protect the user from making an administrative change without intending to. This is particularly relevant if UAC is configured to require a password each time.
Thirdly, ask whether your program really needs a user interface. If not, then it should be a system service.
If your program really does need admin privilege all the time, and really does need a user interface, then you need to separate it into two parts, one containing the user interface and one containing the functionality that requires elevated privilege.
The user interface part should be a program that runs whenever a user logs in, just as your program does now. The elevated privilege part should be a system service.
The primary logic might belong in either part, or might also need to be split into two; it depends entirely on the context. (The system service does need to contain enough logic to ensure that the the privileged operations it is performing are safe and appropriate. It can't simply do anything the user interface part tells it to.)
These two parts can interact using whatever form of inter-process communication and/or synchronization is most convenient. You do need to be aware that they will be in different Remote Desktop sessions; for example, if you create an event object for synchronization the name must start with the Global\ prefix.
You will need to consider that more than one user may be logged in at the same time, either via Switch User or because the machine is a Remote Desktop server. This may mean that the service component needs to support multiple simultaneous clients, which affects your choice and implementation of IPC. Alternatively, the user interface component needs to detect that another instance is already running, and wait until that instance goes away before attempting to connect.
You will also need to consider how the program should react when the logged-in user does not have administrative privilege. At the moment such a user can't run your program at all, probably making the prompts even more annoying than they are to an admin user! If it is OK for the program to work as normal for a non-admin user then you don't need to do anything special. If the program should not work for a non-admin user, or if some of the functionality should be restricted, then (a) the GUI component needs to behave accordingly, by, e.g., exiting silently; and (b) the service component needs to check the context in which the GUI component is running. It is not enough for the GUI component to do the check, because the user can trick it if he or she wishes to; the service component must check too.
The easiest way to do that is probably to use GetTokenInformation with the TokenElevationType option; if the token type is TokenElevationTypeLimited or TokenElevationTypeFull, the user has administrator privilege. If the token type is TokenElevationTypeDefault, there is no split token; either the user is not an administrator, is the local Administrator account, or UAC is turned off; in this case, use CheckTokenMembership to check whether the user is in the Administrators group or not.
In some cases, it might also be sensible for certain tasks to require UAC approval, even if other tasks do not. Such tasks need not involve the service component; the GUI component can elevate itself, with the user's consent, to perform them.

Making an app/service such that trying to end/kill its process in Task Manager would result in "Unable to Terminate Process"

I have an Avast antivirus and it has a process "AvastSvc.exe". If I try to end/kill that process in Windows Task Manager, then a windows with the following messages appears: "Unable to Terminate Process", "The operation could not be completed.", "Access is denied". Trying to end some system Windows processes (like winlogon.exe) may feature the same behaviour (although once I managed to kill winlogon.exe and got my machine hanged!).
I want my application (possibly, converted to a service) behave in the same way. How can I do this?
Disable Windows Task Manager so he cant kill my process is a similar question which has many interesting answers, but they don't seem to feature the technique which is used by the above antivirus and results in "Unable to Terminate Process" message.
http://forums.codeguru.com/showthread.php?t=503337 has a solution on how to prevent stopping a service (eg, via services.msc console), but I need preventing ending/killing its process in Task Manager.
I am writing the app in C++/winapi, no CLR/.Net, under Windows 7.
UPDATE on permissions:
Antivirus process AvastSvc.exe is owned by "system" account. However, I have other processes owned by "system" account, and they are killable and antivirus is not. Also, I compared executable permissions and owners of antivirus process and ones of killable processes, and I don't see any difference.
UPDATE on user control and purpose of the software:
The software functionality is somewhere between that of system and business software. The nature of the software requires it to run on a permanent basis. The application itself will have a "turn off" action, and we want to encourage users to use it and discourage them from killing the process (it's similar to what antiviruses do). I understand that it's not possible to completely prevent users from killing it, but I want to make it harder. This question is specifically about the way described above ("Unable to Terminate Process") which some services (like Avast) use to prevent killing their processes. It is sufficient for me to achieve just the same behavior. Also, users will be able to just uninstall the software if they don't like it/don't need it anymore.
This is not achieved through code (well, it might be for critical Windows system processes, but you are [probably] not writing components of the operating system), but rather through access permissions.
You can demonstrate this by elevating to Administrator and then attempting to kill Avast's process. It should succeed this time. Alternatively, you can take ownership of the executable (and possibly the folder in which it resides), then try to kill the process. Again, it should be successful.
Windows does not allow applications to exert more power over the computer than the user. If you own the machine and have the appropriate permissions, you can do anything you want, including terminating a running process. Thankfully, there is no way for you, as a developer, to block this.
The user is always in ultimate control. Attempting to create an alternative situation is a battle that virus and other malware developers fight—and lose—regularly. Since I'm not interested in helping anyone write malware, that's all I'm going to say about that.
And other than writing malware, I can't imagine what the motivation for this "feature" in an application would be in the first place. If you're simply trying to prevent regular users from killing a process that is critical to a business system, then you should just demote the privileges of the standard user accounts so that they will not be able to tamper with such things. As such, this is probably a job for Group Policy, rather than code.
I found that the function ProtectProcess() supplied in Prevent user process from being killed with "End Process" from Process Explorer results exactly in the effect I was looking for.
Hide your process by removing it from the eprocess structure
Issue persistent I/O requests that cannot be cancelled or completed by other processes
Create threads to debug your own process
Create separate process/es from memory that monitors the main process and re-starts it from memory once terminated by another process

Alternatives to LogonUser for network impersonation (C++)

Are there any alternatives to LogonUser and for impersonating given account in order to access network resources? I'm looking for the method of impersonation which would let me connect to machine in foreign domains (or, workgroup machines for the same matter).
For initial data I have: machine name, username (or domain\username), cleartext password.
I know there's a way to establish connection using WNetAddConnection to a \\machinename\ipc$, then most network functions will run in a context of that account, however win2008 added another twist and some functions still use the account, that thread is running under.
I'm also aware, that there's some way to get an impersonation token using SSPI. Have anyone experimented with those tokens, are they good for accessing shares, SCM, remote registry and stuff? Is is what WNetAddConnection is using?
EDIT: To clarify, the reason I cannot use LogonUser is because I need to impersonate user in a non-trusted domain or workgroup
EDIT2: Another clarification: the item I'm trying to implement is similar to psexec, e.g.:
program should not modify host or active directory configuration (e.g.: create temporary local users, etc). Moreover assumption cannot be made that it is running on DC or not
there can be no assumptions made about which software is pre-installed on the remote host, only condition given is that windows file sharing is enabled on target
Account/password is known to be working on target, but target machine may be in local domain, foreign domain, not in domain at all.
EDIT3: I would really love to hear more about SSPI InitializeSecurityContext / AcquireCredentialsHandle option. Is there anybody who has been working with this API extensively? Is it possible to use the tokens returned with impersonation, so that a thread can access network shares and copy files, etc? Can someone post a working code snippet?
EDIT4: Thanks to Marsh Ray, problem got resolved. If anyone is looking to see the proof-of-concept code, it is here
If you're wanting to "access network resources" outside of your forest, do that with WNetAddConnection2/3 as you mentioned, or use the standard RPC APIs with RPC_ C__ AUTHN__ GSS__ NEGOTIATE and and explicit credentials structure.
Normally, "impersonation" is something that happens on the server side. The server side will be able to impersonate the connection as the account you're connecting as.
But the key is this: impersonation only makes sense for impersonating an account the server can access in his local SAM/domain/forest directory. If the client and server are in different forests, they clearly can't agree on the SID of an account for an impersonation token (except for the case of well-known SIDs like Administrator which serve mainly to confuse this kind of thing), and that seems necessary to check against DACLs etc.
Perhaps what you want is to call LogonUserEx with the LOGON32__ LOGON__ NEW__ CREDENTIALS flag. This should succeed (even in a different forest - it doesn't actually authenticate the credentials you give it) giving you a token with the username/password you specified. You may have to use DuplicateToken to turn this into an impersonation token. Then you can use SetThreadToken to replace the token on your thread.
IMHO this isn't really "impersonation", you're just using the credentials outright, but it allows you to access network resources transparently as the arbitrary username/password you supply.
Edit: Oh yeah, be aware that there is no protection against man-in-the-middle on this type of connection. The client especially cannot strongly authenticate the server (short of heroics like IPSEC), so in theory you can't trust anything the server tells you.
The theory goes that you pass the credentials as a SEC_WINNT_AUTH_IDENTITY structure to the AcquireCredentialsHandle function that creates the handle used in InitializeSecurityContext. I never tried this on foreign domains though and I don't know if it works.
Doing this directly and reliably via the Windows API seems next to impossible, plus Windows does so much work behind the scenes to make network access "just work". Plus the impersonation side of things only works for the single thread that called the APIs.
But... you can run a whole program under a different user... such as when you run a service.
So you could edit the registry in your main program to run various services under different security tokens and use IPC/Sockets to communicate with those processes from your main application. ie. a whole bunch (or restarting and reconfiguring the same process) of helper processes running under the different user(s) which your main app abuses.
I realize this is a hack but it seems viable ;)
You could open a command line, map the drive using the plaintext username and password. Then disconnect the drive:
net use m: \\machinename\share password /user:username
... do stuff ...
net use m: /delete
http://technet.microsoft.com/en-us/library/cc756153(WS.10).aspx