模拟用户登录
--张佩
1. 用户模拟
如果将文件test.exe的安全属性设置成Guest用户无法访问的话,以Guest用户登录后,访问者就不能访问test.exe文件了。但有一个办法可以让访问者在使用Guest账户登录的情况下也能够访问此文件,就是使用用户模拟的方式,暂时以高权用户的身分访问这个文件!下面的代码实现了用户模拟:
HANDLEhToken;
DWORD dwError;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
if(0 ==LogonUser("administ", ".", "password", LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT, &hToken))
{
printf("Failed to call LogonUser/r/n");
dwError = GetLastError();
}
else
{
if(CreateProcessAsUserW(hToken,L"c://test.exe",NULL,
NULL, NULL,
FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi))
{/×成功×/}
}
代码调用了两个关键函数:LogonUser获取高权用户的令牌(Token),令牌代表了用户所能拥有的系统权限,使用这个API需要将用户名称和密码作为参数输入;CreateProcessAsUser利用此用户令牌创建进程,从而执行有安全保护的文件。
如果要提权的不是可执行程序,而是一个文档(比如:text.txt),比如要读取它里面的数据,应怎么办呢?其实很简单,代码如下:
bRet = ImpersonateLoggedOnUser(hToken);
if(bRet)
{
FILE* hFile = fopen("c://test.txt", "r");
RevertToSelf();
}
ImpersonateLoggedOnUser的作用是模拟用户,就是让当前执行进程暂时以被模拟用户的身份来运行,并完全使用被模拟用户的权限级别来操作。输入参数hToken就是前面已经获取的用户令牌。调用RevertToSelf让当前进程恢复到本身的用户环境。
2. 问题和改进
上面的方法有一个缺点,通过LogonUser打开用户令牌的时候,必须输入用户名和密码作为必备参数,可移植性太差。如果有更好的办法获取高权用户Token就好了。每个进程在运行的时候都保存一个用户令牌,而用户令牌又是可以获取的,从这一点出发,我们能想到更好的办法。winlogon.exe进程总是以System用户权限运行,下面的代码将从Winlogon中提取System用户令牌(代码作者是我的同事
jiurl):
pid = FindWinlogon();//取得winlogon.exe的进程ID,从略
if(pid<0 )
{
return 0;
}
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
if(hProcess==NULL )
{
return 0;
}
rc = OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hOldToken );
if(rc==0 )
{
CloseHandle(hProcess);
return 0;
}
rc = DuplicateTokenEx(hOldToken,NULL, NULL, SecurityIdentification, TokenPrimary, &hNewToken);
if(rc==0 )
{
CloseHandle(hProcess);
CloseHandle(hOldToken);
return 0;
}
(注:上面的代码一般应在单独的服务中运行,否则代码本身可能会因为权限问题而中途失败)代码分成了三个部分,首先是找到Winlogon进程,具体方法很多,代码从略。然后获取进程令牌,通过调用OpenProcessToken函数实现。最后复制一个令牌给当前进程使用,从而生成新的令牌句柄,这一步通过调用DuplicateToken/DuplicateTokenEx实现。得到新的令牌句柄hNewToken后,我们就可以继续第一节中的用户模拟,从而实施高权操作了。