fru*_*ela 5 c# winapi credentials
我正在尝试请求用户在安全桌面上输入凭据,但我找不到解密生成的身份验证缓冲区的方法:
凭证通过以下方式获得:
CREDUI_INFO cui = new CREDUI_INFO()
{
cbSize = (uint)Marshal.SizeOf(typeof(CREDUI_INFO)),
pszMessageText = "MyMessage",
pszCaptionText = "MyCaption",
};
bool save = false;
uint authPackage = 0U;
IntPtr authBuffer;
uint authBufferSize;
uint error = CredUIPromptForWindowsCredentials(
ref cui,
0U,
ref authPackage,
IntPtr.Zero,
0U,
out authBuffer,
out authBufferSize,
ref save,
CREDUIWIN_SECURE_PROMPT);
Run Code Online (Sandbox Code Playgroud)
凭据解压缩:
uint userBufferSize = CREDUI_MAX_USERNAME_LENGTH;
uint domainBufferSize = CRED_MAX_STRING_LENGTH;
uint passwordBufferSize = CREDUI_MAX_PASSWORD_LENGTH;
StringBuilder userBuffer = new StringBuilder((int)userBufferSize);
StringBuilder domainBuffer = new String((int)domainBufferSize);
IntPtr passwordBuffer = Marshal.AllocCoTaskMem((int)passwordBufferSize);
bool success = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS,
authBuffer, authBufferSize
userBuffer, ref userBufferSize,
domainBuffer, ref domainBufferSize,
passwordBuffer, ref passwordBufferSize);
Run Code Online (Sandbox Code Playgroud)
如果我CREDUIWIN_SECURE_PROMPT在CredUIPromptForWindowsCredentials上面的例子中指定in ,则CredUnPackAuthenticationBuffer失败ERROR_NOT_CAPABLE.如果我使用CREDUIWIN_GENERIC而不是安全桌面,它会成功.
如何从安全桌面获取此类加密凭据的名称,域和密码? 或者如果那是不可能的话我怎么能一般使用它们呢?
凭证提供者使用CredProtectW或CredProtectEx用于加密密码。withCredUnPackAuthenticationBufferW尝试使用或CRED_PACK_PROTECTED_CREDENTIALS解密身份验证缓冲区中的凭据(密码)。错误 - ERROR_NOT_CAPABLE由 准确返回。CredUnprotectWCredUnprotectExCredUnprotectW
用于加密凭证的安全上下文与用于解密凭证的安全上下文不同。
这是因为,当CREDUIWIN_SECURE_PROMPT用于收集用户凭据时,系统会在上下文中作为系统进程运行LogonUI.exe 。密码在此过程中加密。当您在另一个安全上下文 - 用户进程中运行时。
如果您没有在令牌中启用任何管理员组,则您无法对此执行任何操作 - 您可以将此凭据传递给系统,例如通过LsaLogonUser,但您无法解密密码。如果您有“admin”,您可以模拟系统令牌,然后CredUnPackAuthenticationBuffer(CRED_PACK_PROTECTED_CREDENTIALS,..)在您的线程模拟时调用。
或者您可以CredUnPackAuthenticationBuffer(0,..) 不 进行调用,然后通过在模拟系统令牌时CRED_PACK_PROTECTED_CREDENTIALS调用来分离不受保护的密码。CredUnprotectW或者,如果您无法模拟系统令牌,那么您至少可以获得用户名。但无法访问密码。如果您调用CredIsProtectedW返回的密码,您将得到CredTrustedProtection。
模拟系统token的代码:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
NTSTATUS ImpersonateSystemToken(PSYSTEM_PROCESS_INFORMATION pspi)
{
NTSTATUS status;
ULONG NextEntryOffset = 0;
do
{
(ULONG_PTR&)pspi += NextEntryOffset;
HANDLE hProcess, hToken;
CLIENT_ID ClientId = { pspi->UniqueProcessId };
if (ClientId.UniqueProcess)
{
const SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof (sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};
const OBJECT_ATTRIBUTES oa_sqos = { sizeof(oa_sqos), 0, 0, 0, 0, const_cast<SECURITY_QUALITY_OF_SERVICE*>(&sqos) };
if (0 <= NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), &ClientId))
{
status = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE|TOKEN_QUERY, &hToken);
NtClose(hProcess);
if (0 <= status)
{
TOKEN_STATISTICS ts;
if (0 <= (status = NtQueryInformationToken(hToken, TokenStatistics, &ts, sizeof(ts), &ts.DynamicCharged)))
{
status = STATUS_NOT_FOUND;
static const LUID SystemLuid = SYSTEM_LUID;
if (ts.AuthenticationId.LowPart == SystemLuid.LowPart &&
ts.AuthenticationId.HighPart == SystemLuid.HighPart)
{
status = NtDuplicateToken(hToken, TOKEN_IMPERSONATE|TOKEN_ADJUST_PRIVILEGES,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), FALSE, TokenImpersonation, &hProcess);
}
}
NtClose(hToken);
if (0 <= status)
{
const TOKEN_PRIVILEGES tp_TCB = { 1, { { { SE_TCB_PRIVILEGE }, SE_PRIVILEGE_ENABLED } } };
if (STATUS_SUCCESS == NtAdjustPrivilegesToken(hProcess, FALSE,
const_cast<TOKEN_PRIVILEGES*>(&tp_TCB), sizeof(tp_TCB), 0, 0))
{
status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hProcess, sizeof(hProcess));
}
else
{
status = -1;
}
NtClose(hProcess);
if (-1 != status)
{
return status;
}
}
}
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS ImpersonateSystemToken()
{
BOOLEAN WasEnabled;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &WasEnabled);
NTSTATUS status;
ULONG cb = 0x40000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb += 0x1000])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
status = ImpersonateSystemToken((PSYSTEM_PROCESS_INFORMATION)buf);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
status = STATUS_UNSUCCESSFUL;
}
}
delete [] buf;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
Run Code Online (Sandbox Code Playgroud)
您可以将其用作:
if (0 <= ImpersonateSystemToken())
{
if (CredUnPackAuthenticationBuffer(CRED_PACK_PROTECTED_CREDENTIALS, pvOutAuthBuffer, ulOutAuthBufferSize,
szUserName, &cchUserName, szDomainName, &cchDomainName, szPassword, &cchPassword))
{
//...
}
else
{
GetLastError();
}
SetThreadToken(0, 0);
}
Run Code Online (Sandbox Code Playgroud)
或者这样:
if (CredUnPackAuthenticationBuffer(0, pvOutAuthBuffer, ulOutAuthBufferSize,
szUserName, &cchUserName, szDomainName, &cchDomainName, szPassword, &cchPassword))
{
HRESULT hr = DecryptPassword(szPassword, cchPassword);
// ...
}
else
{
GetLastError();
}
Run Code Online (Sandbox Code Playgroud)
和
HRESULT DecryptPassword(PWSTR szPassword, ULONG cchPassword)
{
CRED_PROTECTION_TYPE ProtectionType;
HRESULT hr = HRESULT_FROM_WIN32(BOOL_TO_ERROR(CredIsProtectedW(szPassword, &ProtectionType)));
if (S_OK == hr)
{
ULONG cch = 0;
PWSTR pszCredentials = 0;
switch (ProtectionType)
{
case CredUnprotected:
pszCredentials = szPassword, cch = cchPassword;
break;
case CredTrustedProtection:
case CredForSystemProtection:
if (0 > (hr = ImpersonateSystemToken()))
{
hr |= FACILITY_NT_BIT;
break;
}
[[fallthrough]];
case CredUserProtection:
while (ERROR_INSUFFICIENT_BUFFER == (hr = BOOL_TO_ERROR(CredUnprotectW(
FALSE, szPassword, cchPassword, pszCredentials, &cch))))
{
if (pszCredentials)
{
break;
}
pszCredentials = (PWSTR)alloca(cch * sizeof(WCHAR));
}
if (ProtectionType != CredUserProtection) SetThreadToken(0, 0);
hr = HRESULT_FROM_WIN32(hr);
break;
default:
hr = HRESULT_FROM_NT(STATUS_NOT_IMPLEMENTED);
}
if (0 <= hr)
{
DbgPrint("pass= \"%.*S\"\n", cch, pszCredentials);
}
}
return hr;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
934 次 |
| 最近记录: |