网安教育
培养网络安全人才
技术交流、学习咨询
在内网渗透中令牌窃取通常用于从Administrator权限提升到System权限或者用于获取trustedinstaller等权限,令牌窃取通过Metasploit框架提供的载荷很容易实现,在学习了Windows访问控制的内容之后,可以自己实现一个令牌窃取的工具,比如 JCTokenUtil、SharpToken、incognito,这篇文章是笔者学习令牌窃取的原理和实现的产出。
令牌列举就是列举本地计算机上所有的访问令牌,NtQuerySystemInformationAPI是用来检索指定的系统信息的,NtQuerySystemInformationAPI的原型如下
1__kernel_entry NTSTATUS NtQuerySystemInformation(
2 [in] SYSTEM_INFORMATION_CLASS SystemInformationClass,
3 [in, out] PVOID SystemInformation,
4 [in] ULONG SystemInformationLength,
5 [out, optional] PULONG ReturnLength
6);
SystemInformationClass参数标识要检索的系统信息,它是SYSTEM_INFORMATION_CLASS中枚举的值之一。SYSTEM_INFORMATION_CLASS的原型如下
1typedef enum _SYSTEM_INFORMATION_CLASS {
2SystemBasicInformation,
3SystemProcessorInformation,
4SystemPerformanceInformation,
5SystemTimeOfDayInformation,
6SystemPathInformation,
7SystemProcessInformation,
8SystemCallCountInformation,
9SystemDeviceInformation,
10SystemProcessorPerformanceInformation,
11SystemFlagsInformation,
12SystemCallTimeInformation,
13SystemModuleInformation,
14SystemLocksInformation,
15SystemStackTraceInformation,
16SystemPagedPoolInformation,
17SystemNonPagedPoolInformation,
18SystemHandleInformation,
19SystemObjectInformation,
20SystemPageFileInformation,
21SystemVdmInstemulInformation,
22SystemVdmBopInformation,
23SystemFileCacheInformation,
24SystemPoolTagInformation,
25SystemInterruptInformation,
26SystemDpcBehaviorInformation,
27SystemFullMemoryInformation,
28SystemLoadGdiDriverInformation,
29SystemUnloadGdiDriverInformation,
30SystemTimeAdjustmentInformation,
31SystemSummaryMemoryInformation,
32SystemNextEventIdInformation,
33SystemEventIdsInformation,
34SystemCrashDumpInformation,
35SystemExceptionInformation,
36SystemCrashDumpStateInformation,
37SystemKernelDebuggerInformation,
38SystemContextSwitchInformation,
39SystemRegistryQuotaInformation,
40SystemExtendServiceTableInformation,
41SystemPrioritySeperation,
42SystemPlugPlayBusInformation,
43SystemDockInformation,
44SystemPowerInformation,
45SystemProcessorSpeedInformation,
46SystemCurrentTimeZoneInformation,
47SystemLookasideInformation
48} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;
当枚举值为SystemProcessInformation时标识要检索计算机上的所有进程信息,这时SystemInformation参数指向检索结果的第一个进程的SYSTEM_PROCESS_INFORMATION结构,SYSTEM_PROCESS_INFORMATION的原型如下
1typedef struct _SYSTEM_PROCESS_INFORMATION {
2ULONG NextEntryOffset;
3ULONG NumberOfThreads;
4BYTE Reserved1[48];
5UNICODE_STRING ImageName;
6KPRIORITY BasePriority;
7HANDLE UniqueProcessId;
8PVOID Reserved2;
9ULONG HandleCount;
10ULONG SessionId;
11PVOID Reserved3;
12SIZE_T PeakVirtualSize;
13SIZE_T VirtualSize;
14ULONG Reserved4;
15SIZE_T PeakWorkingSetSize;
16SIZE_T WorkingSetSize;
17PVOID Reserved5;
18SIZE_T QuotaPagedPoolUsage;
19PVOID Reserved6;
20SIZE_T QuotaNonPagedPoolUsage;
21SIZE_T PagefileUsage;
22SIZE_T PeakPagefileUsage;
23SIZE_T PrivatePageCount;
24LARGE_INTEGER Reserved7[6];
25} SYSTEM_PROCESS_INFORMATION;
NumberOfThreads成员指示进程拥有的线程数,UniqueProcessId成员指示进程的唯一进程ID,HandleCount成员指示进程拥有的句柄数,NextEntryOffset指示下一个SYSTEM_PROCESS_INFORMATION结构距离当前结构的偏移,最后一个SYSTEM_PROCESS_INFORMATION结构的NextEntryOffset成员值为0。
SYSTEM_PROCESS_INFORMATION结构后紧跟若干个SYSTEM_THREAD_INFORMATION结构表示此进程的若干个线程。
通过NtQuerySystemInformationAPI获取到计算机上所有的进程后,可以通过DuplicateHandle函数获取每个进程拥有的所有句柄,然后用NtQueryObject函数来检索句柄对应的对象类型。
NtQueryObject函数原型如下
1__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
2 [in, optional] HANDLE Handle, //要检索的句柄
3 [in] OBJECT_INFORMATION_CLASS ObjectInformationClass,
4 [out, optional] PVOID ObjectInformation,
5 [in] ULONG ObjectInformationLength,
6 [out, optional] PULONG ReturnLength
7);
当指定ObjectInformationClass成员为ObjectTypeInformation枚举值时,ObjectInformation参数返回PUBLIC_OBJECT_TYPE_INFORMATION结构,PUBLIC_OBJECT_TYPE_INFORMATION结构原型如下
1typedef enum _OBJECT_INFORMATION_CLASS {
2 ObjectBasicInformation,
3 ObjectTypeInformation
4} OBJECT_INFORMATION_CLASS;
TypeName成员表示对象的类型字符串,当对象是访问令牌时该值为Token,通过控制该值为Token就可以过滤出所有访问令牌的句柄。
注意的是,工具获取的是访问令牌模拟级别大于SecurityImpersonation模拟级别的访问令牌,通过GetTokenInformation函数获取访问令牌的TokenImpersonationLevel成员来确定访问令牌的模拟级别。
通过上面的步骤就可以获取到每个进程拥有的访问令牌句柄,但是上面检索的访问令牌不包括每个进程本身的访问令牌,所以需要再通过OpenProcessToken函数来获取进程本身的令牌句柄。
比如我们想窃取NT AUTHORITYSYSTEM账户的令牌来执行命令,我们需要先找到NT AUTHORITYSYSTEM账户的令牌。这个很简单,通过GetTokenInformation函数获取到令牌的用户SID,然后用LookupAccountSidA函数将SID转换为对应的账户名即可。
找到NT AUTHORITYSYSTEM账户的令牌后,需要把令牌的TokenSessionId改为当前进程令牌的TokenSessionId,调用SetTokenInformation函数来设置即可。注意更改令牌的TokenSessionId需要SeTcbPrivilege特权。
最后调用CreateProcessAsUserA函数来执行命令,CreateProcessAsUserA函数的原型如下
1BOOL CreateProcessAsUserA(
2 [in, optional] HANDLE hToken,
3 [in, optional] LPCSTR lpApplicationName,
4 [in, out, optional] LPSTR lpCommandLine,
5 [in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
6 [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
7 [in] BOOL bInheritHandles,
8 [in] DWORD dwCreationFlags,
9 [in, optional] LPVOID lpEnvironment,
10 [in, optional] LPCSTR lpCurrentDirectory,
11 [in] LPSTARTUPINFOA lpStartupInfo,
12 [out] LPPROCESS_INFORMATION lpProcessInformation
13);
lpCommandLine参数传递要执行的命令,hToken参数传递NT AUTHORITYSYSTEM账户的令牌。
由于更改令牌的TokenSessionId值需要SeTcbPrivilege特权,CreateProcessAsUserA函数的调用需要SE_ASSIGNPRIMARYTOKEN_NAME特权。而NT AUTHORITYSYSTEM账户拥有这两个特权,所以在更改令牌的TokenSessionId值和调用CreateProcessAsUserA函数之前先调用ImpersonateLoggedOnUser函数模拟NT AUTHORITYSYSTEM账户。
熟悉令牌窃取的应该都知道一般普通用户是无法窃取令牌来执行命令的,这就导致令牌窃取只能用来从Administrator权限提升到System权限或System权限到trustedinstaller权限等。
出现这种情况的原因之一是普通用户无法获取到System、Administrator等账户的令牌,管理员账户获取到的令牌有730个
而普通账户获取到的令牌只有345个
我把普通账户获取到的令牌都down下来后发现此普通账户获取到的令牌用户都是其本身,没有其它账户存在。
账户能获取到多少令牌,取决于令牌的安全描述符和完整性级别是否允许账户对令牌的请求。
文:hangchuanin
原文链接:https://xz.aliyun.com/t/11981#toc-0
版权声明:著作权归作者所有。如有侵权请联系删除
战疫期间,开源聚合网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入开源聚合网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!
加QQ(1005989737)找小姐姐私聊哦
原文始发于微信公众号(开源聚合网络空间安全研究院):【网安干货】内网渗透从零到一之令牌窃取
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论