WTS API 令牌窃取技术

admin 2023年10月14日15:26:51评论48 views字数 2883阅读9分36秒阅读模式

概述

传统令牌窃取技术如下:

OpenProcess / NtOpenProcess -> OpenProcessToken -> DuplicateTokenEx -> CreateProcessWithTokenW. 这种方法目前很容易被EDR、XDR或者其他安全解决方案检测到。普通的令牌模拟会操作进程令牌,而WTS技术在进程中仅调用OpenProcessToken(在我们自己的进程上),其余操作通过RPC命名管道PipeLSM_API_service完成,另一个进程为我们完成了繁重的任务。

分析过程

WTSQueryUserToken

WTS API 令牌窃取技术

BOOL WTSQueryUserToken(  [in]  ULONG   SessionId,  [out] PHANDLE phToken);

传入一个登录会话ID:SessionId,返回登录用户的令牌句柄。文档还给出了怎么获取会话ID:

A Remote Desktop Services session identifier. Any program running in the context of a service will have a session identifier of zero (0). You can use the WTSEnumerateSessions[1] function to retrieve the identifiers of all sessions on a specified RD Session Host server.

WTSEnumerateSessions

BOOL WTSEnumerateSessionsA(  [in]  HANDLE             hServer,  [in]  DWORD              Reserved,  [in]  DWORD              Version,  [out] PWTS_SESSION_INFOA *ppSessionInfo,  [out] DWORD              *pCount);

通过整理各种碎片信息可以构建以下函数序列:

WTSEnumerateSessionsA → WTSQuerySessionInformationA -> WTSQueryUserToken -> CreateProcessAsUserW

1.WTSEnumerateSessionsA: 这是用于枚举当前计算机上所有用户会话的函数。它可以列出所有已登录用户的会话,以及它们的会话ID等信息。2.WTSQuerySessionInformationA: 这个函数用于查询特定用户会话的信息,通常用于获取用户会话的详细信息,如用户名、域名、连接状态等。3.WTSQueryUserToken: 这个函数用于获取指定用户会话的用户令牌(token)。用户令牌是用于验证用户身份和访问权限的关键对象。通常,通过这个函数获取的用户令牌用于后续的操作,以确保进程在正确的上下文中运行。4.CreateProcessAsUserW: 这是一个用于在指定用户会话中创建一个新进程的函数。它接受用户令牌和其他参数,以创建一个以指定用户身份运行的进程。

但是需要注意一个问题。WTSQueryUserToken需要服务的上下文环境才能生效,并且该服务必须具有SeDelegateSessionUserImpersonatePrivilege权限和SE_TCB_NAME权限。另外枚举阶段可以通过使用名为pipeLSM_API_service的RPC命名管道(WTSEnumeratureSessionsA→ WTSQuerySessionInformationA),这意味着我们可以使用RPC来发现每个站点哪些用户连接到,而无需在系统上部署代码。由于这个名称管道几乎没有文档记录,我们可以猜测LSM代表Local Security Manager(只是猜测)。下面借助WTSImpersonator[2]项目介绍窃取过程。

代码简述

枚举功能,可以使用WTSOpenServer或WTSOpenServerEx函数来检索特定服务器的句柄,也可以使用WTS_CURRENT_server_handle来使用承载应用程序的RD会话主机服务器:

HANDLE hServer = ServerName ? WTSOpenServerA(ServerName) : WTS_CURRENT_SERVER_HANDLE;            PWTS_SESSION_INFOA pSessionInfo;            bSuccess = WTSEnumerateSessionsA(hServer, 0, 1, &pSessionInfo, &count);            if (!bSuccess)            {                printf("WTSEnumerateSessions failed: %dn", (int)GetLastError());                return 0;            }

pSessionInfo结构如下:

typedef struct _WTS_SESSION_INFOA {    DWORD        SessionId;    LPSTR        pWinStationName;    WTS_CONNECTSTATE_CLASS State;} WTS_SESSION_INFOA, * PWTS_SESSION_INFOA;

循环读取获取到的sessionid信息并打印出来:

WTS API 令牌窃取技术

WTSQueryUserToken根据指定的sessionid获取其token,并把token相关信息打印输出:

WTS API 令牌窃取技术

再使用该token的权限打开目标进程,这里后面使用cmd测试:

    if (CreateProcessAsUserW(hToken, PATH, NULL, NULL,        NULL, FALSE, 0, NULL, NULL, &si, &pi))    {        /* Process has been created; work with the process and wait for it to        terminate. */        WaitForSingleObject(pi.hProcess, INFINITE);        CloseHandle(pi.hThread);        CloseHandle(pi.hProcess);    }

执行效果

我们现在普通环境下枚举当前的会话ID:

WTSImpersonator.exe -m enum

WTS API 令牌窃取技术

此时我们使用id为1的token进行窃取是没啥效果的:

WTSImpersonator.exe -m exec -id 1 -c C:WindowsSystem32cmd.exe

WTS API 令牌窃取技术

因为不在windows服务环境下,我们尝试使用

PsExec64.exe -accepteula -s cmd.exe,启动cmd,然后同样执行上述命令,发现就成功使用目标token创建cmd:

WTS API 令牌窃取技术

总结

道高一尺魔高一丈

References

[1] WTSEnumerateSessions: https://learn.microsoft.com/en-us/windows/desktop/api/wtsapi32/nf-wtsapi32-wtsenumeratesessionsa
[2] WTSImpersonator: https://github.com/OmriBaso/WTSImpersonator


信息安全吹水:

WTS API 令牌窃取技术


原文始发于微信公众号(TIPFactory情报工厂):WTS API 令牌窃取技术

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月14日15:26:51
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   WTS API 令牌窃取技术https://cn-sec.com/archives/2111500.html

发表评论

匿名网友 填写信息