Component Object Model

0x00 COM模型

      Component Object Model 译为组件对象模型,是一种独立于语言的一种二进制操作模型,攻击者通常使用组件对象模型(即COM)来执行本地代码。由于COM组件是语言独立的。所以,这些接口经常通过各种语言调用来进行代码执行,以及无文件下载以及持久性等诸多隐秘的操作,而被滥用。通常通过指定CLSID(标识GUID)或ProgID(程序标识符)来获得COM对象。

0x01 寻找可以被使用COM组件

      FireEye 曾在2019年写了两篇文章Hunting COM Objects,以及Hunting COM Objects (Part Two)来描述如何寻找未被公开的COM组件接口。并公布了采用powershell编写的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR
Get-ChildItem -Path HKCR:\CLSID -Name | Select -Skip 1 > clsids.txt
$Position = 1
$Filename = "win10-clsid-members.txt"
$inputFilename = "clsids.txt"
ForEach($CLSID in Get-Content $inputFilename) {
Write-Output "$($Position) - $($CLSID)"
Write-Output "------------------------" | Out-File $Filename -Append
Write-Output $($CLSID) | Out-File $Filename -Append
$handle = [activator]::CreateInstance([type]::GetTypeFromCLSID($CLSID))
$handle | Get-Member | Out-File $Filename -Append
$Position += 1
}

      因为COM对象的信息(CLSID,ProgID)被存储在注册表HKEY_CLASSES_ROOT\CLSID{clsid}中,所以通过遍历HKEY_CLASSES_ROOT\CLSID所有的CLSID就可以所有的COM对象。CLSID具有唯一性,用于表征不同的COM对象。通过几个不同的维度进行组合拼接而成。而ProgID也可以被用于检索COM。但是CLSID 和 ProgID 不具有一一对应性。InprocServer32指向的是存储COM的二级制文件,这些文件通常是DLL文件或者EXE文件。

1
2
3
4
* lnprocServer32
* TypeLib
* version
* progID

0x02 寻找COM组件进阶

      但是上述脚本只是通过CLSID遍历处于表面的COM组件,就是FireEye的第二篇文章所说,“However, this only scratches the surface of what is accessible through these COM objects, as each object may return other objects that cannot be directly created on their own.”

      通过FireEye给的寻找递归COM对象这一部分,作者滥用MMC20.Application COM对象中的ExecuteShellCommand方法来运行另外的程序。又根据文章的提示,翻看了原文,发现原文作者enigma0x3是通过Get-CimInstance Win32_DCOMApplication来检索用PowerShell的DCOM应用程序的完整列表.但是我始终不明白为什么要选择MMC20.Application COM这个对象。

      提出问题:能不能尽可能多的遍历COM的Method,从中寻找可能被滥用的Method.

      然后我在自己机器中复现了利用过程,如图1所示,并没有找到合适的Method去滥用。这也是FireEye那个脚本的局限性。
mark
接着,如图2所示,在$Instance.Document.ActiveView中可以发现可以被利用的Method。
mark

1
2
3
4
$Instance = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application"))
$Instance | gm
$Instance.Document.ActiveView | gm
$Instance.Document.ActiveView.ExecuteShellCommand("cmd.exe",$null,"/c calc","7")

      因为“ExecuteShellCommand”这个方法位于$Instance.Document.ActiveView中。所以上面的那个脚本并不可以获取这样的Method。还有就是文章中使用通过ProgID来获取Type,继而创建Instance。但是ProgID不具有对应性(部分COM可能没有ProgID),所以使用CLSID进行遍历。下面的脚本可以帮助获取CLSID和ProgID的对应关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR
