有过内网测试经验的人基本都敲过这个命令:Meterpreter 里直接输入getsystem,几秒钟后getuid显示NT AUTHORITY\SYSTEM,一条管理员会话就这样变成了系统权限。很多人把它当成“提权玄学”,但仔细拆开看,这个命令背后的逻辑一点也不神秘——它只是把 Windows 令牌机制、服务机制和进程模拟机制组合起来,替你尝试了各种可行的“换身份”路径。
这篇文章我会把getsystem的底层原理拆开讲清楚,包括它到底动了哪些 Windows 权限对象、为什么有时一下就成功有时反复失败、以及防守方该从哪些维度拦住它。无论你是刚开始学内网渗透测试,还是已经在做安全防御,这篇文章都值得花几分钟读完。看完你会明白:getsystem不是“一条命令搞定提权”,而是一整套权限切换思路的集合,理解这套思路,比记住命令本身有用得多。
1. 先说结论:getsystem 不是万能提权,而是一套权限提升的组合拳
1.1 一条命令的背后:为什么管理员权限还不够
很多人第一次产生疑惑,是在一个奇怪的现象里:明明已经是管理员账户了,但在拿到会话后执行某些命令还是提示“拒绝访问”,尤其是访问注册表 SAM 键值、读取 LSASS 进程的内存、或者加载驱动这类操作。这是因为 Windows 里有两套“身份”体系在一同起作用,一套是账户 SID(你是谁),另一套是特权(你能做什么)。
Administrator账户虽然能通过 UAC 提升到管理员权限,但它并不是 Windows 系统里权限最高的身份。真正掌管系统内核级操作的是LocalSystem,也就是我们常说的 SYSTEM 账户。它是一个独立于所有用户的基础系统账户,SID 是S-1-5-18,几乎所有系统服务、驱动加载、SAM 数据库读取,都要求进程至少以 SYSTEM 身份在运行。管理员能做很多事,但和 SYSTEM 之间还隔着一道明显的权限墙。
getsystem就是为了跨过这道墙而存在的。它的目标很纯粹:把当前 Meterpreter 会话所在的进程身份,切换成 SYSTEM。如果会话本身已经是 SYSTEM,它会告诉你已经具备权限;如果不是,它就会尝试用各种机制去拿一个 SYSTEM 令牌,然后用这个令牌去创建新进程或替换当前进程的身份。
1.2 实测中 getsystem 的行为逻辑:自动尝试与手动指定
在默认情况下,直接执行getsystem时,命令后台会按照一组预设的技术列表逐个尝试。不同能力和场景下,它会优先尝试当前会话具备条件的技术。比如当前进程有足够特权,那就直奔令牌相关技术;如果当前账户具备服务创建权限,则可能走服务路径。
你可以用getsystem -h查看参数,常见的是-t指定技术编号。不同版本的 Meterpreter 对技术编号的实现有差异,有些版本的技术列表是:服务方式、命名管道模拟、令牌复制;有些版本会有更多细分。老实说,我见过不少人习惯于反复执行getsystem直到成功,但这并不是一个好习惯,因为默认自动模式会浪费不少时间在不适用的技术上。理解每种技术的适用条件,才能做到“知其然也知其所以然”,也能在失败时准确定位问题。
2. 原理地基:访问令牌、特权与进程身份的底层关联
2.1 Access Token 到底存了哪些东西
Windows 里的访问令牌(Access Token)是一个内核对象,它描述了一个进程或线程的安全上下文。你可以把它想象成一张工牌:上面写着你是谁、属于哪些组、有哪些权限。进程在创建时会关联一个主令牌(Primary Token),线程在执行时还可以临时挂上一个模拟令牌(Impersonation Token),用来以别的身份执行一部分操作。
令牌里主要包括:
- 用户 SID 和组的 SID 列表
- 特权列表(Privileges)
- 所有者、默认 DACL
- 令牌类型(主令牌或模拟令牌)
- 完整性级别(Integrity Level)
- 其他安全属性
当你执行getsystem时,本质上就是在寻找一个 SYSTEM 令牌,然后把当前会话挂载到那个令牌上。SYSTEM 令牌和普通管理员令牌最大的区别并不是“用户名叫 SYSTEM”,而是它的特权列表里几乎包含了所有关键特权,同时它的完整性级别是系统级别,可以访问大多数保护程度较高的系统资源。
2.2 特权列表才是提权目标:SeDebugPrivilege 与 SeImpersonatePrivilege
在 Windows 的权限模型里,特权有时比 SID 更重要。getsystem涉及的几个关键特权是:
SeDebugPrivilege:允许调试他人进程,也就是可以用OpenProcess打开系统进程句柄,从而读取 SYSTEM 进程的令牌。这是令牌复制技术的地基。SeImpersonatePrivilege:允许线程模拟某个已认证用户。这是命名管道模拟和 Potato 类技术的核心。SeAssignPrimaryTokenPrivilege:允许把令牌分配给主令牌,某些场景下需要用它来创建新进程。
很多初学者以为“管理员就是一切”,这是误解。就算你是管理员,如果系统策略显式收回了这些特权,getsystem也可能失败。反过来,有些服务账户虽然不是管理员,但具备SeImpersonatePrivilege,反而可以通过 Potato 类技术轻松拿到 SYSTEM 令牌。这也是为什么在实战中,不一定要追求“管理员会话”,一个服务账户的会话有时更具提权潜力。
2.3 主令牌与模拟令牌:为什么“换个身份”不是简单的赋值
令牌分为主令牌和模拟令牌,两者在 Windows 内部的使用场景不同。主令牌决定一个进程的完整身份,用来执行大多数系统调用;模拟令牌是线程临时借用来的身份,只能用于执行某些操作,不能直接作为新进程的主令牌。
getsystem在做的事情,通常是把获取到的 SYSTEM 令牌经过DuplicateTokenEx复制转换,变成一个新主令牌,然后用CreateProcessWithTokenW或CreateProcessAsUser创建出真正以 SYSTEM 身份运行的新进程。如果是模拟令牌,则需要先提升模拟级别,再转换令牌类型,否则很多操作仍然受限。理解了主令牌和模拟令牌的区别,你就能明白为什么有时提权之后还要迁移进程,或者为什么明明是 SYSTEM 却仍然打不开某些进程——大概率是令牌类型或模拟级别不对。
3. getsystem 的几种底层实现逐个拆解
3.1 谁的令牌可以偷:目标进程的选择逻辑
令牌复制技术的第一步,是找到一个合适的“持卡人”——一个正在以 SYSTEM 身份运行的进程。常见目标包括:
winlogon.exe:登录进程,以 SYSTEM 运行services.exe:服务控制管理器,以 SYSTEM 运行lsass.exe:本地安全认证进程,以 SYSTEM 运行svchost.exe:很多系统服务宿主进程,多数也是 SYSTEM
选择目标进程时有一个讲究:进程的完整性级别和保护级别。Windows 8 之后引入了受保护进程(Protected Process Light,PPL),比如lsass.exe在某些配置下受保护,普通进程即使拥有SeDebugPrivilege也很难打开。所以在老系统上喜欢打lsass.exe的思路在现在不一定好用,反而是winlogon.exe和services.exe更容易成为突破口。
拿到目标进程句柄后,调用OpenProcessToken打开令牌,再调用DuplicateTokenEx复制成新的主令牌,整个链条就完成了大半。
3.2 令牌复制提速:DuplicateToken + CreateProcessWithToken
这是最容易理解、也最经典的一条路径。我用一个简化的 API 调用序列来说明:
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, targetPid); HANDLE tokenHandle = NULL; OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_QUERY, &tokenHandle); HANDLE newToken = NULL; DuplicateTokenEx(tokenHandle, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &newToken); CreateProcessWithTokenW(newToken, LOGON_NETCREDENTIALS_ONLY, L"C:\\Windows\\System32\\cmd.exe", NULL, ...);这段代码展示了核心思想:从 SYSTEM 进程那里“借”令牌,复制出一个主令牌,再用这个新令牌创建进程。创建出来的进程就是 SYSTEM 权限。Meterpreter 的getsystem在成功获取令牌后,往往不是直接在当前进程里切换,而是让会话以新身份继续运行。这也是为什么getsystem之后有时会有短暂的停顿,因为后面可能在启动一个新进程来完成会话接管。
这条路径能不能成功,最大的变量是OpenProcess能否拿到目标进程句柄。如果你没有SeDebugPrivilege,系统会直接拒绝你打开 SYSTEM 进程,所以那些“普通用户跑 getsystem”的想法,在这条路径上基本不会成功。
3.3 服务方式提权:临时服务为何能直接 SYSTEM
服务方式是一条非常稳定的提权路径。Windows 服务控制管理器(SCM)在启动服务时,默认以LocalSystem身份创建服务进程。如果你当前账户具备创建服务的权限,就可以创建一个临时服务,指定一个需要执行的命令,然后让系统帮你以 SYSTEM 身份把这个命令跑起来。
流程大致如下:
- 调用
OpenSCManager打开服务控制管理器 - 调用
CreateService创建一个临时服务,指定服务类型、启动方式和执行路径 - 调用
StartService启动这个服务 - 命令执行完成后,调用
DeleteService清理痕迹
关键点是CreateService默认创建的服务会以SERVICE_LOCAL_SYSTEM账户运行。所以哪怕你只是一个有服务创建权限的管理员,也可以利用这个机制轻松获得一个 SYSTEM 身份来执行指定程序。
这条路径最怕的是防护软件盯上服务创建行为。现在的 EDR 基本都会监控CreateService和StartService的关键调用,临时服务突然出现又消失本来就是一个典型风险信号。我见过不少场景,getsystem走服务方式时被杀软直接干掉了临时服务进程,导致会话异常退出。遇到这种情况,可以考虑先迁移到一个可信的进程中再尝试,或者服务进程的路径尽量伪装成系统常见路径,而不是直接用临时目录。
3.4 命名管道模拟与 Potato 家族:SeImpersonatePrivilege 的高价值
命名管道模拟的路线更像一种“借力打力”的思路。攻击者不需要直接打开 SYSTEM 进程,而是创建一个命名管道,然后想方设法诱导一个 SYSTEM 权限的进程向这个管道发起连接请求。Windows 在服务端接受到命名管道连接时,会执行ImpersonateNamedPipeClient,从而在管道服务线程上获得客户端的模拟令牌,而这个客户端是 SYSTEM,所以模拟令牌也就是 SYSTEM 令牌。
网上常说的 Potato 家族,利用的是 Windows 的各种 RPC 接口中某些“受害者会自动回连”的特性。比如某些系统组件会以 SYSTEM 身份主动去连接指定的 RPC 服务,攻击者通过中间人的方式,把这次连接引到自己的命名管道上来,在连接建立的瞬间调用ImpersonateNamedPipeClient,就拿到了 SYSTEM 模拟令牌。
这条路径的核心前置条件是当前进程必须拥有SeImpersonatePrivilege。而很多服务账户、IIS 应用池账户天生具备这个特权,因此 Potato 家族在实战中的价值相当高。getsystem的部分新版本也已经把命名管道模拟纳入技术列表,所以当你对一个服务账户会话执行getsystem时,成功路径往往不是令牌复制,而是这种模拟技术。
3.5 各种实现技术的适用场景对比
| 技术类型 | 核心前置权限 | 关键 API 或机制 | 典型适用场景 | 主要风险 |
|---|---|---|---|---|
| 令牌复制 | SeDebugPrivilege | OpenProcessToken / DuplicateTokenEx | 已拿到管理员会话或高特权账户 | 受保护进程拦截、EDR 监控进程句柄 |
| 服务方式 | 服务创建权限 | CreateService / StartService | CentOS、Windows 服务类环境,管理员权限 | 杀软监控服务创建与启动 |
| 命名管道模拟 | SeImpersonatePrivilege | ImpersonateNamedPipeClient | 服务账户、IIS 应用池账户 | 依赖系统版本,部分新系统已缓解 |
4. 实战操作:从输入 getsystem 到确认 SYSTEM 的完整链路
4.1 参数选择:-t 技术编号该怎么理解
getsystem的参数并不多,最重要的是-t。不过不同版本的技术编号不完全相同,所以最稳妥的做法是先执行getsystem -h看本机的技术列表。通常你能看到类似这样的输出:
Usage: getsystem [options] OPTIONS: -t <opt> Technique to use if you want to force a specific technique这里的-t后面跟的数字对应不同的实现方式:有的版本里 1 表示服务方式,2 表示命名管道模拟,3 表示令牌复制。不要死记硬背某个编号,因为 payload 升级后技术顺序可能变化。我的经验是:先用默认自动模式跑一次,如果失败,再用-t逐项试,观察每项技术失败时的提示,能帮你更清楚地判断当前会话到底缺什么条件。
4.2 一次完整的命令行演示
假设我现在已经拿到一个 Meterpreter 会话,先看当前身份和特权,再执行提权:
meterpreter > getuid Server username: LAB-DEMO\UserA meterpreter > getprivs Enabled Process Privileges: SeDebugPrivilege SeTcbPrivilege SeAssignPrimaryTokenPrivilege ... meterpreter > getsystem ...getsystem: Service technique failed. (Next technique: 2/3) ...getsystem: Named Pipe technique succeeded. meterpreter > getuid Server username: NT AUTHORITY\SYSTEM从SeDebugPrivilege存在开始,我就知道会话具备令牌类技术的条件;而SeTcbPrivilege的存在,意味着会话本身已经有较高的系统权限。实际执行时我看到前一个技术失败、后一个技术成功,这说明自动模式在按顺序尝试,遇到不适用的技术会跳到下一个,直到成功或全部失败。提权后再次执行getuid,确认身份已经切换为NT AUTHORITY\SYSTEM,这一步不能省略,因为不是所有输出都明确写着成功。
4.3 常见失败信号与排查路径
最让人头疼的自然是getsystem执行之后直接返回失败。我遇到的失败场景大致可以归为以下几类:
| 现象 | 可能原因 | 排查方式 |
|---|---|---|
Failed to get SYSTEM | 当前用户权限过低,令牌复制打不开系统进程 | 先尝试 UAC 绕过或换一个管理员会话再执行 |
| 进程消失或会话掉线 | 杀软拦截了服务创建或进程注入 | 检查杀软日志,尝试其他技术编号或迁移进程 |
| 一直卡在某个技术编号 | 当前会话架构与系统位数不匹配 | 确认是 x86 还是 x64 Meterpreter,必要时迁移到相同位数进程 |
The token is already elevated | 当前本来就是 SYSTEM 或等效权限 | 直接用getuid验证 |
| 特定技术编号报错 | 该技术依赖的特权被禁用或系统版本不支持 | 逐项测试其他技术编号,优先走-t手动模式 |
另外一个常见的坑是进程位数。如果你的 Meterpreter 是 x86 版本,运行在 64 位系统上,在尝试打开某些 64 位 SYSTEM 进程时可能会遇到兼容性问题,导致OpenProcess失败。解决办法是先把 Meterpreter 迁移到一个同为 x64 的进程中,再重新执行getsystem。
4.4 提权后的权限验证与局限性
提权成功后,建议做两件事。第一,执行getuid确认当前身份已经变成NT AUTHORITY\SYSTEM;第二,直接执行某个需要 SYSTEM 权限的操作来验证实际能力,比如尝试读取注册表 SAM 键值,或者执行ps查看当前会话是否能够列出所有进程。有些场景下,虽然getuid显示 SYSTEM,但令牌是模拟令牌,完整性级别不一定够。此时可以执行shell进入一个交互式命令行,用whoami /all看看当前令牌的完整信息。
还要明白getsystem的局限性:它不是一个“从普通用户直接变 SYSTEM”的万能工具。多数技术路径都要求会话本身已经是本地管理员或至少具备某些高级特权。如果当前会话是低权限普通用户,直接调用getsystem大概率会失败,这时候应该先想办法提升到管理员权限,再做 SYSTEM 级提权。
5. 防守方视角:怎么让这套组合拳失效
5.1 削减令牌攻击面
既然getsystem的核心是拿到 SYSTEM 令牌,那防守重点就很明确了:让令牌不能被轻易获取和复制。具体可以做的事不少:
- 移除普通管理员不必要的
SeDebugPrivilege - 对关键系统进程启用受保护进程(PPL),尤其是
lsass.exe - 开启 Credential Guard,让 LSASS 进程内维护的凭据得到隔离保护
- 限制管理员账户的令牌窃取能力,通过组策略调整用户权限指派
实战中我遇到过不少系统其实已经做了部分加固,执行getsystem时能看到打开了目标进程,但后续的令牌复制被拒绝,原因就是 PPL 或 Credential Guard 介入了。这说明,检测侧不需要等到进程创建才告警,令牌相关 API 的调用本身就很值得关注。
5.2 服务创建与管道模拟的检测维度
服务创建是一条非常容易被防守方发现的路径。比如,可以通过以下事件监控服务创建与启动:
- Windows 事件 ID 4697:服务创建
- Windows 事件 ID 7045:服务安装(系统日志)
- 进程创建事件中父进程是 services.exe 的可疑进程,使用
svchost.exe -k之外的可执行路径
命名管道模拟的检测则更隐蔽,但也不是无迹可寻。关键看两个点:进程是否创建了命名管道,以及是否调用了ImpersonateNamedPipeClient。在 EDR 的监控规则里,这两类调用的组合出现是 Potato 类攻击的典型特征。另外,高权限进程主动连接低权限进程创建的命名管道,本身就是一个异常行为,可以通过管道创建与访问的审计来发现。
5.3 测试工作的边界:授权与还原
这里必须多说一句。getsystem也好,更底层的提权技术也好,都应该只在明确授权的环境中使用。做测试时,我会在项目开始时记录当前会话权限、系统版本、补丁情况,提权成功后及时做截图留档,测试结束时把临时创建的服务、计划任务都清理干净,恢复到初始状态。这既是对目标系统负责,也是安全测试的基本职业素养。不要为了“看起来厉害”就无边界地使用这些技术,合规才是最重要的底线。
6. 写在最后:一点个人经验
说实话,我第一次成功执行getsystem是在本地虚拟机里,当时我以为是某种“玄学命令”,敲下去就成功了。后来仔细读完系统原理和相关的实现代码才发现,这个命令只是在不断尝试“换一张更高级的工牌”。当你真正理解了令牌、特权、服务、命名管道这些机制后,再回头看getsystem,它就不再有神秘感了。
最后分享一个排查小技巧:如果你在目标机上发现当前会话是普通用户,别急着反复敲getsystem。先确认会话有没有可用的提权路径,比如 UAC 绕过、已知漏洞或服务配置弱点。先把权限提成管理员,再执行getsystem,成功率会高得多,也节省大量时间。理解这条路之后,你会发现,真正的提权能力不在于命令本身,而在于对 Windows 安全模型的理解深度。