Skip to content

Instantly share code, notes, and snippets.

@mattifestation
Last active January 18, 2024 17:37
Show Gist options
  • Save mattifestation/11fb1bd37fff9a80803d7b39a43553ee to your computer and use it in GitHub Desktop.
Save mattifestation/11fb1bd37fff9a80803d7b39a43553ee to your computer and use it in GitHub Desktop.

Microsoft Defender for Endpoint does a great job of ensuring the integrity of the scripts they push and execute.

First, they ensure that the script to execute matches the expected file hash. Example:

powershell.exe -ExecutionPolicy AllSigned -NoProfile -NonInteractive -Command "& {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8;$scriptFileStream = [System.IO.File]::Open('C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1', [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileAccess]::Read);$calculatedHash = Get-FileHash 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1' -Algorithm SHA256;if (!($calculatedHash.Hash -eq 'd871ab44a81b93cdf3c7e235c246ea8b4bf65d9141d7797270c15dd6bbdb2803')) { exit 323;}; . 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1' }"

Cleaned up PowerShell:

& {
    $OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8
    
    $scriptFileStream = [System.IO.File]::Open('C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1', [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileAccess]::Read)
    
    $calculatedHash = Get-FileHash 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1' -Algorithm SHA256
    
    if (!($calculatedHash.Hash -eq 'd871ab44a81b93cdf3c7e235c246ea8b4bf65d9141d7797270c15dd6bbdb2803')) {
        exit 323; # ERROR_DATA_CHECKSUM_ERROR
    }
    
    . 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\7910.6064030.0.6552433-3a7d9fb541a03fc183f740777b7bb1aa20a20efd\046a3caf-d9ec-4da6-a32a-fb148992596a.ps1'
}

C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection is also only accessible by SYSTEM.

Also, each script is signed with a Microsoft Windows Defender Advanced Threat Protection certificate which makes validation and enforcement with application control so much easier!

> Get-AuthenticodeSignature 046a3caf-d9ec-4da6-a32a-fb148992596a.ps1 | Select-Object -ExpandProperty SignerCertificate | Format-List *


EnhancedKeyUsageList : {Code Signing (1.3.6.1.5.5.7.3.3), 1.3.6.1.4.1.311.76.47.1}
DnsNameList          : {Microsoft Windows Defender Advanced Threat Protection}
SendAsTrustedIssuer  : False
Archived             : False
Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
                       System.Security.Cryptography.Oid...}
FriendlyName         :
IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter             : 1/27/2022 3:50:22 PM
NotBefore            : 1/28/2021 3:50:22 PM
HasPrivateKey        : False
PrivateKey           :
PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey
RawData              : {48, 130, 6, 21...}
SerialNumber         : 3300000205FC5081544065EFB0000000000205
SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm   : System.Security.Cryptography.Oid
Thumbprint           : 1FF064E13C25D7B5C83549F1562DD64181C4443A
Version              : 3
Handle               : 3221047460208
Issuer               : CN=Microsoft Code Signing PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Subject              : CN=Microsoft Windows Defender Advanced Threat Protection, O=Microsoft Corporation, L=Redmond, S=Washington, C=US

Here is a link to 046a3caf-d9ec-4da6-a32a-fb148992596a.ps1 in VT: https://www.virustotal.com/gui/file/d871ab44a81b93cdf3c7e235c246ea8b4bf65d9141d7797270c15dd6bbdb2803/details

And because the scripts are signed, I can allow all of them to execute in a robust fashion with WDAC. This is the code integrity policy that I merged into my master policy that allows these scripts to execute:

<?xml version="1.0" encoding="utf-8"?>
<SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy">
  <VersionEx>10.0.0.0</VersionEx>
  <PlatformID>{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}</PlatformID>
  <Rules />
  <!--EKUS-->
  <EKUs />
  <!--File Rules-->
  <FileRules />
  <!--Signers-->
  <Signers>
    <Signer ID="ID_SIGNER_DEFENDER_FOR_ENDPOINT" Name="Microsoft Code Signing PCA 2011">
      <CertRoot Type="TBS" Value="F6F717A43AD9ABDDC8CEFDDE1C505462535E7D1307E630F9544A2D14FE8BF26E" />
      <CertPublisher Value="Microsoft Windows Defender Advanced Threat Protection" />
    </Signer>
  </Signers>
  <!--Driver Signing Scenarios-->
  <SigningScenarios>
    <SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS_1" FriendlyName="Auto generated policy on 10-27-2021">
      <ProductSigners />
    </SigningScenario>
    <SigningScenario Value="12" ID="ID_SIGNINGSCENARIO_WINDOWS" FriendlyName="Auto generated policy on 10-27-2021">
      <ProductSigners>
        <AllowedSigners>
          <AllowedSigner SignerId="ID_SIGNER_DEFENDER_FOR_ENDPOINT" />
        </AllowedSigners>
      </ProductSigners>
    </SigningScenario>
  </SigningScenarios>
  <UpdatePolicySigners />
  <CiSigners>
    <CiSigner SignerId="ID_SIGNER_DEFENDER_FOR_ENDPOINT" />
  </CiSigners>
  <HvciOptions>0</HvciOptions>
  <PolicyTypeID>{A244370E-44C9-4C06-B551-F6016E563076}</PolicyTypeID>
