☰
MS15-051实战:Windows Server 2008 R2本地提权到SYSTEM全解析
2026/10/20 7:26:39 网站建设 项目流程

做内网渗透这几年,最难搞的其实不是打进去,而是打进去之后拿不到应有的权限。很多时候,你费尽心思拿到一个WebShell,结果一看是IIS中间件权限,或者是某个低权限服务账户,想读个密码哈希、横向移动都寸步难行。这种情况下,本地权限提升就是必答题。前阵子我正好在一个模拟内网环境里碰到一台Windows Server 2008 R2,系统补丁停留在好几年前,手持一个普通用户权限,最后通过MS15-051漏洞一路提权到SYSTEM,整个过程非常典型。今天就把这次实战的完整思路、操作细节和对应的防御加固方案一次性讲透。

MS15-051这个漏洞,全称是“Windows内核模式驱动程序中的权限提升漏洞”,影响面覆盖Windows Server 2003到2012 R2以及对应的桌面系统。它的利用代码公开得非常早,稳定性和通用性在众多提权漏洞里都算名列前茅。对搞渗透测试的人来说,当目标机器无法联网、补丁未更新、Metasploit模块又不灵光的时候,手工编译MS15-051的利用程序往往能救急。这篇文章适合正在学内网渗透的新手,也适合需要快速温习提权思路的蓝队同学——攻防本来就一体,知道攻击怎么打,才能知道防御怎么守。

这篇文章我会把这台Server 2008 R2机器的整个提权过程拆开来讲,从漏洞原理、环境判断、编译利用,到实战中各种报错的排查,一条龙走完。最后还会从防御者的视角详细说说,面对这类老系统提权漏洞,你到底该做哪些缓解措施才算真的"扛得住"。

1. 漏洞原理与适用场景

1.1 MS15-051的核心成因

MS15-051对应的内核驱动函数是NtApphelpCacheControl,这个函数本来是系统用来管理应用程序兼容性缓存(AppCompat Cache)的。问题出在NtApphelpCacheControl在对用户传入的ApphelpCacheControl结构体做校验时,没有严格验证调用者是否有足够的权限,导致任意权限的进程都能触发内核态代码执行路径。

利用思路很简单,就是通过这个漏洞调用特定功能,让内核将一份恶意DLL加载到SYSTEM权限的进程中,从而完成权限提升。它的触发点在驱动层,所以一旦利用成功,拿到的基本就是SYSTEM级别的令牌,而且相比一些用户态漏洞利用(比如服务配置篡改类),它的隐蔽性更好,因为不依赖计划任务、不注册服务,行为特征更接近正常的系统调用。

1.2 影响范围与判定条件

MS15-051影响的操作系统覆盖范围很广,包括:

  • Windows Server 2003 / 2008 / 2008 R2 / 2012 / 2012 R2
  • Windows XP / 7 / 8 / 8.1
  • Windows Vista

2015年4月微软发布的安全公告MS15-051中,补丁编号是KB3057191。只要目标系统没有安装这个补丁,理论上都存在被利用的可能。

对渗透测试者来说,如何快速判定目标是否受影响是第一步。在拿到一个低权限Shell之后,我的习惯是先执行systeminfo命令,把补丁列表拉出来看看有没有KB3057191。没有这个补丁,基本就能确定可以利用MS15-051。

另外也可以通过网络连接行为做预判——NtApphelpCacheControl漏洞的利用代码依赖目标系统的线程栈布局,Windows 7和Server 2008 R2因为内核结构相似,利用稳定性最高。而Windows 8及以上版本需要额外的KASLR绕过手段,利用失败率会高一些。所以我个人遇到Windows 7 / Server 2008 R2这台组合,会第一时间想到MS15-051,而遇到Windows 10就会优先看其他提权点。

注意:MS15-051利用成功的标志是当前进程令牌被替换为SYSTEM令牌。如果执行利用程序后出现弹窗报错或者进程直接崩溃,十有八九是系统打了补丁或者架构判断错误。

1.3 为什么这个漏洞在实战中经久不衰

距离补丁发布已经过去多年,为什么我现在还会在一台Server 2008 R2上用到它?答案很简单:存量老系统远比想象中多。

