WMIC WinRM LOLBin Execution by Provider Host

schema: v1
enabled: true
change_log:
  - {
      version: "1.0",
      uuid: "8affa5d2-cf69-4c2b-961a-5d5cb047e1de",
      date: "2023-04-18",
      impact: "major",
      message: "Initial version",
      author: "Till Studer",
    }

title: "WMIC/WinRM LOLBin Execution by Provider Host"
severity: medium
description: |

  The following report contains all activities related to the execution of any [LOLBin](https://lolbas-project.github.io/) using WMI or WinRM.
  It does this by searching for child-processes of the WMI and WinRM provider hosts `WmiPrvSE.exe` & `wsmprovhost.exe` where the child-process is either a LOLBin or a proxyBin like `cmd.exe` used as an in-between (e.g.: `cmd.exe /c "..."`).
  It also tries to enrich the output by identifying from whom and where the command came, the `AccountDisplayName` and `RemoteDeviceName` columns, by correlating successful logon events to the device before the execution time.

  An adversary may execute this attack by
    - `wmic process call create ${process_to_execute}`
    - `wmic /user:${user_name} /password:${password} /node:"${node}" process call create ${process_to_execute}`
    - `Invoke-WmiMethod -Path Win32_Process -Name create -ArgumentList ${process_to_execute}`
    - `winrm invoke Create wmicimv2/Win32_Process @{CommandLine="${process_to_execute}"} -r:http://target:5985`
    - `Invoke-Command -ComputerName $env:COMPUTERNAME -ScriptBlock ${command_to_execute}`
    - `evil-winrm -i ${destination_address} -u ${user_name} -p ${password}`

  This detection tries to catch the attack by
    1. Checking for LOLBin child-processes of `WmiPrvSE.exe` and `wsmprovhost.exe` also taking into consideration that there could be a in-between like `powershell.exe`
    2. Joining those results with previous logon events to the device
    3. Adding a short description about the LOLBin for each result

considerations: |

  If the `RemoteDeviceName` column is empty, this could be an indication that the WMIC execution was started locally, 
  but it could also mean that the start of the session (and its logon event) happened outside of the lookup window.

blindspots: |

  This detection only searches for LOLBin executions, as searching for all child-processes was causing too many false positives.

false_positive_rate: medium
false_positives: |

  WMIC and WinRM are common IT administration tools and will be used by sysadmins, developers and the like.
  Also, some of the LOLBins like `sc.exe`, `schtasks.exe` etc. will be used for legitimate development and administration purposes.

response_plan:
  triage: |

    - Open a case from the alert(s).
    - Determine **when** the action happened by checking the `Timestamp` field.
    - Determine **who** is the user responsible for the action through the `AccountDisplayName` field.
    - Determine **where** this action has taken place through the `DeviceName` field.
    - Determine **from where** this action has taken place through the `RemoteDeviceName` field.
    - Close case, describe why and add whitelisting suggestion if
        1. You observe previously "false positive" closed cases from the same detection on TheHive; either on the same machine or by the same user or both.
        2. ServiceNow shows any operation that might be related to the alert.
    - If none of the above applies, escalate.

  investigation: |

    - Determine **what** has been executed using the `ProcessCommandLine` field.
        1. Check the `ProcessCommandLine` field for suspicious usage of the LOLBin
        2. Check the device's timeline arround the time of the event for other unusual activity
        3. Check the device's timeline for any event tagged with `T1047: Windows Management Instrumentation` in the Additional information column.
    - If none of the above steps lead to a resolution that can be considered "false positive", respond!

  response: |

    - Determine **why** the operation was needed by the user by contacting them.
    - Contain the threat.
    - Expand the investigation to other machines if necessary.
    - Expand the detection if necessary.
    - Whitelist if needed.

references:
  - "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1047/T1047.md"
  - "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1021.006/T1021.006.md"
  - "https://lolbas-project.github.io/LOLbas/Binaries/Wmic/"
  - "https://lolbas-project.github.io/LOLbas/Scripts/Winrm/"
  - "https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmic"
  - "https://jsecurity101.medium.com/wmi-internals-part-1-41bb97e7f5eb"
  - "https://jsecurity101.medium.com/wmi-internals-part-2-522f3e97709a"
  - "https://posts.specterops.io/wmi-internals-part-3-38e5dad016be"
tags:
  - "mitre/attack/tactics/TA0002"
  - "mitre/attack/tactics/TA0008"
  - "mitre/attack/techniques/T1047"
  - "mitre/attack/techniques/T1021.006"
  - "mitre/attack/datasources/DS0009"
  - "mitre/attack/datasources/DS0017"
  - "mitre/attack/datasources/DS0028"
  - "mitre/defend/technique/D3-PSA"
  - "mitre/defend/technique/D3-FA"
  - "mitre/defend/technique/D3-RTSD"
  - "mitre/defend/doa/CreateProcess"
  - "mitre/defend/doa/ExecutableBinary"
  - "mitre/defend/doa/NetworkTraffic"
  - "mitre/defend/doa/IntranetAdministrativeNetworkTraffic"
  - "MDE/datasource/DeviceProcessEvents"
  - "MDE/datasource/IdentityLogonEvents"
  - "requester/redteam"
  - "platform/windows"

offensive_tests:
  - "38d65687-d62e-4f6b-acea-ca5def84ee7e"

detection_query:
  language: Kusto
  platform: MTP
  scheduling: "0 * * * *"
  query_variables:
    LOOKBACK-PERIOD: "61min"
    LOOKUP-WINDOW: "30min"
  output_columns:
    [
      Timestamp,
      AccountDisplayName,
      RemoteDeviceName,
      DeviceName,
      FileName,
      SHA1,
      Description,
      ProcessCommandLine,
      InitiatingProcessCommandLine,
      InitiatingProcessParentFileName,
    ]
  output_plugin: md
  query: |
    let providerHosts = dynamic (["WmiPrvSE.exe", "wsmprovhost.exe"]);
    let proxyBins = dynamic(["cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe", "wt.exe", "conhost.exe", "OpenConsole.exe", "pcwrun.exe", "scriptrunner.exe", "wlrmdr.exe"]);
    let LOLBas = externaldata(Name: string, Description: string, Author: string, Created: datetime, Commands: dynamic, FullPath: dynamic, Detection: dynamic, Resources: dynamic, url: string) [@'https://lolbas-project.github.io/api/LOLbas.json'] with (format='multijson');
    let LOLBins = LOLBas | where not(Name in~ (proxyBins)) | summarize make_set(Name);
    let lookupWindow = ${LOOKUP-WINDOW};
    let lookupBin = lookupWindow / 2;
    // Detection Logic
    DeviceProcessEvents
    | where Timestamp > ago(${LOOKBACK-PERIOD})
    //// filtering for the Provider Hosts and LOLBins or Proxies as child-processes
    | where (InitiatingProcessParentFileName =~ "svchost.exe" and InitiatingProcessFileName has_any (providerHosts) and FileName has_any (LOLBins))
         or (InitiatingProcessParentFileName has_any (providerHosts) and InitiatingProcessFileName has_any (proxyBins) and FileName has_any (LOLBins))
    //// joining the results with successful logon events around the time to know who initiated the connection
    | extend TimeKey = bin(Timestamp, lookupBin)
    | join kind=leftouter (
        IdentityLogonEvents
        | where ActionType == "LogonSuccess"
        | extend RemoteDeviceName = DeviceName
        | where isnotempty(TargetDeviceName)
        | where isnotempty(RemoteDeviceName)
        | project AccountDisplayName, RemoteDeviceName, TargetDeviceName,
                  ////// Reference: https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/join-timewindow
                  TimeKey = range(bin(Timestamp-lookupWindow, lookupBin),
                                  bin(Timestamp, lookupBin),
                                  lookupBin)
        | mv-expand TimeKey to typeof(datetime)
        | distinct AccountDisplayName, RemoteDeviceName, TargetDeviceName, TimeKey
        ) on $left.DeviceName == $right.TargetDeviceName, TimeKey
    //// joining the results with the LOLBas table to give the analyst additional context about the LOLBin
    | extend LowerFileName = tolower(FileName)
    | join kind=leftouter (
        LOLBas
        | extend LowerFileName = tolower(Name)
        | project LowerFileName, Description, url
        ) on LowerFileName
    // False Positive Allowlisting
    //
    // [REDACTED]
    //
    // Filtering and Sorting
    | sort by DeviceName, Timestamp desc
    | project-reorder Timestamp, AccountDisplayName, RemoteDeviceName, DeviceName, FileName, SHA1, Description, ProcessCommandLine, InitiatingProcessCommandLine, InitiatingProcessParentFileName


Relevant Note(s):