Skip to content

Octoberfest7/DSCourier_BOF

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DSCourier BOF

This is a BOF implementation of Dylan Davis and Matthew Schramm's DSCourier project. It uses WinGet's COM interface to execute arbitrary powershell code in a Microsoft signed and trusted process. Their full research blog can be found here.

Unlike most projects I release, this is NOT an operationally ready tool but rather more of a POC. I chose not to further pursue this after discovering a number of issues that stand in the way of this being a readily-deployable BOF. The code was almost entirely clanked. Several issues remain unresolved and are discussed below

Usage

Put your arbitrary powershell code in the dist/rev.yml file. By default it contains a simple powershell reverse shell from the original repo. If you choose to use that, make sure to replace the IP within the existing example with your desired IP.

Example using the powershell reverse shell:

alt text

alt text

How it Works / Limitations

In no particular order, here are some issues/limitations around this tool.

  1. For the COM calls to succeed, the Microsoft.Management.Configuration.winmd file must be present in the same directory as the executable making the COM calls. This poses an immediate problem when running a Beacon from a hollowed-out system32 process for example, where normal users don't have write permissions. To get around this, the file is instead dropped to %APPDATA%\temp and the WinTypes!RoGetMetaDataFile function which retrieves the winmd filepath is hooked with an inline hook so that we can provide the temp path location. This allows the winmd file to be read / the COM calls to succeed, but means there are VirtualProtect calls made and overwriting of DLL memory which creates IOCs.
  2. Following #1, the winmd file gets locked on disk after running the BOF until the Beacon process exits. I played with this a little to try and resolve, including adding the Self-delection functionality that is well known at this point, but the file remained locked on disk. May be able to engineer around this/resolve, but that is for someone else to chase.
  3. As mentioned in the original research, because this uses the pwsh resource within WinGet, a conhost.exe process is spawned under ConfigurationRemotingServer.exe. Claude suggested it would be possible to load a custom binary module as a resource instead of invoking pwsh, which should solve the conhost problem, but this requires dropping additional files to disk and I was unable to get it working. It may not be possible. If it were, it opens the door to dropping a generic .NET dll to disk which could be loaded by ConfigurationRemotingServer.exe and execute passed shellcode/params/etc.
  4. This BOF implements the Async versions of the required COM interfaces. Using the Sync versions results in Beacon hanging / not calling back in until the ConfigurationRemotingServer.exe process is done; with the simple reverse shell example, this would mean that Beacon would not check in again until the shell is killed. Switching to the Async interfaces prevents this issue, but intoduces some timing issues. There is a hardcoded 3 second sleep that has worked in practice to delay between specific calls, but this is of course not the proper way to implement this.
  5. COM interface definitions were obtained by downloading the winget-cli .msixbundle from Github, extracting, extracting the .msix, and finding the .winmd file. winmdidl.exe was then used to extract the IDL files. midlrt.exe was then used to convert the IDL into headers/.c files, which was then parsed down by Claude to only contain the required definitions. It's still a mess of code. This Microsoft link will probably be helpful in understanding this process better
  6. The code is generally kind of a mess because this didn't make it out of POC stage.
  7. The winget configure --enable command must be ran at least once on a target machine before the BOF will succeed. I tracked the reason for this down to the fact that the DotNet directory containing ConfigurationremotingServer.exe doesn't even exist until the command has been ran / the binary downloaded. These files reside in C:\Program files\WindowsApps... and are thus not writable by a low priv user, so we can't even drop these files to disk ourselves with the BOF and have things work.
  8. I looked into it, and as far as I can tell these are NOT DCOM interfaces, just COM. So this isn't a viable primitive for lateral movement to other machines.
  9. Due to #7, this doesn't make for a good/reliable initial access method IMO. If you land on a machine with WinGet disabled (see original blog post), or the configure --enable command hasn't been ran, you are hard stopped. For post-ex purposes, it might have value, but you are somewhat constrained in that it's a fixed process that will spawn / run your code, and it being pwsh there will be AMSI at play.

Compilation

This tool was written without the use of normal BOF API declarations (e.g. a bofdefs.h file). As outlined in this blog post by Matt Ehrnschwender, it's possible to use objcopy to patch the proper symbols of format DLL$API into the BOF post-compilation.

I have written a tool called BOFPatcher that automates this process. This allows users to write BOFs as normal C without worrying about cumbersome API declarations:

alt text

This tool is available to those who purchase my BOF Development and Tradecraft course.

While the BOFPatcher tool is not included in this repo, the Makefile for this tool calls objcopy, passing an imports_dscourier64.txt file containing the proper symbol replacements which then renders the BOF usable.

Credits

  1. Great work from Dylan and Matt. Hope to see more from them!
  2. Claude for clanking most of this out

About

BOF POC of the DSCourier project / invoking WinGet via COM

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors