8

Is it possible for a C# Windows service running as Local System or Local Service to impersonate another user without needing a password for that user?

How would this be done?

Note: My motivation for this is to be able to run user specific WMI queries in a service. The WMI calls I'm making (to the OfflineFiles WMI API) are user sensitive, and they only work when I run my service as the user whose data I want to query. I don't want users to have to enter their usernames and passwords when installing the service, so I'd like to just run the service as Local System or something, and impersonate the user I care about.

Eric
  • 5,842
  • 7
  • 42
  • 71
  • I suspect you will have better luck if you explain what you want the service to do once it has impersonated a user. AFAIK, what you are asking for is not possible without stashing credentials (which means the user entering a password at some point) – Chris Shain Nov 29 '11 at 00:59
  • @ChrisShain, I have updated the question as you suggested. – Eric Nov 29 '11 at 01:07
  • Check out the answers to this question: http://stackoverflow.com/questions/559719/windows-impersonation-from-c-sharp – Chris Shain Nov 29 '11 at 01:16

2 Answers2

11

Assuming you only need start impersonation whilst the relevant user is logged on, you could:

  1. Locate relevant user session using EnumProcesses (eg http://msdn.microsoft.com/en-us/library/windows/desktop/ms682623(v=vs.85).aspx) [winapi]
  2. OpenProcessToken() on relevant user process [winapi]
  3. DuplicateToken() with impersonation privileges [winapi]
  4. Create a new WindowsIdentity() using the result of DuplicateToken
  5. Call .Impersonate on your new identity from step 4

Once the token has been duplicated, it doesn't matter if the user logs of - the impersonation in your service remains.

Apparently the API the undocumented ZwCreateToken winapi function can achieve this although also, but I have never used it and may break at anytime in future.

geoffreys
  • 1,107
  • 7
  • 24
  • 1
    for #1, can also use `Process.GetProcesses()` – Dave Thieben Aug 01 '16 at 14:23
  • Indeed there is a kind of technique using S4U (service for user): https://blogs.msdn.microsoft.com/winsdk/2015/08/28/logon-as-a-user-without-a-password/ https://msdn.microsoft.com/en-us/library/windows/desktop/aa378128(v=vs.85).aspx – Michael Flyger Oct 06 '16 at 05:34
1

To the best of my knowledge, it can't be done for obvious security reasons. You have to have the password in order to call LogonUser, then WindowsIdentity.Impersonate.

The one exception: if you had an existing WindowsIdentity passed to the service through a remoting call, then you can impersonate that WindowsIdentity in the service, but not too apps operate this way.

competent_tech
  • 44,465
  • 11
  • 90
  • 113
  • 4
    The security reasons are not obvious - if you are a service running with on a Local System account there is really nothing you can't do. – EFraim May 18 '16 at 08:50