</SiPolicy>
@pl4nty
Copy link

pl4nty commented Oct 11, 2022

Do you happen to know if the EKU 1.3.6.1.4.1.311.76.47.1 is specific to MDE? I haven't found any other instances of it (or 010A2B0601040182374C2F01) online or in my environments

@mattifestation
Copy link
Author

@pl4nty I can't be absolutely certain but I think it's a safe bet to assume that it is specific to MDE. I too haven't encountered that EKU anywhere besides MDE script code.

@kimoppalfens
Copy link

Sounds nice, in theory.
Have you verified whether these scripts actually execute after doing this?
The script call appears to use dotsourcing and method executions that do not work on a WDAC enforced machine.

It took me a while to figure out, but enabling PowerShell transcript logging confirms the commands actually fail to execute.
Be interesting to see whether you are seeing different behaviour.

Kim

@pl4nty
Copy link

pl4nty commented Aug 3, 2023

I left that environment around 9 months ago, but PowerShell transcript logs and MDE queries were showing successful executions at the time and no failures on Win11 22H2. Dotsourcing should also work if the imported scripts are allowed. Which method executions were failing?

@kimoppalfens
Copy link

Here's a sample from my 22h2. Pretty sure we are running into this issue:
https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode-and-the-dot-source-operator/

It working for you has me puzzled. I used a path rule to make these scripts trusted in the policy, but that shouldn't matter.
Guess I'll try your policy and see whether there's a difference in behavior.


Windows PowerShell transcript start
Start time: 20230803095148
Username: LABO\SYSTEM
RunAs User: LABO\SYSTEM
Configuration Name:
Machine: BE-HER1-PC1122 (Microsoft Windows NT 10.0.22621.0)
Host Application: C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy AllSigned -NoProfile -NonInteractive -Command & {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8;$scriptFileStream = [System.IO.File]::Open('C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0bc45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1', [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read);$calculatedHash = Get-FileHash 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0bc45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1' -Algorithm SHA256;if (!($calculatedHash.Hash -eq '6183ae1127346ebacb45cb9a5fbd94a260915343ae376ed25c63503b2ba77fae')) { exit 323;}; . 'C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0bc45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1' }
Process ID: 65052
PSVersion: 5.1.22621.1778
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.22621.1778
BuildVersion: 10.0.22621.1778
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1


PS>CommandInvocation(Out-String): "Out-String"

ParameterBinding(Out-String): name="InputObject"; value="Cannot dot-source this command because it was defined in a different language mode. To invoke this command without importing its contents, omit the '.' operator."
C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0bc
45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1 : Cannot dot-source this command because it was def
ined in a different language mode. To invoke this command without importing its contents, omit the '.' operator.
At line:1 char:754

  • ... exit 323;}; . 'C:\ProgramData\Microsoft\Windows Defender Advanced Thr ...
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (:) [05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1], NotSupportedException
    • FullyQualifiedErrorId : DotSourceNotSupported,05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1
      C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0bc
      45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1 : Cannot dot-source this command because it was def
      ined in a different language mode. To invoke this command without importing its contents, omit the '.' operator.
      At line:1 char:754
  • ... exit 323;}; . 'C:\ProgramData\Microsoft\Windows Defender Advanced Thr ...
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (:) [05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1], NotSupportedException
    • FullyQualifiedErrorId : DotSourceNotSupported,05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1
      C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\DataCollection\8699.9330757.0.9330757-b210af0a6f0b
      c45baa07a45fffe247e8e825f5cc\05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1 : Cannot dot-source this command because it was d
      efined in a different language mode. To invoke this command without importing its contents, omit the '.' operator.
      At line:1 char:754
  • ... exit 323;}; . 'C:\ProgramData\Microsoft\Windows Defender Advanced Thr ...
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (:) [05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1], NotSupportedException
    • FullyQualifiedErrorId : DotSourceNotSupported,05f2c576-9ed5-41eb-9b1e-1b653eebfdff.ps1

PS>$global:?
True

@pl4nty
Copy link

pl4nty commented Aug 3, 2023

Interesting, I've been able to replicate the issue with psexec and my old policy. Its SYSTEM PowerShell session executes in CLM, so dotsourcing fails like Example 2 in the article you linked. I might not have spotted the issue during deployment due to the lack of event logs. But I made extensive use of MDE hunting, and didn't notice any missing data.

@kimoppalfens
Copy link

kimoppalfens commented Aug 3, 2023

Yeah, we've missed it for the longest time too. We stumbled upon it when investigating another issue. When we enabled transcript logging we found our issue, but immediately show a bunch of MDE scripts blocked too. We've reported it, but the general feeling appeared to be that it doesn't really hurt functionality. I've tried using advanced hunting to show some of the data they appear to collect, but even on a system without wdac I can't see that data. It's unclear to me what they're collecting it for and where they store it.

Thanks for the swift responses, was wondering whether you'd found some magic.

@pl4nty
Copy link

pl4nty commented Nov 6, 2023

Stumbled across this in the MDE settings management docs, wonder if it's related

Security settings management doesn't work for a device that has PowerShell LanguageMode configured with ConstrainedLanguage mode enabled

https://learn.microsoft.com/en-us/mem/intune/protect/mde-security-integration?pivots=mdssc-preview#powershell-restrict-mode

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment