Created
July 22, 2018 12:34
-
-
Save mgreen27/441dac7d2034cb0f13844e4f82c2387b to your computer and use it in GitHub Desktop.
Parse CLSID COM objects from Registry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Invoke-CLSIDParser.ps1 parses COM CLSID entries from HKEY_LOCAL_MACHINE and HKEY_USERS registry hives. | |
Name: Invoke-CLSIDParser.ps1 | |
Version: 0.1 | |
Author: Matt Green (@mgreen27) | |
.DESCRIPTION | |
Researchers have recently written about several use cases for code execution and persistance utilising COM (Component Object Model) hijacking. | |
This script enables enumeration of all COM CLSID objects, enabling analysis and detection of these techniques. | |
This script can list SYSTEM, USER or a specific SID | |
.EXAMPLE | |
Invoke-CLSIDParser.ps1 | |
Lists all COM CLSID. | |
.EXAMPLE | |
Invoke-CLSIDParser.ps1 -System | |
Lists all SYSTEM COM CLSID. | |
.EXAMPLE | |
Invoke-CLSIDParser.ps1 -User | |
Lists all USER COM CLSID. | |
.EXAMPLE | |
Invoke-CLSIDParser.ps1 -Sid <SID> | |
Lists all COM CLSID associated to the User SID referenced. | |
.NOTES | |
References: | |
https://bohops.com/2018/06/28/abusing-com-registry-structure-clsid-localserver32-inprocserver32/ | |
https://www.youtube.com/watch?v=mkvGcf63_9k&feature=youtu.be | |
#> | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory = $False)][Switch]$System, | |
[Parameter(Mandatory = $False)][Switch]$User, | |
[Parameter(Mandatory = $False)][String]$Sid = $Null | |
) | |
$System = $PSBoundParameters.ContainsKey('System') | |
$User = $PSBoundParameters.ContainsKey('User') | |
If (!($System) -And !($User) -And !($Sid)) { | |
$System = $True | |
$User = $True | |
} | |
If ($System){ | |
Get-ChildItem -Path HKLM:\SOFTWARE\Classes\CLSID -Depth 1 | Where-Object {(Split-Path $_.name -Leaf) -eq "LocalServer32" -or (Split-Path $_.name -Leaf) -eq "InprocServer32"} | ForEach-Object { | |
# Setting up object for nicest output format | |
$Output = "" | Select Name, CLSID, Type, Value, Key | |
$Output.CLSID = Split-Path $_.PSParentPath -Leaf | |
$Output.Type = $_.PSChildName | |
$Output.Name = (Get-ItemProperty -Path HKLM:\SOFTWARE\Classes\CLSID\$($Output.CLSID) -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Value = (Get-ItemProperty -Path HKLM:\SOFTWARE\Classes\CLSID\$($Output.CLSID)\$($Output.Type) -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Key = $_.Name | |
$Output | |
} | |
} | |
If ($User){ | |
$Sids = (Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Profilelist").Name | ForEach-Object {Split-Path $_ -Leaf} | |
$Sids | Foreach-object {Get-ChildItem -Path REGISTRY::HKEY_USERS\$_\SOFTWARE\Classes\CLSID -Depth 1 -ErrorAction SilentlyContinue} | Where-Object {(Split-Path $_.name -Leaf) -eq "LocalServer32" -or (Split-Path $_.name -Leaf) -eq "InprocServer32"} | ForEach-Object { | |
# Setting up object for nicest output format | |
$Output = "" | Select Name, CLSID, Type, Value, Key | |
$Output.CLSID = Split-Path $_.PSParentPath -Leaf | |
$Output.Type = $_.PSChildName | |
$Output.Name = (Get-ItemProperty -Path REGISTRY::$(Split-Path $_.Name) -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Value = (Get-ItemProperty -Path REGISTRY::$_ -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Key = $_.Name | |
$Output | |
} | |
} | |
If ($Sid){ | |
Try{ | |
Get-ChildItem -Path REGISTRY::HKEY_USERS\$Sid\SOFTWARE\Classes\CLSID -Depth 1 -ErrorAction Stop | Where-Object {(Split-Path $_.name -Leaf) -eq "LocalServer32" -or (Split-Path $_.name -Leaf) -eq "InprocServer32"} | ForEach-Object { | |
# Setting up object for nicest output format | |
$Output = "" | Select Name, CLSID, Type, Value, Key | |
$Output.CLSID = Split-Path $_.PSParentPath -Leaf | |
$Output.Type = $_.PSChildName | |
$Output.Name = (Get-ItemProperty -Path REGISTRY::$(Split-Path $_.Name) -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Value = (Get-ItemProperty -Path REGISTRY::$_ -Name "(Default)" -ErrorAction SilentlyContinue).("(Default)") | |
$Output.Key = $_.Name | |
$Output | |
} | |
} | |
Catch{ | |
"Invoke-CLSIDParser Error: User SID does not exist. Please check format - e.g S-1-5-21-1866233333-1870853333-1579133333-1000" | |
} | |
} | |
[gc]::Collect() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment