如何通过Windows API令牌模拟访问跨信任AD林的受限资源?
解决跨AD林访问SMB资源的0x5拒绝访问问题
问题背景
- 跨AD林环境:AD1.local与AD2.local已建立双向林信任
- AD1内存在SMB共享资源"X",仅允许AD1的Marketing组成员访问
- AD2域内的BossPC.AD2.local(本地管理员权限)需定期扫描该资源,当前通过
LogonUser()+ImpersonateLoggedOnUser()+文件API的方案持续报0x5(ACCESS_DENIED)错误
核心问题分析
你的代码存在几个关键错误,直接导致访问被拒绝:
- 使用了错误的用户凭证:代码中
LogonUser调用的是AD2域的administrator@ad2.local,该用户不在AD1的Marketing组中,无访问AD1资源的权限,必须使用AD1内属于Marketing组的用户凭证。 - 资源路径错误:代码访问的是AD2域的SYSVOL共享(
\\resourcedc.ad2.local\SYSVOL),而非AD1的目标资源"X"。 - 登录类型选择不当:访问跨域网络资源时,
LOGON32_LOGON_INTERACTIVE并非最优选择,推荐使用更适合跨域场景的登录类型。
修正后的代码示例
#include <windows.h> #include <iostream> using namespace std; HANDLE token = NULL; bool authenticate() { bool bSuccess{ false }; // 跨域访问网络资源优先使用NEW_CREDENTIALS登录类型,不会缓存凭证 DWORD logonType{ LOGON32_LOGON_NEW_CREDENTIALS }; DWORD logonProvider{ LOGON32_PROVIDER_WINNT50 }; cout << endl << "Current process token: " << GetCurrentThreadToken() << endl; // 替换为AD1域内Marketing组的有效用户凭证 bSuccess = LogonUser(L"ad1_marketing_user", L"AD1.local", L"secure_user_password", logonType, logonProvider, &token); if (bSuccess) { cout << endl << "Got token from LogonUser : " << token << endl; bSuccess = ImpersonateLoggedOnUser(token); if (!bSuccess) { wprintf(L"\nImpersonateLoggedOnUser failed with 0x%X", GetLastError()); goto cleanup; } cout << endl << "After impersonation token: " << GetCurrentThreadToken() << endl; // 替换为AD1目标资源的正确SMB路径 HANDLE hFile = CreateFile( L"\\\\ad1-resource-server.ad1.local\\X\\", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr ); if (hFile == INVALID_HANDLE_VALUE) { cout << endl << "CreateFile failed with 0x" << hex << GetLastError(); } else { cout << endl << "CreateFile success: " << hFile; BY_HANDLE_FILE_INFORMATION fileInfo; if (GetFileInformationByHandle(hFile, &fileInfo)) { cout << endl << "File information: attributes = 0x" << hex << fileInfo.dwFileAttributes; } else { cout << endl << "GetFileInformationByHandle failed with 0x" << hex << GetLastError(); } CloseHandle(hFile); } } else { cout << endl << "LogonUser failed with 0x" << hex << GetLastError(); } cleanup: if (token) { CloseHandle(token); token = nullptr; } // 完成操作后立即还原线程身份,避免身份泄漏 RevertToSelf(); return bSuccess; } int main() { authenticate(); return 0; }
额外验证与优化要点
- 权限校验:确认AD1的目标用户确实属于Marketing组,同时检查资源"X"的共享权限和NTFS权限均对该组开放READ权限。
- 特权启用:若使用
FILE_FLAG_BACKUP_SEMANTICS标志,需通过AdjustTokenPrivileges为进程启用SE_BACKUP_NAME特权,否则可能触发权限不足错误。 - 信任关系验证:确认AD林信任为双向,且AD1允许来自AD2的信任访问,同时DNS能正确解析AD1资源服务器的主机名。
- 凭证安全:禁止硬编码密码,建议使用Windows凭据管理器或加密存储方案管理用户凭证。
内容的提问来源于stack exchange,提问作者Arif RiseAgainstHate
相关产品推荐
相关产品推荐

