如果我被模拟,为什么 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND? [英] Why does Win32 API function CredEnumerate() return ERROR_NOT_FOUND if I'm impersonated?

查看:38
本文介绍了如果我被模拟,为什么 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一些示例代码,当我在普通用户帐户的上下文中从 Windows 命令提示符调用时,使用 CredEnumerate() 转储所有用户保存的凭据.但是,我真的希望能够从 SYSTEM 用户上下文执行此操作,因此我已从 SYSTEM cmd 提示符下测试了我的程序.

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.

当我以 SYSTEM 身份运行我的程序时,我像这样运行 LogonUser:

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

然后我在令牌上运行 ImpersonateLoggedOnUser() 来为我提供本地用户的安全上下文.在此之后,我会这样做:

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?

推荐答案

我想我应该自己回答这个问题,因为我已经花了很长时间研究如何做到这一点,但我不确定它是否广为人知.CredEnumerate/CredRead 永远不会提供域密码的密码信息,无论您处于什么进程上下文或您拥有什么令牌,尽管它似乎在 MSDN 上暗示了什么.访问保存的凭据信息的唯一方法是使用 lsasrv.dll 中未记录的函数 LSAICryptUnprotectData().这可以解密您在 %APPDATA%\Microsoft\Credentials 中找到的文件,并且可以提供与 CredEnumerate 相同的数据结构,除了填写密码.唯一的问题是这必须在 lsass.exe 的进程上下文中完成(windows 安全子系统),没有设置特权等就足以赋予正常进程执行此操作的权限.如果您是黑客,您可以通过执行 CreateRemoteThread() 将线程注入 lsass.exe 来实现此目的,或者如果您尝试以合法方式执行此操作,即您正在以某种方式扩展 Windows 操作系统对于像我这样的第三方应用程序,您可以通过创建 lsass 将加载的 Windows 身份验证包来完成此操作.然后,该 AP 可以使用命名管道或某种此类方法来允许与您的其余代码进行交互.

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.

这篇关于如果我被模拟,为什么 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