views:

1445

answers:

5

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

+3  A: 

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.

Remus Rusanu
A: 

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 ;)

Rudi Bierach
nope. not viable. need to be able to obtain impersonation tokens for machines in un-trusted forest. You cannot run a program as a user from untrusted forest
galets
You can create the user locally since you have the cleartext password and delete the user when you are done.Another option is talking DCERPC/MSRPC (http://en.wikipedia.org/wiki/MSRPC) directly but then you are effectively going down a similar track to samba, but at least you could use Wireshark to compare your implementation against what happens via the normal Window APIs.Can you install helper programs on the remote machine and impersonate on that end (and use whatever protocol you like to connect to the remote helper program?)?
Rudi Bierach
I guess I haven't carefully read your comment about service. My post has been specifically instigated by the fact that when I try to install service to remote Windows 2008 box, and I already have a share mapped, remote SCM will still not use the account used to map a share
galets
Newer versions of Windows stop allowing services from using mapped drives, which leaves only UNC paths to access remote drives. It makes sense since mapped drives are more tied to the desktop than anything else.
Rudi Bierach
Correct. I should have used wording carefully. By "mapping a drive" I meant "establishing WMNet connection". What I found, however, is that even though I established connection and can copy files, under windows 2008 attempts to open SCM will still be using currently logged in account, not the one I used to establish connection and copy files. This is the reason I'm looking what alternatives are
galets
A: 

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

Robert
I mentioned this solution does not work: "I know there's a way to establish connection using WNetAddConnection to a \\machinename\ipc$, ..." - you essentially suggesting the same thing
galets
Sorry, I thought WNetAddConnection was something different.
Robert
+4  A: 

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.

Marsh Ray
wow, sounds like a great approach! I never thought of using this. Let me give it a quick test to see if it works
galets
dude, that did it! Thank you so very much, this was exactly what I've been looking for
galets
great! glad to hear it!
Marsh Ray
Don't forget to restore your thread's old token and clean up all the new ones. You don't want to leak tokens, I suspect they consume a scarce resource in the kernel and/or lsass.exe.
Marsh Ray
Out of curiosity, did you end up needing to call DuplicateToken?
Marsh Ray
nope. All works without a glitch, no DuplicateToken needed. Here's the code: http://docs.google.com/View?id=djcgsjz_1gvhc7wfg
galets
Cool. This is a case where C++ destructors are great at cleaning up objects like tokens and calling RevertToSelf().
Marsh Ray
A: 

Marsh, THANK YOU!!!!!!!

After a week of no sleep and enough Capt. Morgan to want to demote him to private, you put me on the right track. You stated that "Normally, "impersonation" is something that happens on the server side." That made it all clear. I was stuck on thinking the client had to be able to authenticate the credentials in order to get a token.

My problem was that NTLM authentication against an SQL server with the MS ODBC drivers authenticated in the context of the logged on user. This requires matching credentials on both the client and server. Not acceptable. Our service has hundreds of threads running at any given time requiring impersonation for WNet???() calls against several targets concurrently with the account we logged into at service start up. Works fine.

I implemented your solution in our SQL threads and it works!

I'm still confused about the scope of calling LogonUser() within a thread though. Can a process have multiple logon sessions and will calls to ImpersonateLoggedonUser() with different tokens only be applicable to the thread that makes the call? Should SetThreadToken() be used instead? Is a call to RevertToSelf() act in the context of the thread or the process?

Again, thanks for your explaination!!

Craig Armstrong