2

I've written some sample code which when I call from the windows command prompt under the context of a normal user account, dump's all the user's saved credentials using CredEnumerate(). However, I really want to be able to do this from SYSTEM user context so I've tested my program from a SYSTEM cmd prompt.

When I running my program as SYSTEM, I run LogonUser like so:

bLoggedOn = LogonUser(userName.c_str(), domain.c_str(), password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &userToken_);

Then I run ImpersonateLoggedOnUser() on the token to give me the security context of the local user. After this I do:

bOk = CredEnumerate(NULL, 0, &count, &pCredentials);

And I'd expect this to return the credentials in the same way as if I'd not gone in from system and impersonated. Can anyone spot anything that I've missed to truly put myself in the user's context?

Benj
  • 31,668
  • 17
  • 78
  • 127
  • 1
    Are these credentials stored in the registry? Maybe you need to load the user's registry hive before calling CredEnumerate. You could use Process Monitor to see if that's what's happening. – Luke Sep 09 '10 at 21:24
  • Hmm, it's a good thought and I hadn't considered it. But I actually have the same problem even if I kick of a system propt using psexec while the user I'm impersonating is actually logged on. Presumably in that instance the user's registry hive would be loaded already. – Benj Sep 10 '10 at 09:06
  • 1
    The documents for the credential management APIs seem to indicate that these credentials are associated with a logon session. Perhaps LogonUser results in a new logon session, so the credentials don't exist there. You could test this by calling ImpersonateLoggedOnUser() with an existing token instead of obtaining one through LogonUser(). – Luke Sep 10 '10 at 11:37

1 Answers1

3

I guess I aught to answer this question myself since I've now spent ages working out how to do this and I'm not sure it's widely known. CredEnumerate/CredRead will never provide password information for domain passwords no matter what process context you're in or what token you have despite what it seems to hint at on MSDN. The only way to get access to the saved credential information is to do so using the undocumented function LSAICryptUnprotectData() which is in lsasrv.dll. This can decrypt the files you find in %APPDATA%\Microsoft\Credentials and can provide an identical data structure to CredEnumerate except with the password filled in. The only catch is that this must be done in the process context of lsass.exe (The windows security subsystem), no setting of privilledges etc is enough to give a normal process the rights to do this. If you're a hacker you can do this by performing a CreateRemoteThread() to inject a thread into lsass.exe or if you're trying to do this in a legitimate way, i.e you're extending the Windows operating system in some way for a third party application, like I was, you can do this by creating a Windows authentication package which lsass will load. This AP can then use a named pipe or some such method to allow interaction with the rest of your code.

Benj
  • 31,668
  • 17
  • 78
  • 127