Get-ChildItem -Path HKCR:\CLSID -Name | Select -Skip 1 > clsids2.txt
$Filename = "win10-ProgID-members.txt"
$inputFilename = "clsids2.txt"
$Position = 1
$count = 0
$MethodList = @()
ForEach($CLSID in Get-Content $inputFilename)
{
#Write-Output "$($Position) - $($CLSID)"
#$CLSID = "{00024502-0000-0000-C000-000000000046}"
$CHILD_REG = Get-ChildItem -Path ("HKCR:\CLSID" + "\" + $CLSID) -Name
if($CHILD_REG -match "ProgID")
{
$ProgID = (Get-ItemProperty ("HKCR:\CLSID" + "\" + $CLSID + '\' + "ProgID"))."(default)"
Write-Output "$($ProgID) - $($CLSID)"
if($ProgID.contains("MMC20.Application"))
{
Write-Output "$($ProgID) - $($CLSID)"
}
}
$Position += 1
}
Write-Output "OK"

      从复现寻找“ExecuteShellCommand”方法中思考,可以写一个脚本,通过递归遍历所有的Property,来获取可能被利用的Method,这些可能存在的Method可能存在以下的关键字。同时,还需要在CLSID和ProgID中选择一个作为遍历的维度或者说遍历的因素。因为CLSID的唯一性,选取CLSID作为遍历因素。以及,每一个COM组件底层的Property都很“深”。所以还需要限制嵌套的深度,不然程序就会一直处于递归状态。具体powershell代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function GetInstanceMethod($Instance)
{
$count = $count + 1
if(($Instance -eq $null) -or (($count -gt 3)))
{
$count = $count - 1
return 0
}
# Print All Methods Of Current Instance
if(($Instance | gm -MemberType "Method") -ne $null)
{
$Method = $Instance | gm -MemberType "Method"
GetSpecialMethod($Method)
}
$PropertyList = $Instance | gm -MemberType "Property"
if($PropertyList -eq $null)
{
$count = $count - 1
return 0
}
ForEach($EachProperty in $PropertyList)
{
$Name = $EachProperty."Name"
if($Name -eq "Application")
{
$Name = $EachProperty."Name"
}
$NextInstance = $Instance.$Name
if(($NextInstance -eq $null) -or ($NextInstance.GetType()."Name" -ne "__ComObject"))
{
if($NextInstance.GetType()."Name" -eq "ApplicationClass")
{
if(GetInstanceMethod($NextInstance) -eq 0)
{
break
}
}
else
{
continue
}
}
if(GetInstanceMethod($NextInstance) -eq 0)
{
break
}
}
$count = $count - 1
return 1
}

0x03 验证所寻找到的COM组件

      需要注意的是,部分COM滥用的Method已经被公开。这里只验证脚本的有效性。

0x01-3-01 {13709620-C279-11CE-A49E-444553540000}

      CLSID为{13709620-C279-11CE-A49E-444553540000}的COM,从他的InprocServer32值来判断应该属于shell32.dll的COM。可以看到包含有一个已经符合条件的Method——ShellExecute。如图4所示,显然这是可以使用的。
mark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{13709620-C279-11CE-A49E-444553540000} /////////////////////////////////////
TypeName: System.__ComObject#{866738b9-6cf2-4de8-8767-f794ebe74f4e}
Name MemberType Definition
---- ---------- ----------
FileRun Method void FileRun ()
TypeName: System.__ComObject#{866738b9-6cf2-4de8-8767-f794ebe74f4e}
Name MemberType Definition
---- ---------- ----------
IsServiceRunning Method Variant IsServiceRunning (string)
TypeName: System.__ComObject#{866738b9-6cf2-4de8-8767-f794ebe74f4e}
Name MemberType Definition
---- ---------- ----------
ShellExecute Method void ShellExecute (string, Variant, Variant, Variant...

0x01-3-02 {1A671297-FA74-4422-80FA-6C5D8CE4DE04}

      CLSID为{1A671297-FA74-4422-80FA-6C5D8CE4DE04},是AutoItX3的COM对象。如图5所示,是该COM所有的Method。
mark

1
2
3
4
5
6
7
8
9
10
11
12
13
{1A671297-FA74-4422-80FA-6C5D8CE4DE04} /////////////////////////
TypeName: System.__ComObject#{3d54c6b8-d283-40e0-8fab-c97f05947ee8}
Name MemberType Definition
---- ---------- ----------
Run Method int Run (string, string, int)
TypeName: System.__ComObject#{3d54c6b8-d283-40e0-8fab-c97f05947ee8}
Name MemberType Definition
---- ---------- ----------
RunAs Method int RunAs (string, string, string, int, string, string, int)

       如图9所示,在导出函数Run中,发现调用CreateProcess等创建进程的函数,继而判断其可以被作为CreateProcess的滥用Method。
mark

0x01-3-03 {F5078F35-C551-11D3-89B9-0000F81FE221}

      这是FireEye在第一篇文章中所提到的滥用COM进行无文件下载和执行的COM。其CLSID和文章中所给的一致,皆为{F5078F35-C551-11D3-89B9-0000F81FE221}。具体使用方法,参考Hunting COM Objects

1
2
3
4
5
6
7
8
9
------------------------
{F5078F35-C551-11D3-89B9-0000F81FE221}
TypeName: System.__ComObject#{ed8c108d-4349-11d2-91a4-00c04f7969e8}
Name MemberType Definition
---- ---------- ----------
send Method void send (Variant)

      而有关任务调度的COM使用方法也在FireEye的第一篇文章中,这里也不进行演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
------------------------
{0F87369F-A4E5-4CFC-BD3E-73E6154572DD}
TypeName: System.__ComObject#{2faba4c7-4da9-4013-9697-20cc3fd40f85}
Name MemberType Definition
---- ---------- ----------
GetRunningTasks Method IRunningTaskCollection GetRunningTasks (int)
TypeName: System.__ComObject#{2faba4c7-4da9-4013-9697-20cc3fd40f85}
Name MemberType Definition
---- ---------- ----------
NewTask Method ITaskDefinition NewTask (uint)

0x01-3-04 {49B2791A-B1AE-4C90-9B8E-E860BA07F889}

      而在FireEye第二篇文章所给的例子中,在MMC20.Application COM对象中滥用未被公开的ExecuteShellCommand方法运行可执行文件。在我的机器上,对应的CLSID 为{49B2791A-B1AE-4C90-9B8E-E860BA07F889},可以发现已经检索到了对应的ExecuteShellCommand方法。结果如图10所示
mark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
------------------------
{49B2791A-B1AE-4C90-9B8E-E860BA07F889}
TypeName: System.__ComObject#{6efc2da2-b38c-457e-9abb-ed2d189b8c38}
Name MemberType Definition
---- ---------- ----------
ExecuteScopeNodeMenuItem Method void ExecuteScopeNodeMenuItem (string, V...
TypeName: System.__ComObject#{6efc2da2-b38c-457e-9abb-ed2d189b8c38}
Name MemberType Definition
---- ---------- ----------
ExecuteSelectionMenuItem Method void ExecuteSelectionMenuItem (string)
TypeName: System.__ComObject#{6efc2da2-b38c-457e-9abb-ed2d189b8c38}
Name MemberType Definition
---- ---------- ----------
ExecuteShellCommand Method void ExecuteShellCommand (string, string, str...

0x04 小结

      本文最主要的部分在于如何编写一个脚本去检索所有可能的Method,FireEye也只是简单描述了一下,脚本所跑出的结果需要大家一一验证,并不保证每个方法都是可以被滥用的。关于寻找可以被滥用的Method,也有许多不同的方法和工具,第三部分讲解的例子也多是基于公开的被滥用的Method。根据关注点的不同,可以适当的更改Method的关键字从而检索不同类型的Method,网络相关?进程执行?宏执行?计划任务?都可以。可以利用的Method示例
Ref:
Hunting COM Objects
lateral-movement-using-the-mmc20-application-com-object
等等