-
-
Save p0w3rsh3ll/b3b599d239897c5fb36c21770c07b47a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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