很多内网的核心业务服务器,特别是老旧的ERP、MES、OA系统,因为业务连续性要求,常年不重启、不安装补丁。管理员不是不知道有漏洞,而是"不敢补",怕兼容性问题导致核心应用宕机。这就形成了一个巨大的攻击面——任何能打进内网的攻击者,碰到这类系统都等于白捡一个SYSTEM权限。

从攻击链的角度看,MS15-051往往处在"获得初始访问权"和"横向移动"之间。你拿到的WebShell权限可能连tasklist都执行不了,但只要编译好的二进制能运行,一步就能冲到SYSTEM。这给后续的哈希抓取、DCSync、横向渗透提供了完美跳板。

2. 实战环境与信息收集

2.1 模拟目标环境搭建

这次模拟的目标是一台Windows Server 2008 R2 SP1,内存分配2GB,双网卡配置(一个连接模拟外网,一个连接内网业务段)。

主机名不好带出,就用模拟项目代号X代替吧。这台机器上跑了两个常见服务:

  • IIS 7.5,承载一个老的ASP.NET后台管理系统
  • MSSQL 2008,业务数据库

初始攻击路径是SQL注入拿到WebShell,WebShell继承的权限是IIS应用程序池身份(默认为IIS APPPOOL\DefaultAppPool),属于低权限用户。模拟过程中,我用一个普通的本地账户user01来模拟这个低权限状态,因为WebShell下的操作受限于进程上下文,和普通用户视角基本一致。

2.2 提权前的信息收集清单

拿到低权限Shell之后,先别急着往漏洞利用上冲,信息收集做扎实了能少踩很多坑。我按顺序做了这几步:

第一步,确认系统版本和补丁情况。执行systeminfo,查看系统版本号、补丁列表、系统架构。

Host Name: X-SERVER OS Name: Microsoft Windows Server 2008 R2 Standard OS Version: 6.1.7601 Service Pack 1 Build 7601 System Type: x64-based PC Hotfix(s): 8 Hotfix(s) Installed.

注意这个输出,System Type: x64-based PC直接决定了编译利用代码时必须选x64版本。32位系统和64位系统的利用程序完全不同,混用只会得到"不是有效的Win32应用程序"之类的报错。

第二步,查看当前权限和用户组信息。

C:\>whoami x-server\user01 C:\>whoami /priv

这一步重点看有没有SeImpersonatePrivilege、SeAssignPrimaryTokenPrivilege这两个特权。如果当前用户有SeImpersonatePrivilege,那优先考虑土豆家族的提权(RoguePotato、PrintSpoofer这些);如果没有,再看内核漏洞利用。user01这台机器上这两个特权都没有,因为它是普通Users组成员,所以内核漏洞利用路线才是正解。

第三步,检查系统已安装补丁。

C:\>wmic qfe get HotFixID

输出确认没有KB3057191。其他热补丁也只有8个,全部还是2016年之前的,明显是长期没更新过的遗留系统。

第四步,确认架构与编译器执行环境。因为利用程序需要能在目标机器上直接运行,所以必须确认存在可执行文件运行的基条件:进程位数(64位)、是否存在DEP/ASLR强制策略。Server 2008 R2默认开启DEP和ASLR,所以选择利用代码时也要考虑这一点。

2.3 利用路线的决策过程

面对一个低权限会话,很多新手会直接掏出Metasploit,exploit/windows/local/ms15_051_client_copy_image一把梭。但实战里,Metasploit的Payload经常被目标机器上安装的各种安全软件拦掉,而且MSF生成的Payload体积大,上传痕迹明显。

我这次选择的路线是手动编译原生利用程序。理由有三:

  1. 目标系统是x64架构,原生64位利用程序执行成功率高
  2. 手动控制编译选项,可以规避部分特征检测
  3. 出问题时方便现场调整,不用依赖MSF的调试日志

这里多说一句,实战中一定要养成"多条腿走路"的习惯。MS15-051的利用代码已经集成到很多渗透框架中,但现场遇到杀软拦截、补丁状态变化、系统特殊配置时,手头有一份自己编译的二进制是最灵活的。

3. 利用代码的编译与投递

3.1 编译环境准备

MS15-051的利用代码在多个公开安全研究仓库都能找到,我不讨论具体来源,只讲编译实操。我是在一台Kali Linux虚拟机上用Mingw-w64交叉编译的,这样能直接产出Windows可执行文件。

先安装交叉编译工具链:

apt-get install gcc-mingw-w64-x86-64

然后下载利用代码源文件,核心就是一个C语言文件ms15-051.c。编译命令如下:

x86_64-w64-mingw32-gcc -o ms15-051.exe ms15-051.c -ladvapi32 -luser32

编译完成后用file命令确认输出类型:

file ms15-051.exe # PE32+ executable (GUI) x86-64, for MS Windows

看到PE32+和x86-64就说明编译成功了。

3.2 源码中的关键逻辑解析

利用代码的核心逻辑就是把NtApphelpCacheControl系统调用封装起来,通过它触发内核态的函数指针调用,最终在winlogon.exe进程中注入代码并复制SYSTEM令牌。整个过程中有个关键函数叫ms15_051_exec,它负责构造调用参数和处理返回值。

我编译时遇到过一个问题:直接使用官方示例中的Makefile会在链接阶段报错,提示缺少advapi32库。原因是部分旧版利用代码默认依赖RegOpenKeyEx等API,而MinGW的默认链接库不全。解决办法就是上面编译命令里显式加上-ladvapi32 -luser32。

3.3 文件的投递方式

编译好的ms15-051.exe是一个独立可执行文件,体积只有几十KB。投递到目标机器的方式有很多:

  • 通过已有WebShell上传(最常用)
  • 通过SMB共享复制(需要目标开放445)
  • 通过HTTP下载(目标能出网时)

我们这次是用WebShell的upload功能直接传上去的,保存路径选在C:\Windows\Temp\。这个目录的好处是Users组成员默认有写权限,而且不像根目录那样容易被监控。

投递完成后,第一步先验证文件是否完整,和执行权限是否正常:

C:\Windows\Temp>dir ms15-051.exe C:\Windows\Temp>ms15-051.exe

注意,这里有个经验技巧:先不带参数运行一次。大部分版本的MS15-051利用程序在无参数运行时只会打印Usage信息,不会真正执行漏洞利用。这样可以确认文件能正常加载、依赖的DLL没缺失。

3.4 执行利用程序

确认程序可用之后,加上-c参数执行漏洞利用。不同版本的利用代码参数不太一样,我用的这个版本语法是:

C:\Windows\Temp>ms15-051.exe -c cmd.exe

这条命令的意思是以SYSTEM权限启动一个交互式的cmd.exe。执行后,如果利用成功,会看到新的命令提示符弹出。我在这个模拟环境中执行的结果是:

