Skip to content

Instantly share code, notes, and snippets.

@p0w3rsh3ll
Last active Nov 19, 2020
Embed
What would you like to do?
#Requires -Version 3.0
#region Score the identity
Function Get-ApplockerRuleUserOrGroupSidScore {
[CmdletBinding()]
[OutputType([int32])]
Param(
[Parameter(Mandatory)]
[Alias('UserOrGroupSid','SID')]
$InputObject
)
Begin {}
Process {
$InputObject |
ForEach-Object {
Switch -Regex ($_) {
'S-1-1-0' { # EveryOne
Write-Verbose -Message 'Applocker score: 50 ; Everyone'
50 ; break
}
'S-1-5-32-544' { # Administrators
Write-Verbose -Message 'Applocker score: 10 ; Administrators'
10 ; break
}
'S-1-5-32-545' { # Users
Write-Verbose -Message 'Applocker score: 10 ; Users'
10 ; break
}
# S-1-5-11 # Authenticated Users
# S-1-5-32-546 # Guests
# S-1-5-32-547 # Power Users
default {
Write-Verbose -Message 'Applocker score: Id is specific'
10
}
}
}
}
End {}
}
#endregion
#region Score the rule type
Function Get-ApplockerRuleTypeScore {
[CmdletBinding()]
[OutputType([int32])]
Param(
[Parameter(Mandatory)]
[string[]]$InputObject
)
Begin {}
Process {
$InputObject |
ForEach-Object {
Switch -Regex ($_) {
'^<FilePath(Rule|Condition)' { Write-Verbose -Message 'Applocker score: 100 ; Path type' ; 100 }
'^<FilePublisher(Rule|Condition)' { Write-Verbose -Message 'Applocker score: 50 ; Path publisher' ; 50}
'^<FileHash(Rule|Condition)' {Write-Verbose -Message 'Applocker score: 50 ; Path Hash' ; 50}
default {}
}
}
}
End {}
}
#endregion
#region Score the rule action
Function Get-ApplockerRuleActionScore {
[CmdletBinding()]
[OutputType([int32])]
Param(
[Parameter(Mandatory)]
[string[]]$InputObject
)
Begin {}
Process {
$InputObject |
ForEach-Object {
Switch -Regex ($_) {
'\sAction="Allow"' {
Write-Verbose -Message 'Applocker score: *1 ; Action is Allow'
1
}
'\sAction="Deny"' {
Write-Verbose -Message 'Applocker score: /10 ; Action is Deny'
0.1
}
default {}
}
}
}
End {}
}
#endregion
#region Score the rule conditions
Function Get-ApplockerRuleConditionsScore {
[CmdletBinding()]
[OutputType([int32])]
Param(
[Parameter(Mandatory)]
[string[]]$InputObject
)
Begin {}
Process {
$InputObject |
ForEach-Object {
($(
Switch -Regex ($_) {
'^<FilePath(Rule|Condition)' {
Write-Verbose -Message 'Applocker score: Path type'
# Depth: count the occurrence of '\'
$depth = 110 - (($_ -split '\\').Count)*10
Write-Verbose -Message "Depth score is $($depth)"
$depth
# Evaluate if there's a wildcard in the path
if ($_ -match '\\\*\\') {
50
}
Switch -Regex ($_) {
# Just a specific extension
# .exe, .com *.msi, msp mst ps1 cmd bat vbs js appx msix dll ocx
'\sPath="\*\.([eE][xX][eE]|[cC][oO][mM]|[mM][sS][iI]|[mM][sS][pP]|[mM][sS][tT]|[pP][sS]1|[cC][mM][dD]|[bB][aA][tT]|[vV][bB][sS]|[jJ][sS])"\s' {
Write-Verbose -Message "Path score: 500 (only a *.ext)"
500
}
# Path letter
'\sPath="(c|C):\\' {
Write-Verbose -Message "Path score: 100 (Path on C: drive)"
100
}
'\sPath="[abABd-zD-Z]:\\' {
Write-Verbose -Message "Path score: 100 (Path not on C: drive)"
50
}
# Extension: just a wildcard
'\sPath="\*\.\*"\s' { # *.*
Write-Verbose -Message "Path score: 1000 (only a *.*)"
1000 ; break
}
'\sPath="\*"\s' { # *
Write-Verbose -Message "Path score: 1000 (only a *)"
1000 ; break
}
default {}
}
}
'^<FilePublisher(Rule|Condition)' {
Write-Verbose -Message 'Applocker score: Path publisher'
Switch -Regex ($_) {
'PublisherName="\*"\sProductName="\*"\sBinaryName="\*"\>\<BinaryVersionRange\sLowSection="0\.0\.0\.0"\sHighSection="\*"' {
Write-Verbose -Message "Publisher score: 1000 (default Appx PublisherName=*)"
1000 ; break
}
'ProductName="\*"\sBinaryName="\*"\>\<BinaryVersionRange\sLowSection="\*"\sHighSection="\*"' {
Write-Verbose -Message "Publisher score: 500 (only a PublisherName)"
500 ; break
}
'\sBinaryName="\*"\>\<BinaryVersionRange\sLowSection="\*" HighSection="\*"' {
Write-Verbose -Message "Publisher score: 500 (PublisherName and ProductName)"
200 ; break
}
'BinaryVersionRange\sLowSection="\*"\sHighSection="\*"' {
Write-Verbose -Message "Publisher score: 100 (PublisherName and ProductName and FileName)"
100 ; break
}
default {
Write-Verbose -Message "Publisher score: 50 (default)"
50
}
}
}
'^<FileHash(Rule|Condition)' {
Write-Verbose -Message "Hash score: 50"
50
}
default {}
}
) | Measure-Object -Sum).Sum
}
}
End {}
}
#endregion
#region Convert to Object from Xml
Function Get-ApplockerRuleObjectFromXml {
[CmdletBinding()]
[OutputType([int32])]
Param(
[Parameter(Mandatory)]
[string[]]$InputObject
)
Begin {}
Process {
$InputObject |
ForEach-Object {
$o = $_
Switch -Regex ($_) {
'^<FilePathRule' {
try {
[Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel.FilePathRule]::FromXml($_)
} catch {
Write-Warning -Message "Failed to translate $($o) to Applocker FilePathRule because $($_.Exception.Message)"
}
break
}
'^<FilePublisherRule' {
try {
[Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel.FilePublisherRule]::FromXml($_)
} catch {
Write-Warning -Message "Failed to translate $($o) to Applocker FilePublisherRule because $($_.Exception.Message)"
}
break
}
'^<FileHashRule' {
try {
[Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel.FileHashRule]::FromXml($_)
} catch {
Write-Warning -Message "Failed to translate $($o) to Applocker FilePublisherRule because $($_.Exception.Message)"
}
break
}
default {
Write-Warning -Message 'Failed to transtale input into an Applocker rule'
}
}
}
}
End {}
}
#endregion
Function Get-ApplockerPolicyRuleScore {
<#
.SYNOPSIS
Score an Applocker policy rule
.DESCRIPTION
Score an Applocker policy rule
.PARAMETER Type
Parameter that indicates the RuleCollectionType to find a rule
.PARAMETER Rule
Dynamic parameter that indicates the Name of the rule to score
.EXAMPLE
Get-ApplockerPolicyRuleScore -Type Script -Rule '(Default Rule) All scripts'
Id Name Score XML
-- ---- ----- ---
ed97d0cb-15ff-430f-b82c-8d7832957725 (Default Rule) All scripts 1210 <FilePathRule Id
.EXAMPLE
$rule = Get-ApplockerPolicyRuleScore -Type Script -Rule '(Default Rule) All scripts' -Verbose
Write-Verbose -Message "Final score for '$($rule.Name)' is $($rule.Score)" -Verbose
$rule.Object
VERBOSE: Dealing with Rule Collection type: Script
VERBOSE: Dealing with Rule Name: (Default Rule) All scripts
VERBOSE: Applocker score: 100 ; Path type
VERBOSE: Applocker score: *1 ; Action is Allow
VERBOSE: Applocker score: 10 ; Administrators
VERBOSE: Applocker score: Path type
VERBOSE: Depth score is 100
VERBOSE: Path score: 1000 (only a *)
VERBOSE: Final score for '(Default Rule) All scripts' is 1210
PathConditions : {*}
PathExceptions : {}
PublisherExceptions : {}
HashExceptions : {}
Id : ed97d0cb-15ff-430f-b82c-8d7832957725
Name : (Default Rule) All scripts
Description : Allows members of the local Administrators group to run all scripts.
UserOrGroupSid : S-1-5-32-544
Action : Allow
#>
[CmdletBinding()]
Param(
[ValidateSet('Exe','Script','Msi','Appx','Dll')]
[Parameter(Mandatory)]
[String]$Type
)
DynamicParam {
$Dictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
#region helper function
Function New-ParameterAttributCollection {
[CmdletBinding(SupportsShouldProcess)]
Param(
[Switch]$Mandatory,
[Switch]$ValueFromPipeline,
[Switch]$ValueFromPipelineByPropertyName,
[String]$ParameterSetName,
[Parameter()]
[ValidateSet(
'Arguments','Count','Drive','EnumeratedArguments','Length','NotNull',
'NotNullOrEmpty','Pattern','Range','Script','Set','UserDrive'
)][string]$ValidateType,
[Parameter()]
$ValidationContent
)
Begin {}
Process {
if ($PSCmdlet.ShouldProcess('Create new Attribute')) {
$c = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$a = New-Object System.Management.Automation.ParameterAttribute
if ($Mandatory) {
$a.Mandatory = $true
}
if ($ValueFromPipeline) {
$a.ValueFromPipeline = $true
}
if ($ValueFromPipelineByPropertyName) {
$a.ValueFromPipelineByPropertyName=$true
}
if ($ParameterSetName) {
$a.ParameterSetName = $ParameterSetName
}
$c.Add($a)
if ($ValidateType -and $ValidationContent) {
try {
$c.Add((New-Object "System.Management.Automation.Validate$($ValidateType)Attribute"(
$ValidationContent
)))
} catch {
Throw $_
}
}
$c
}
}
End {}
}
#endregion
try {
$ApplockerPolicyXml = [xml](Get-AppLockerPolicy -Effective -Xml -ErrorAction Stop)
} catch {
Throw 'Failed to read the effective Applocker policy into XML'
}
#region param Rule
$Dictionary.Add(
'Rule',
(New-Object System.Management.Automation.RuntimeDefinedParameter(
'Rule',
[string],
(New-ParameterAttributCollection -Mandatory -ValidateType Set -ValidationContent (
$ApplockerPolicyXml.SelectNodes("/AppLockerPolicy/RuleCollection[@Type='$($PSBoundParameters['Type'])']").ChildNodes| ForEach-Object { $_.Name }
))
))
)
$Dictionary
}
Begin {}
Process {
Write-Verbose -Message "Dealing with Rule Collection type: $($PSBoundParameters['Type'])"
Write-Verbose -Message "Dealing with Rule Name: $($PSBoundParameters['Rule'])"
# Select node
$n = $ApplockerPolicyXml.SelectNodes("/AppLockerPolicy/RuleCollection[@Type='$($PSBoundParameters['Type'])']").ChildNodes |
Where-Object { $_.Name -eq "$($PSBoundParameters['Rule'])" }
try {
$TypeScore = Get-ApplockerRuleTypeScore -InputObject $n.OuterXml
$ActionSore = Get-ApplockerRuleActionScore -InputObject $n.OuterXml
$IdScore = Get-ApplockerRuleUserOrGroupSidScore -InputObject $n.OuterXml
$ConditionScore = Get-ApplockerRuleConditionsScore -InputObject $n.OuterXml
$r = [PSCustomObject]@{
Id = $n.Id
Name = $n.Name
Score = ($TypeScore+$IdScore+$ConditionScore)*$ActionSore
XML = $n.OuterXml
Object = Get-ApplockerRuleObjectFromXml -InputObject $n.OuterXml
}
Update-TypeData -TypeName 'Applocker.Rule.Score' -DefaultDisplayPropertySet 'Id','Name','Score','XML' -Force
$r.PSTypeNames.Insert(0,'Applocker.Rule.Score')
$r
} catch {
Throw "Something went wrong while scoring applocker rule: $($_.Exception.Message)"
}
}
End {}
} # endof Get-ApplockerPolicyRuleScore
Export-ModuleMember -Function 'Get-ApplockerPolicyRuleScore'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment