Windows.Forensics.UEFI.BootApplication

This artifact parses Windows MeasuredBoot TCGLogs to extract PathName of EV_EFI_Boot_Services_Application events, which can assist detection of potential ESP based persistance.

\EFI\Microsoft\Boot\bootmgfw.efi - the Windows boot manager on systems with UEFI firmware.

The artifact leverages Velociraptor tools to deploy and execute a powershell module to parse TCGLogs on disk and memory.

NOTE:

  • Recommended to host TCGLogTools and TCGLogToolsExecution locally to mitigate github connection limits.
  • AllParsedTCGLog can be large and is best suited to triage.
  • Thank you to mattifestation for TCGTools!

name: Windows.Forensics.UEFI.BootApplication
author: "Matt Green - @mgreen27"
description: |
    This artifact parses Windows MeasuredBoot TCGLogs to extract PathName of 
    EV_EFI_Boot_Services_Application events, which can assist detection of 
    potential ESP based persistance.  
    
    \EFI\Microsoft\Boot\bootmgfw.efi - the Windows boot manager on systems with 
    UEFI firmware.

    
    The artifact leverages Velociraptor tools to deploy and execute a powershell 
    module to parse TCGLogs on disk and memory.
    
    NOTE:
    
    - Recommended to host TCGLogTools and TCGLogToolsExecution locally to mitigate github connection limits.
    - AllParsedTCGLog can be large and is best suited to triage.
    - Thank you to mattifestation for TCGTools!

reference:
  - https://www.microsoft.com/en-us/security/blog/2023/04/11/guidance-for-investigating-attacks-using-cve-2022-21894-the-blacklotus-campaign/
  
type: CLIENT
resources:
  timeout: 6000

tools:
    - name: TCGLogTools
      url: https://raw.githubusercontent.com/mattifestation/TCGLogTools/master/TCGLogTools.psm1
    - name: TCGLogToolsExecution
      url: https://gist.githubusercontent.com/mgreen27/d7bd2480069f714f31296d5f38fe7f0c/raw/708002dd858a38e8e8885e926c3016f80057a7d4/Run-TCGLogTools.ps1
      

parameters:
  - name: TCGLogLocationGlob
    default: c:\Windows\Logs\MeasuredBoot\*.log
  - name: AllParsedTCGLog
    type: bool
    description: Return all parsed TCGLog data. This can be very large so best used as triage only!


precondition:
      SELECT OS From info() where OS = 'windows'

sources:
  - query: |
      -- Get the path to the TCGLogTools tool
      LET module <= SELECT OSPath
            FROM Artifact.Generic.Utils.FetchBinary(
                ToolName="TCGLogTools",
                IsExecutable=FALSE
                )
      LET script <= SELECT OSPath
            FROM Artifact.Generic.Utils.FetchBinary(
                ToolName="TCGLogToolsExecution",
                IsExecutable=FALSE
                )
      
      -- Run the tool and relay back the output
      LET data = SELECT *    
        FROM execve(argv=['powershell','-ExecutionPolicy','Unrestricted','-NoProfile','-File',script.OSPath[0]],
            env=dict(
                `TCGLogTools` = str(str=module.OSPath[0]),
                `TCGLogLocation` = TCGLogLocationGlob ),
            length=100000000)
        WHERE Stdout
        
      LET file_info(path) = SELECT OSPath,Size,Mtime,Atime,Ctime,Btime 
        FROM stat(filename=path)
      
      LET results <= SELECT *,
            if(condition= LogPath,
                then= file_info(path=LogPath)[0],
                else= Null ) as FileInfo
        FROM parse_json_array(data=data.Stdout)
        
      -- quick dynamic function to clean up multi entries for PathName
      LET bootapplication(data) = SELECT PathName FROM data.Event.DevicePath.DeviceInfo 
        WHERE PathName
        GROUP BY lowcase(string=PathName)
        
      LET clean_bootapplication(data) = SELECT _value as PathName FROM foreach(row=data) GROUP BY _value
        
      LET boot_application = SELECT 
            if(condition=FileInfo,
                then= FileInfo.OSPath,
                else= 'Current InMemory' ) as OSPath,
            FileInfo.Size as Size,
            FileInfo.Mtime as Mtime,
            FileInfo.Ctime as Ctime,
            FileInfo.Btime as Btime,
            clean_bootapplication(data=array(a=Events.PCR4.Event.DevicePath.DeviceInfo.PathName)).PathName as BootApplication
        FROM results
        
      -- cleaning up results and ensuring single string if not multiple BootApplication entries
      SELECT *,
        if(condition=len(list=BootApplication)=1,
            then= BootApplication[0],
            else= BootApplication ) as BootApplication
      FROM boot_application

    notebook:
      - type: vql
        name: BootApplication count
        template: |
          /*
          ## BootApplication by count
          */
          SELECT 
                BootApplication,
                min(item=Btime) as EarliestBtime,
                count() as TotalBoots
          FROM source(artifact="Exchange.Windows.Forensics.UEFI.BootApplication")
          GROUP BY lowcase(string=BootApplication)
          
          /*
          ##  All BootApplication
          */
          SELECT BootApplication, OSPath, Size, Mtime, Ctime, Btime
          FROM source(artifact="Exchange.Windows.Forensics.UEFI.BootApplication")
          
  - name: AllParsed
    queries:
      - |
        SELECT FileInfo,Header,Events
        FROM if(condition=AllParsedTCGLog, 
            then= results )