[#] ms15-051 x64 [+] Found: 0x00000001800b8300 [+] Store: 0x00000001800b834c [+] Payload: 0x00000001800b8364 [+] Run: cmd.exe [+] Success: SYSTEM Shell

看到Success: SYSTEM Shell的输出,说明提权已经成功。在这个新起的cmd.exe里执行whoami验证:

C:\Windows\system32>whoami nt authority\system

到了这一步,权限提升的整个闭环就打通了。

注意:利用成功之后,原低权限进程还在,新进程是独立的SYSTEM上下文。这时候做后续操作,比如抓取哈希、导出票据,都要在新的SYSTEM Shell里做,不要在原来的低权限Shell里浪费时间。

4. 实操中的常见问题与排查技巧

4.1 利用程序无法执行,提示"不是有效的Win32应用程序"

这个报错在实战中出现频率最高。原因几乎都是位数不匹配——目标系统是x64,你上传了x86编译版本,或者反过来。

排查步骤:

  1. 执行echo %PROCESSOR_ARCHITECTURE%确认目标架构
  2. 重新检查编译命令,确保用的是x86_64-w64-mingw32-gcc
  3. 用file命令确认编译产物类型

有些情况下,目标机器是64位系统但进程被WoW64重定向,会有奇怪的执行表现。这时候直接在C:\Windows\System32下运行程序,不要放到SysWOW64目录里。

4.2 利用程序运行后无输出,进程直接消失

这个现象通常是DEP(数据执行保护)拦截导致的。MS15-051的利用代码会尝试在栈上执行Shellcode,如果系统开启了强制执行DEP的策略,程序可能在触发漏洞的瞬间被终止,看不到任何输出。

从实战角度说,这个问题不太好从应用层解决,因为DEP策略是系统级的。可行的替代方案:

  • 换用基于NtApphelpCacheControl的另一种利用实现,优先选择不依赖栈执行的那版
  • 检查系统是否开启了Exploit Protection或类似安全策略
  • 换其他提权漏洞去尝试

4.3 利用成功但反弹Shell不稳定,一操作就断

我在真实环境里遇到过用MS15-051直接反弹Shell后,执行几个命令就断开的情况。原因是利用程序把cmd.exe的父进程设置为系统关键进程,一旦那个进程被回收,子进程也跟着结束。

更稳妥的做法是分两步:

C:\Windows\Temp>ms15-051.exe -c "net user hacker P@ssw0rd /add"

在执行-c参数时,直接带上你要执行的单条命令。这样即使Shell不稳定,命令也已经执行完毕,结果不受影响。如果需要交互式操作,建议利用成功后再手动建立一个服务或者添加一个管理员用户,用远程登录的方式接管,不要一直依赖那个脆弱的进程。

4.4 目标打了补丁,但利用程序仍然能成功——可能吗?

有这个可能,但概率极低。MS15-051的补丁对这个漏洞做了多层修复,包括对调用权限的校验和对内核结构体的验证。**就算目标没有安装KB3057191,也可能因为后续其他安全更新顺带修复了这个漏洞。**所以在实战中,补丁列表里没有KB3057191,只能说明有利用可能性,不能保证百分之百成功。

我的习惯是多准备两三个提权方案作为备选。MS15-051不行就试试MS16-032、MS16-135,再不行就看服务配置、看注册表自启动项、看有没有明文凭证。提权本身就是个"试错+积累"的过程,手里方案越多,现场越从容。

4.5 常见问题速查表

现象可能原因处理方式
"不是有效的Win32应用程序"架构不匹配重新编译对应位数版本
程序无输出直接退出DEP拦截换利用实现,或换其他提权漏洞
"Access is denied"当前用户权限过低确认是以低权限用户执行的,而不是IIS降权失败
弹窗报错0xc0000005内核结构体偏移不匹配选择匹配系统版本源码,或换漏洞
Shell不稳定父进程被回收改用-c执行单条命令方式
杀软拦截文件特征被检测重新编译、混淆或换编码方式投递

5. 深度防御视角:如何有效缓解这类提权漏洞

5.1 治本:补丁管理与生命周期控制

说实话,MS15-051这种老漏洞,治本方案就一条:安装补丁,或者说让系统不再停留在过期版本。

具体操作建议是:

  1. 对存量Windows Server 2008/2008 R2机器,尽快制定升级或迁移计划,目标是迁移到新版本或云原生架构
  2. 在过渡期内,通过Windows Server Update Services(内部补丁服务器)下发KB3057191等关键安全更新,优先覆盖面向业务的核心服务器
  3. 建立"补丁例外审批"流程,任何申请不更新的服务器必须由业务负责人签字,同时附加额外的安全补偿措施

这听起来很"大道理",但实际渗透测试中,超过七成的成功提权都发生在长期未打补丁的系统上。补丁管理到位了,提权成功率直接砍半。

5.2 缓解:最小权限与应用程序白名单

即便补丁一时补不上,也有缓解措施能显著提高利用门槛。

第一道防线是最小权限原则。很多内网系统被攻击后,攻击者拿到的WebShell之所以能运行利用程序,根本原因在于应用池权限过高。IIS应用程序池默认使用ApplicationPoolIdentity这个低权限账户,但很多管理员为了方便,直接改成LocalSystem或者管理员账户,等于给攻击者开了金手指。正确做法是保持应用池默认身份,同时为应用程序池设置独立的虚拟账户,限制其访问范围。

第二道防线是AppLocker或者软件限制策略。在Server 2008 R2上,可以用AppLocker限制只允许特定目录下的可执行文件运行。编译好的ms15-051.exe通过WebShell上传后,默认落在C:\Windows\Temp,如果AppLocker规则里禁止Temp目录执行exe,利用程序连启动这关都过不了。

规则示例:可执行规则 - 路径 C:\Windows\Temp\* - 拒绝

5.3 检测:安全监控与日志审计

攻击者利用MS15-051的整个过程,会在系统里留下痕迹。从蓝队视角,紧盯这几个检测点能有效发现这类攻击:

进程创建事件。Sysmon或Windows安全日志(事件ID 4688)记录了新进程的创建。正常的cmd.exe从explorer.exe或服务宿主进程启动,如果看到cmd.exe或powershell.exe的父进程是winlogon.exe或services.exe,就要高度警惕。MS15-051利用成功启动的SYSTEM Shell,父进程链路往往不正常。

event_id: 4688 parent_process: winlogon.exe child_process: cmd.exe

系统调用审计。通过内核日志或第三方EDR,可以观察到异常的NtApphelpCacheControl系统调用。虽然普通日志系统一般不会记录到这个粒度,但主流EDR产品都有对应的内核行为检测能力。

文件落盘检测。在C:\Windows\Temp、C:\Users\Public等目录出现新的exe文件,配合短时间内出现SYSTEM权限的新进程,基本可以断定发生了类似的本地提权攻击。

5.4 加固:具体配置清单

结合这台Server 2008 R2的环境,给一份可以直接抄作业的加固清单:

  1. 使用WSUS内部补丁服务器,在测试通过后优先推送KB3057191和后续所有安全更新
  2. IIS应用程序池身份全部改为ApplicationPoolIdentity,严禁使用管理员或SYSTEM账号运行
  3. 在C:\Windows\Temp和用户临时目录启用AppLocker拒绝执行规则
  4. 启用Sysmon并配置进程创建、网络连接、文件创建事件的采集,集中接入日志平台
  5. 面向公网和核心业务区的Windows Server,强制开启防火墙,仅放行业务端口
  6. 将MSSQL和IIS服务账号纳入周期改密流程,避免账号复用和权限蔓延
  7. 对无法升级的老系统,在其前端部署Web应用防火墙和主机入侵检测探针,弥补系统自身防御缺口

5.5 从攻击者视角反推防御短板

每做完一次渗透测试,我都会把攻击路径捋一遍,看看哪些环节本来可以被拦截但没有拦住。这次MS15-051的提权过程暴露了三个防御短板:

短板一:补丁体系形同虚设。机器上有WSUS客户端配置,但多年没有收到有效更新。安全运维不是"装了WSUS就好",而要有定期的补丁合规检查机制。

短板二:WebShell落盘后没有即时告警。文件上传和进程创建几乎同时发生,如果EDR配置了"文件写入可执行目录后N秒内启动新进程"的行为关联检测,这次提权至少会多一道坎。

短板三:日志未集中管理。攻击者在目标机器上执行了多轮命令,攻击完成后日志还留存在本地。想要溯源时,管理员甚至不知道从哪台机器查起。

防御不是单点技术,而是体系。补丁、白名单、监控、日志,四者协同才能有效抵御这类攻击。

6. 本次实战的几点心得体会

实验做完了,补丁也打了,最后聊点实操层面的经验。

MS15-051这个漏洞利用,在Windows Server 2008 R2上的稳定性的确名不虚传。整个提权链路从信息收集到拿到SYSTEM Shell,熟练的话五分钟内可以走完。但稳定归稳定,它还是有明显的时代烙印——攻击代码的编译选项、执行方式、触发条件都需要和系统环境严格匹配,不像现在一些新的利用手法那样"傻瓜化"。所以碰到老系统,先确认版本和架构,再选利用代码,这个顺序不能乱。

另外我想特别提醒两点。第一,提权成功后不要得意忘形,内网渗透的目的是证明风险、帮助加固,不是搞破坏。拿到SYSTEM权限之后,我会立刻停止攻击行为,转而梳理该系统的暴露面和关联风险,把利用路径完完整整写进报告。第二,如果你是在做红队演练,务必要在方案里明确约定利用行为的边界,尤其是对老旧的业务系统,稍微激进的操作就可能导致不可逆的服务中断。

防御层面的体会更深。一台Server 2008 R2能在一台内部业务网络中存活十年不被升级,这本身就不是技术问题,而是管理问题。你给运维一千个加固建议,不如逼着业务方把升级排上日程。所以做安全的同行,如果发现内网还有这类老系统,第一优先级绝对不是天天盯着日志,而是推动业务方做资产治理和版本升级。技术问题可以慢慢解,业务系统一直躺在过期操作系统上,等于把家门钥匙挂在门口,只等有人来取。

最后分享个小技巧。当你在一台Windows Server 2008 R2上用MS15-051成功提权后,强烈建议顺手把当时的补丁列表、进程树、网络连接状态全部导出留存。这些数据既能用作攻击溯源的参考基线,也能帮你下次遇到同类型系统时更快判断它的补丁水位和利用成功概率。攻防经验的积累,就是从这一次次实操记录里沉淀出来的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询