内网渗透之令牌窃取
原文链接: https://mp.weixin.qq.com/s?__biz=MzkwODc1NTgyMg==&mid=2247487314&idx=1&sn=ce3f14deb4e79dd84f77a86601024a63
内网渗透之令牌窃取
hangchuanin 蓝云Sec 2025-07-11 16:01
原文链接:
https://xz.aliyun.com/news/11427
0x00
在内网渗透中令牌窃取通常用于从Administrator权限提升到System权限或者用于获取trustedinstaller等权限,令牌窃取通过Metasploit框架提供的载荷很容易实现,在学习了Windows访问控制的内容之后,可以自己实现一个令牌窃取的工具,比如 JCTokenUtil、SharpToken、incognito,这篇文章是笔者学习令牌窃取的原理和实现的产出。
0x01 令牌列举
令牌列举就是列举本地计算机上所有的访问令牌,
NtQuerySystemInformation
API是用来检索指定的系统信息的,
NtQuerySystemInformation
API的原型如下
__kernel_entryNTSTATUSNtQuerySystemInformation([in]SYSTEM_INFORMATION_CLASSSystemInformationClass,[in,out]PVOIDSystemInformation,[in]ULONGSystemInformationLength,[out,optional]PULONGReturnLength);
SystemInformationClass
参数标识要检索的系统信息,它是
SYSTEM_INFORMATION_CLASS
中枚举的值之一。
SYSTEM_INFORMATION_CLASS
的原型如下
typedefenum_SYSTEM_INFORMATION_CLASS{SystemBasicInformation,SystemProcessorInformation,SystemPerformanceInformation,SystemTimeOfDayInformation,SystemPathInformation,SystemProcessInformation,SystemCallCountInformation,SystemDeviceInformation,SystemProcessorPerformanceInformation,SystemFlagsInformation,SystemCallTimeInformation,SystemModuleInformation,SystemLocksInformation,SystemStackTraceInformation,SystemPagedPoolInformation,SystemNonPagedPoolInformation,SystemHandleInformation,SystemObjectInformation,SystemPageFileInformation,SystemVdmInstemulInformation,SystemVdmBopInformation,SystemFileCacheInformation,SystemPoolTagInformation,SystemInterruptInformation,SystemDpcBehaviorInformation,SystemFullMemoryInformation,SystemLoadGdiDriverInformation,SystemUnloadGdiDriverInformation,SystemTimeAdjustmentInformation,SystemSummaryMemoryInformation,SystemNextEventIdInformation,SystemEventIdsInformation,SystemCrashDumpInformation,SystemExceptionInformation,SystemCrashDumpStateInformation,SystemKernelDebuggerInformation,SystemContextSwitchInformation,SystemRegistryQuotaInformation,SystemExtendServiceTableInformation,SystemPrioritySeperation,SystemPlugPlayBusInformation,SystemDockInformation,SystemPowerInformation,SystemProcessorSpeedInformation,SystemCurrentTimeZoneInformation,SystemLookasideInformation}SYSTEM_INFORMATION_CLASS,*PSYSTEM_INFORMATION_CLASS;
当枚举值为
SystemProcessInformation
时标识要检索计算机上的所有进程信息,这时
SystemInformation
参数指向检索结果的第一个进程的
SYSTEM_PROCESS_INFORMATION
结构,
SYSTEM_PROCESS_INFORMATION
的原型如下
typedefstruct_SYSTEM_PROCESS_INFORMATION{ULONGNextEntryOffset;ULONGNumberOfThreads;BYTEReserved1[48];UNICODE_STRINGImageName;KPRIORITYBasePriority;HANDLEUniqueProcessId;PVOIDReserved2;ULONGHandleCount;ULONGSessionId;PVOIDReserved3;SIZE_TPeakVirtualSize;SIZE_TVirtualSize;ULONGReserved4;SIZE_TPeakWorkingSetSize;SIZE_TWorkingSetSize;PVOIDReserved5;SIZE_TQuotaPagedPoolUsage;PVOIDReserved6;SIZE_TQuotaNonPagedPoolUsage;SIZE_TPagefileUsage;SIZE_TPeakPagefileUsage;SIZE_TPrivatePageCount;LARGE_INTEGERReserved7[6];}SYSTEM_PROCESS_INFORMATION;
NumberOfThreads
成员指示进程拥有的线程数,
UniqueProcessId
成员指示进程的唯一进程ID,
HandleCount
成员指示进程拥有的句柄数,
NextEntryOffset
指示下一个
SYSTEM_PROCESS_INFORMATION
结构距离当前结构的偏移,最后一个
SYSTEM_PROCESS_INFORMATION
结构的
NextEntryOffset
成员值为0。
SYSTEM_PROCESS_INFORMATION
结构后紧跟若干个
SYSTEM_THREAD_INFORMATION
结构表示此进程的若干个线程。
通过
NtQuerySystemInformation
API获取到计算机上所有的进程后,可以通过
DuplicateHandle
函数获取每个进程拥有的所有句柄,然后用
NtQueryObject
函数来检索句柄对应的对象类型。
NtQueryObject
函数原型如下
__kernel_entryNTSYSCALLAPINTSTATUSNtQueryObject([in,optional]HANDLEHandle,//要检索的句柄[in]OBJECT_INFORMATION_CLASSObjectInformationClass,[out,optional]PVOIDObjectInformation,[in]ULONGObjectInformationLength,[out,optional]PULONGReturnLength);
OBJECT_INFORMATION_CLASS
是一个枚举类型,原型如下
typedefenum_OBJECT_INFORMATION_CLASS{ObjectBasicInformation,ObjectTypeInformation}OBJECT_INFORMATION_CLASS;
当指定
ObjectInformationClass
成员为
ObjectTypeInformation
枚举值时,
ObjectInformation
参数返回
PUBLIC_OBJECT_TYPE_INFORMATION
结构,
PUBLIC_OBJECT_TYPE_INFORMATION
结构原型如下
typedefstruct__PUBLIC_OBJECT_TYPE_INFORMATION{UNICODE_STRINGTypeName;ULONGReserved[22];// reserved for internal use}PUBLIC_OBJECT_TYPE_INFORMATION,*PPUBLIC_OBJECT_TYPE_INFORMATION;
TypeName
成员表示对象的类型字符串,当对象是访问令牌时该值为
Token
,通过控制该值为
Token
就可以过滤出所有访问令牌的句柄。
注意的是,工具获取的是访问令牌模拟级别大于
SecurityImpersonation
模拟级别的访问令牌,通过
GetTokenInformation
函数获取访问令牌的
TokenImpersonationLevel
成员来确定访问令牌的模拟级别。
通过上面的步骤就可以获取到每个进程拥有的访问令牌句柄,但是上面检索的访问令牌不包括每个进程本身的访问令牌,所以需要再通过
OpenProcessToken
函数来获取进程本身的令牌句柄。
0x02 窃取令牌来执行命令
比如我们想窃取NT AUTHORITY\SYSTEM账户的令牌来执行命令,我们需要先找到NT AUTHORITY\SYSTEM账户的令牌。这个很简单,通过
GetTokenInformation
函数获取到令牌的用户SID,然后用
LookupAccountSidA
函数将SID转换为对应的账户名即可。
找到NT AUTHORITY\SYSTEM账户的令牌后,需要把令牌的
TokenSessionId
改为当前进程令牌的
TokenSessionId
,调用
SetTokenInformation
函数来设置即可。注意更改令牌的
TokenSessionId
需要SeTcbPrivilege特权。
最后调用
CreateProcessAsUserA
函数来执行命令,
CreateProcessAsUserA
函数的原型如下
BOOLCreateProcessAsUserA([in,optional]HANDLEhToken,[in,optional]LPCSTRlpApplicationName,[in,out,optional]LPSTRlpCommandLine,[in,optional]LPSECURITY_ATTRIBUTESlpProcessAttributes,[in,optional]LPSECURITY_ATTRIBUTESlpThreadAttributes,[in]BOOLbInheritHandles,[in]DWORDdwCreationFlags,[in,optional]LPVOIDlpEnvironment,[in,optional]LPCSTRlpCurrentDirectory,[in]LPSTARTUPINFOAlpStartupInfo,[out]LPPROCESS_INFORMATIONlpProcessInformation);
lpCommandLine
参数传递要执行的命令,
hToken
参数传递NT AUTHORITY\SYSTEM账户的令牌。
由于更改令牌的
TokenSessionId
值需要SeTcbPrivilege特权,
CreateProcessAsUserA
函数的调用需要SE_ASSIGNPRIMARYTOKEN_NAME特权。而NT AUTHORITY\SYSTEM账户拥有这两个特权,所以在更改令牌的
TokenSessionId
值和调用
CreateProcessAsUserA
函数之前先调用
ImpersonateLoggedOnUser
函数模拟NT AUTHORITY\SYSTEM账户。
0x03 为什么低权限用户无法窃取令牌
熟悉令牌窃取的应该都知道一般普通用户是无法窃取令牌来执行命令的,这就导致令牌窃取只能用来从
Administrator
权限提升到
System
权限或
System
权限到
trustedinstaller
权限等。
出现这种情况的原因之一是普通用户无法获取到
System
、
Administrator
等账户的令牌,管理员账户获取到的令牌有730个
而普通账户获取到的令牌只有345个
我把普通账户获取到的令牌都down下来后发现此普通账户获取到的令牌用户都是其本身,没有其它账户存在。
账户能获取到多少令牌,取决于令牌的安全描述符和完整性级别是否允许账户对令牌的请求。
蓝云Sec公众号公开交流群,欢迎大家加入!