WMI
WMIC (Windows 管理仪表) 是一项 Windows 管理功能,它为本地和远程访问 Windows 系统组件提供统一的环境。系统管理员可以创建 VBScript 或 PowerShell 脚本来管理本地和远程的 Windows 主机。WMI 也是横向移动和远程代码执行的原生方式,它需要本地管理员权限。
wmi.WMI 基础
在 WMI 中,命名空间是类的逻辑容器,它允许以层次结构组织类,每个命名空间可以包含类、类的实例或其他命名空间。WMI 使用命名空间来避免类之间的命名冲突。WMI中的根命名空间是 Root,Root下有几个标准的命名空间,如 CIMV2、Security、StandardCimv2 等。
WMI 中的类是定义一种托管对象类型的架构,类似于数据库中的表。 每个类都有一个属性列表,这些属性定义了类实例的数据字段,以及可以在类实例上执行的操作的方法。例如,在 Root\CIMV2 命名空间中,有一个名为 Win32_Process 的类,它代表一个运行在 Windows 系统上的进程。 Win32_Process 类具有 Name 和 ProcessID 等属性,提供有关每个进程的信息,以及 Create 和 Terminate 等可用于控制进程的方法。
通常,要执行 WMI 操作,我们需要指定包含要使用的类的命名空间以及类的名称。 例如,要创建一个新进程,我们可以使用 Root\CIMV2 命名空间中的 Win32_Process 类,并调用该类的 Create 方法。接下来,我们通过 PowerShell 命令熟悉一下 WMI。
列举所有命名空间,需要提升特权:
Get-WmiObject -Class "__Namespace" -Namespace "Root" -List -Recurse 2> $null | select __Namespace | sort __Namespace
列举 root\cimv2 中的命名空间:
Get-WmiObject -Class "__Namespace" -Namespace "root\cimv2" -List -Recurse 2> $null | select __Namespace | sort __Namespace
罗列有关 Win32_process 的类,如果不指定命名空间,默认是 root\cimv2。
Get-WmiObject -Recurse -List -class win32_process*
WMI 还支持基于 SQL 语法的查询,我们可以用如下查询做到相同的事情:
Get-WmiObject -Query 'Select * From Meta_Class WHERE __Class Like "win32_process%"'
调用 Win32_process 类以查看进程的相关信息
Get-WmiObject -Class win32_process | select Name,ProcessId,CommandLine
调用 Win32_process 类的 Create 方法来创建新的进程:
$process=[wmiclass]"win32_process"
$process.Create("calc.exe",$null,$null)
wmic.exe
无论是枚举信息还是执行任务,wmic.exe 都很得心应手,wmic 对类添加了别名,例如 Win32_process 在 wmic 里可以通过 process 进行访问。不提供任何选项,直接运行 wmi.exe 会进入交互式控制航,可以查看所有类。
我们可以通过如下的原生命令给远程主机创建新的进程:
wmic /node:<主机> /user:<用户名> /password:<密码> process call create "<命令>"
然后发现在目标主机上该进程确实存在了。
将要启动的进程换为载荷,便能实现横向移动了。
C2
remote-exec wmi
我们会发现没有 jump wmi 的选项,只有 remote-exec wmi。remote-exec 方法使用的其实就是 process call create 来执行任意命令。
因此,我们可以先上传载荷文件到目标主机上,再使用 remote-exec 来执行。
第三方工具
Impacket
Impacket 中的 wmiexec 同样可用于横向移动,不过返回的是半交互式 Shell。
因为 wmiexec 会将输出写入文件,因此会带来 IoC,静默命令以及取消输出可以改善这一问题。
XiaoLi 修改后的 wmiexec 脚本 (https://github.com/XiaoliChan/wmiexec-RegOut) 通过注册表读写输出,也是一个不错的方法。