itm4n / privesccheck Goto Github PK
View Code? Open in Web Editor NEWPrivilege Escalation Enumeration Script for Windows
License: BSD 3-Clause "New" or "Revised" License
Privilege Escalation Enumeration Script for Windows
License: BSD 3-Clause "New" or "Revised" License
Hi,
It would interesting if PrivescCheck was able to detect whether ASR is configured or not, and if there is a misconfiguration among the ASR rules (cf. win10-asr-get.ps1).
On a default Windows 10 install:
+------+------------------------------------------------+------+
| TEST | APPS > Modifiable Apps | VULN |
+------+------------------------------------------------+------+
| DESC | List non-default and third-party applications and |
| | report the ones that can be modified by the current |
| | user. |
+------+-------------------------------------------------------+
[*] Found 1 result(s).
ModifiablePath : C:\Program Files\UNP\Logs
IdentityReference : Everyone
Permissions : {WriteOwner, Delete, WriteAttributes, Synchronize...}
This should probably be ignored by default.
I got some of the following errors on a Microsoft Windows Server 2019 Datacenter.
Specified cast is not valid.
At line:1077 char:17
+ if (($ServiceItem.Type -band $TypeMask) -gt 0) {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], InvalidCastException
+ FullyQualifiedErrorId : System.InvalidCastException
This happens during multiple checks:
Running as admin doesn't change this. I tried adding -Verbose
but no interesting information was shown to narrow down the issue.
Does this make sense for you? I probably have access to this particular system for only one day. So if this isn't enough information, we may close this until it is clearly reproducible. But feel free to tell me which information might be helpful.
Great script! We use this for OSCP. Would suggest you add the checks for the JuicyPotato COM technique?
During the run of Invoke-UdpEndpointsCheck
the following error occurs. The message is German but it means "Cannot find process with ID xyz".
+------+------------------------------------------------+------+
| TEST | NETWORK > UDP Endpoints | INFO |
+------+------------------------------------------------+------+
| DESC | List all UDP ports that are in a LISTEN state. For |
| | each one, the corresponding process is also returned. |
| | DNS is filtered out to minimize the output. |
+------+-------------------------------------------------------+
Get-Process : Es kann kein Prozess mit der Prozess-ID 55184 gefunden werden.
In Zeile:514 Zeichen:86
+ ... oteProperty" -Name "Name" -Value (Get-Process -PID $ProcessId).Proces ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (55184:Int32) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenId,Microsoft.PowerShell.Commands.GetProcessCommand
So I assume either we have no privileges looking up the process, or the processes are so short living that they are gone when the process info is retrieved. However, listing TCP services works and it is always reproducible on this particular machine, so I'm a bit confused. Maybe this exception can be handled and the process name can be left empty in this case?
Hi Clement,
I was wondering if, in the extended mode, it may be relevant to have a full picture of permissions abuse of any executable or dll which do not belong to the current user and where this last one has interesting permissions on the exe or dll ? I just fear it may be a bit long to enumerate.
Let me know,
Cheers.
Recently I ran PrivescCheck on the Windows 11 client of a customer but Invoke-SystemInfoCheck
and Get-WindowsVersion
detected the OS as Windows 10. I thought this might be because the system has been upgraded from 10 to 11 and maybe something wasn't clean afterwards.
But now I installed a fresh Windows 11 Pro myself (no upgrade) and the issue is reproducible:
> Invoke-SystemInfoCheck
Name Version
---- -------
Windows 10 Pro 10.0.22621 Version 2009 (22621.1194)
> Get-WindowsVersion
Major : 10
Minor : 0
Build : 22621
Revision : 0
MajorRevision : 0
MinorRevision : 0
Which is no surprise, given that Microsoft apparently messed it up in the registry. See ProductName
Value below. (Again, this is a fresh install from today!)
> Get-ItemProperty -Path "Registry::HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -ErrorAction SilentlyContinue
SystemRoot : C:\Windows
BaseBuildRevisionNumber : 1
BuildBranch : ni_release
BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff
BuildLab : 22621.ni_release.220506-1250
BuildLabEx : 22621.1.amd64fre.ni_release.220506-1250
CompositionEditionID : Enterprise
CurrentBuild : 22621
CurrentBuildNumber : 22621
CurrentMajorVersionNumber : 10
CurrentMinorVersionNumber : 0
CurrentType : Multiprocessor Free
CurrentVersion : 6.3
DisplayVersion : 22H2
EditionID : Professional
EditionSubManufacturer :
EditionSubstring :
EditionSubVersion :
InstallationType : Client
InstallDate : 1674909738
ProductName : Windows 10 Pro
ReleaseId : 2009
SoftwareType : System
UBR : 1194
PathName : C:\Windows
PendingInstall : 0
ProductId : 00330-80183-90218-AA479
DigitalProductId : {164, 0, 0, 0...}
DigitalProductId4 : {248, 4, 0, 0...}
RegisteredOwner : user
RegisteredOrganization :
InstallTime : 133193833380897739
PSPath : Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
PSParentPath : Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\Microsoft\Windows NT
PSChildName : CurrentVersion
PSProvider : Microsoft.PowerShell.Core\Registry
The only commands I found that show the correct OS are Get-WMIObject
and systeminfo
(the latter in German):
> (Get-WMIObject win32_operatingsystem).name.split('|')[0]
Microsoft Windows 11 Pro
> systeminfo
Hostname: WIN11
Betriebssystemname: Microsoft Windows 11 Pro
Betriebssystemversion: 10.0.22621 Nicht zutreffend Build 22621
[...]
Under specific conditions, the function Invoke-ServicesImagePermissionsCheck
incorrectly reports some service binary permissions as vulnerable.
Below is an example when the script is executed while the current directory is C:\Users\USERNAME
. It identifies Desktop
as a token to check, finds that the path C:\Users\USERNAME\Desktop
exists, and is writable. Therefore, it reports the service as vulnerable.
Name : SomeService
ImagePath : "C:\Program Files\SomeProgram\Foo Desktop Bar\SomeExecutable.exe"
User : LocalSystem
ModifiablePath : C:\Users\USERNAME\Desktop
IdentityReference : COMPUTER\USERNAME
Permissions : WriteOwner, Delete, WriteAttributes, Synchronize, ReadControl, ListDirectory, AddSubdirectory,
WriteExtendedAttributes, WriteDAC, ReadAttributes, AddFile, ReadExtendedAttributes, DeleteChild,
Traverse
Status : Stopped
UserCanStart : False
UserCanStop : False
Hi,
First off, love this script. I use it multiple times during my Pen Tests. Also love your blogs and research.
The HTML Report - The DLL hijacking Section doesn't have a severity even when the DLLs are missing. I thought this might be due to the fact that maybe the SYSTEM %PATH% folder check came back as compliant = true hence what else are you going to do with some missing DLLs.
When re assessing my HTML reports I found that even though the script highlighted that I could write to a SYSTEM %PATH%, the DLL section was still marked as complaint = true with no severity. I feel it could be beneficial to have the DLL section highlighted with a severity if the first condition is met.
Thanks
In the "Unquoted path check", a path such as C:\Program Files\SomeService\service.exe
is reported as being exploitable because the ACL indicates that BUILTIN\Users
can create files in C:\
. This is a false positive and needs to be filtered out.
Name : ServiceName
ImagePath : C:\Program Files\SomeService\service.exe
ModfiablePath : C:\
IndentityReference : BUILTIN\Users
Permissions : WriteData/AddFile
Status : Running
UserCanStart : False
UserCanRestart : False
This can be easily run by a one-liner:
IEX([Net.Webclient]::new().DownloadString("https://raw.githubusercontent.com/itm4n/PrivescCheck/master/PrivescCheck.ps1"));Invoke-PrivescCheck
Maybe consider adding this to the README.md
It would be great if Pentester could also see the potential path to insert malicious dll in Hijackable DLLs Test, similar to how PowerUp's invoke-allchecks displays
Hi !
The scheduled tasks checks (Invoke-ScheduledTasksImagePermissionsCheck
, Invoke-ScheduledTasksUnquotedPathCheck
) do not show correct results when multiple results exist for the same task: the first Add-Member
s work as expected, but further Add-Member
s for subsequent results of the same CurrentTask
do not work, as the function Add-Member
does not allow overwriting by default. This results in the ModifiablePath
, IdentityReference
, and Permissions
elements not being updated (and errors in the console), which for the user means the same result is outputted multiple times.
Example on an up-to-date 20H2, PSv5 (same ModifiablePath
, IdentityReference
, and Permissions
for both items; check was executed as a privileged user for demonstration purposes, so technically not a false positive 🙂):
Proposed solution: adding -Force
to each Add-Member
of both these checks. Example output (the attributes are updated, and no more error outputted):
Cheers! 🙂
Great tool! But I suppose I figure out some buggy testcase: if thread's token has deny only SID and file's ACE has deny only rule for that SID, Get-ModifiablePath() still shows that file could be modified, in spite of it actually couldn't.
PS C:\> icacls C:\test\file.txt
C:\test\file.txt BUILTIN\Administrators:(DENY)(W) <--- deny rule for administrators
BUILTIN\Users:(R,W)
PS C:\> whoami /groups
BUILTIN\Administrators Alias S-1-5-32-544 Group used for deny only <--- current user is administrator
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
PS C:\> Get-ModifiablePath -Path C:\test\file.txt
ModifiablePath IdentityReference Permissions
-------------- ----------------- -----------
C:\test NT AUTHORITY\Authenticated Users {Delete, WriteAttributes, Synchronize, ReadControl...}
C:\test\file.txt BUILTIN\Users {WriteAttributes, Synchronize, ReadControl, ReadData/ListDirectory...} <--- Get-ModifiablePath() shows that file is modifiable
PS C:\> echo 123 > C:\test\file.txt
out-file : Access to the path 'C:\test\file.txt' is <--- actually it's not
Suppose that root cause of the issue that you are completely ignoring deny ACEs after Get-Acl() invocation
Additional check for write permissions in folders in the current user's environment PATH variable. This script loops through each folder and checks for access-controls
https://github.com/unkn0wnsyst3m/scripts/blob/master/PathVarPermCheck.ps1
$groups = [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | ForEach-Object -Process { Write-Output $_.Translate([System.Security.Principal.NTAccount]) }
$userpath = $env:path
$path_array = $userpath.split(";")
$dtable = New-Object System.Data.DataTable
$dtable.Columns.Add("FolderPath", "System.String") | Out-Null
$dtable.Columns.Add("Access", "System.String") | Out-Null
Write-host "Current Path: "
$path_array
function CheckFolderAccess {
Param (
[String]$Folder
)
$User = $env:UserName
if (! $Folder -eq "" ) {
try {
$permission = (Get-Acl $Folder -ErrorAction Stop).Access | ?{$_.IdentityReference -match $User} | Select IdentityReference,FileSystemRights
If ($permission){
$Row = $dtable.NewRow()
$Row.FolderPath = $Folder
$Row.Access = $permission.FileSystemRights
$dtable.Rows.Add($Row)
} elseif (! $permission) {
$Row = $dtable.NewRow()
$Row.FolderPath = $Folder
$Row.Access = "NoWriteAccess"
$dtable.Rows.Add($Row)
}
}
catch {
$Row = $dtable.NewRow()
$Row.FolderPath = $Folder
$Row.Access = "FolderDoesNotExist"
$dtable.Rows.Add($Row)
}
}
}
foreach ($p in $path_array) {
CheckFolderAccess $p
}
$dtable | Format-Table
Output:
Current Path:
C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\OpenSSH\
C:\Program Files (x86)\Plantronics\Spokes3G\
C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\
C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\
C:\Program Files\Microsoft SQL Server\140\Tools\Binn\
C:\Program Files\Microsoft SQL Server\140\DTS\Binn\
C:\Program Files (x86)\Microsoft SQL Server\150\DTS\Binn\
C:\Windows\ServiceProfiles\MSSQL$SQLEXPRESS\AppData\Local\Microsoft\WindowsApps
FolderPath Access
---------- ------
C:\Windows\system32 NoWriteAccess
C:\Windows NoWriteAccess
C:\Windows\System32\Wbem NoWriteAccess
C:\Windows\System32\WindowsPowerShell\v1.0\ NoWriteAccess
C:\Windows\System32\OpenSSH\ NoWriteAccess
C:\Program Files (x86)\Plantronics\Spokes3G\ NoWriteAccess
C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\ NoWriteAccess
C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ NoWriteAccess
C:\Program Files\Microsoft SQL Server\140\Tools\Binn\ NoWriteAccess
C:\Program Files\Microsoft SQL Server\140\DTS\Binn\ NoWriteAccess
C:\Program Files (x86)\Microsoft SQL Server\150\DTS\Binn\ FolderDoesNotExist
C:\Windows\ServiceProfiles\MSSQL$SQLEXPRESS\AppData\Local\Microsoft\WindowsApps NoWriteAccess
From this tweet it is possible to enumerate Windows Defender's exclusions by listing the event ID 5007.
For example, whitelisting cmd.exe generates the following event
The tool https://github.com/0xsp-SRD/MDE_Enum already implement this finding and also enumerates the event ID 1121 to retrieve the ASR rules that have matched.
Hi,
Is the throw at line 725 intended?
PrivescCheck/src/helper/CredentialHelpers.ps1
Lines 638 to 730 in 7d384bf
It seems to be crashing the script when Get-SccmCacheFiles return $null.
Hello,
I have tried to download the tool but Windows Defender removes it because it says it contains a virus (Trojan). I think it is because in the Build.ps1 file there are Links to the original repository and, as it was called, PowerSploit detects that word as malicious and therefore the entire tool is quarantined (even if you download it as ZIP)
I want to think that the tool is safe. More than anything, I'm warning you in case you didn't know that this was happening, since maybe many people don't download it because of that link that Windows Defender sees as a threat.
PD: I'm sorry that the photo is in Spanish, but I think it is understood 😃
Thanks!
Hey there,
just wanted to give an update that the Wifi Airstrike attack was fixed in April 13 2021 https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-28316.
So I guess to properly detect the vulnerable config the patch level should also be checked.
Cheers
Hi @itm4n !
The function Get-ScheduledTaskList
does not work in Powershell V2:
This seems to be due to the use of member enumeration on lines 2496 and 2511, a feature only available starting from PS v3 ($TaskExec
is of type XmlElementList
, an array of XmlElement
objects):
Lines 2496 to 2511 in 39fc098
Thanks for your work !
I just tried to run the latest version and it threw an exception. I tracked it down to this line:
State = New-StructureField 1 $WTS_CONNECTSTATE_CLASS
and apparently $WTS_CONNECTSTATE_CLASS
is NULL and can't be bound to parameter Type
.
(btw I think it makes more sense to load the modules by replacing ./PrivescCheck.ps1:99
with $ScriptBlock = [Scriptblock]::Create($Decompressed); New-Module -ScriptBlock $ScriptBlock
, because then exceptions work better)
I checked all recent commits and the issue first appeared with 885c774.
I don't really understand why it is Null. I guess something goes wrong in New-Enum
. If you need more information about this particular system I'm running it on: I have access until the end of this week.
Hey,
It looks like LAPSv2 is currently not being checked.
I don't have time to make a PR right now, but I think a check could be added for the following locations:
HKLM:\Software\Microsoft\Policies\LAPS
HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\LAPS
HKLM:\Software\Microsoft\Windows\CurrentVersion\LAPS
I'm running the TryHackMe
Windows PrivEsc machine,
and there is a service binary path is unquoted path:
C:\Users\user>sc qc unquotedsvc
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: unquotedsvc
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Program Files\Unquoted Path Service\Common Files\unquotedpathservice.exe
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Unquoted Path Service
DEPENDENCIES :
SERVICE_START_NAME : LocalSystem
C:\Users\user>C:\PrivEsc\accesschk.exe /accepteula -uwdq "C:\Program Files\Unquoted Path Service\"
C:\Program Files\Unquoted Path Service
Medium Mandatory Level (Default) [No-Write-Up]
RW BUILTIN\Users
RW NT SERVICE\TrustedInstaller
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
C:\Users\user>whoami /all
USER INFORMATION
----------------
User Name SID
==================== ==============================================
win-qba94kb3iof\user S-1-5-21-3025105784-3259396213-1915610826-1000
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
====================================== ================ ============ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Desktop Users Alias S-1-5-32-555 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\REMOTE INTERACTIVE LOGON Well-known group S-1-5-14 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level Label S-1-16-8192
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
C:\Users\user>
but PrivescCheck said:
C:\PrivEsc>powershell -ep bypass -c ". .\PrivescCheck.ps1; Invoke-PrivescCheck"
...
+------+------------------------------------------------+------+
| TEST | SERVICES > Unquoted Path | VULN |
+------+------------------------------------------------+------+
| DESC | List registered services and check whether any of |
| | them is configured with an unquoted path that can be |
| | exploited. |
+------+-------------------------------------------------------+
[!] Not vulnerable.
...
I'm not sure if there is a bug or if I run it in the wrong way.
I think this project is cool and powerful, and I would like to contribute to its improvement. However, I am not very familiar with PowerShell.
The script returns empty WinLogon credentials.
+------+------------------------------------------------+------+
| TEST | CREDS > WinLogon | VULN |
+------+------------------------------------------------+------+
| DESC | Parse the Winlogon registry keys and check whether |
| | they contain any clear-text password. Entries that |
| | have an empty password field are filtered out. |
+------+-------------------------------------------------------+
[*] Found 1 result(s).
Domain :
Username :
Password :
This may occur if the values DefaultPassword
or AltDefaultPassword
exist but are empty. Indeed, the code only checks whether the value exist with $null -ne ...
.
if ($null -ne $RegItem.DefaultPassword) {
# ...
}
if ($null -ne $RegItem.AltDefaultPassword) {
# ....
}
The -ne
comparison should be replaced by [System.String]::IsNullOrEmpty()
.
Windows 1809 Build 17763.1577, PowerShell 1.0
| OK | None | SCHEDULED TASKS > Binary Permissions |
| OK | None | SCHEDULED TASKS > Unquoted Path |
| OK | None | SCHEDULED TASKS > Binary Permissions |
| OK | None | SCHEDULED TASKS > Unquoted Path |
The configuration above allows the program/script (runs with a high privilege) to be changed by anyone. However PrivescCheck failed to detect it.
Hi itm4n,
Just wanted to let you know, there might be something wrong with the credential guard logic or i'm missing something. Invoke-CredentialGuardCheck might require a little update. Get-WindowsVersion also doesn't exist so it still returns "Credential Guard is not supported on this OS"
On my Windows 11 machine Credential Guard was running (by default on Windows 11) but it wasn't configured.
Check configuration returned false:
"CredentialGuard" -match ((Get-ComputerInfo).DeviceGuardSecurityServicesConfigured)
Check running returned true:
"CredentialGuard" -match ((Get-ComputerInfo).DeviceGuardSecurityServicesRunning)
Please close it if you think it isn't an issue, just wanted to let you know and help improve your awesome script!
When running Invoke-PrivescCheck
on my current target, I get the following exception.
+------+------------------------------------------------+------+
| TEST | SERVICES > Registry Permissions | VULN |
+------+------------------------------------------------+------+
| DESC | Parse the registry and check whether the current user |
| | can modify the configuration of any registered |
| | service. |
+------+-------------------------------------------------------+
Get-Acl : Es wurde versucht, einen nicht autorisierten Vorgang auszuführen.
In Zeile:1189 Zeichen:19
+ ... $KeyAcl = Get-Acl -Path $Path -ErrorAction SilentlyContinue -ErrorV ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Acl], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetAclCommand
The German line roughly says "An unauthorized task was attempted."
It is possible to run PrivescCheck with -ErrorAction SilentlyContinue
but maybe this can be fixed.
By default, Windows machines perform automatic proxy discovery. This makes some man-in-the-middle attacks easier, see for example: https://dirkjanm.io/worst-of-both-worlds-ntlm-relaying-and-kerberos-delegation/
The reason is because they download the settings from wpad.corp.local
and other hosts without any sort of verification.
Sure, there are many other ways to get a MitM position, and if every service was properly hardened (i.e. validate certs, enforce SMB signing, etc), it wouldn't matter much. But many Windows protocols by default are vulnerable. So if I wanted to harden a Windows default installation and didn't really, really need automatic proxy discovery, I'd want to disable it.
I'd like Invoke-PrivescCheck to report default WPAD settings, either as VULN LOW or INFO. What do you think? Should I submit a PR?
On a Microsoft Windows Server 2019 Standard, PrivescCheck crashed when checking wifi profiles. Running Invoke-WlanProfilesCheck
as a standalone check reproduces this for me.
> Invoke-WlanProfilesCheck
Cannot bind argument to parameter 'Message' because it is null.
+ CategoryInfo : InvalidData: (:) [Invoke-WlanProfilesCheck], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Invoke-WlanProfilesCheck
This could be convenient :o)
Hi!
Would it be possible to readd the "Compliance" field within the XML output?
On a previous version it was like this:
<Object Type="System.Management.Automation.PSCustomObject">
<Property Name="Id" Type="System.String">HARDEN_BITLOCKER</Property>
<Property Name="Category" Type="System.String">Hardening</Property>
<Property Name="DisplayName" Type="System.String">BitLocker</Property>
<Property Name="Description" Type="System.String">Check whether BitLocker is configured and enabled on the system drive. Note that this check will yield a false positive if another encryption software is in use.</Property>
<Property Name="Type" Type="System.String">Info</Property>
<Property Name="Compliance" Type="System.Boolean">False</Property>
<Property Name="Severity" Type="System.String">None</Property>
<Property Name="ResultRawString" Type="System.String">
Now the Compliance field is missing:
<Object Type="System.Management.Automation.PSCustomObject">
<Property Name="Id" Type="System.String">HARDEN_BITLOCKER</Property>
<Property Name="Category" Type="System.String">TA0001 - Initial Access</Property>
<Property Name="DisplayName" Type="System.String">BitLocker configuration</Property>
<Property Name="Description" Type="System.String">Check whether BitLocker is enabled on the system drive and requires a second factor of authentication (PIN or startup key). Note that this check might yield a false positive if a third-party drive encryption software is installed.</Property>
<Property Name="Severity" Type="System.String">Medium</Property>
<Property Name="ResultRawString" Type="System.String">
Line 550 in a7b04e6
function Test-IsKnownService {
[CmdletBinding()] param(
[object]$Service
)
if (-not($Service)) { return $false }
$ImagePath = $Service.ImagePath
$SeparationCharacterSets = @('"', "'", ' ', "`"'", '" ', "' ", "`"' ")
ForEach($SeparationCharacterSet in $SeparationCharacterSets) {
$CandidatePaths = $ImagePath.Split($SeparationCharacterSet) | Where-Object {-not([String]::IsNullOrWhiteSpace($_)) }
ForEach($CandidatePath in $CandidatePaths) {
$TempPath = $([System.Environment]::ExpandEnvironmentVariables($CandidatePath))
if (-not(Test-Path -LiteralPath $TempPath)) { continue }
$File = Get-Item -LiteralPath $TempPath -ErrorAction SilentlyContinue -ErrorVariable ErrorGetItem
if ($File.VersionInfo.LegalCopyright -Like "*Microsoft Corporation*") { return $True }
elseif ($null -eq $File) { continue }
else { return $False }
}
}
}
Hi there,
I had a customer today where the DWORD Value DisableWindowsUpdateAccess under HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate was set to 1 which seems to effectively disable Windows Update and the config is not vulnerable event though http is set. Would be great if that made into the checks.
PrivescCheck covers the majority of the host checks I'd perform except SMB signing, which is often useful to know, especially as there are a bunch of different and whacky (like https://github.com/nccgroup/Change-Lockscreen) ways to coerce a SYSTEM/user account to authenticate to a capture/relay server.
I've written a reference implementation below. I reckon it should probably be in the -Extended category?
function Get-SMBSigningStatus {
# NOTE: The EnableSecuritySignature registry setting for SMB2+ client and SMB2+ server is ignored.
# Therefore, this setting does nothing unless you're using SMB1. So we only care about RequireSecuritySignature.
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/overview-server-message-block-signing
$SmbClientSettingsPath = "HKLM:\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters"
$SmbServerSettingsPath = "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters"
# Check if the registry value exists
if (Test-Path $SmbClientSettingsPath) {
$value = Get-ItemPropertyValue -Path $SmbClientSettingsPath -Name "RequireSecuritySignature" -ErrorAction SilentlyContinue
$status = if ($value -eq 1) { "Required" } else { "NOT Required" }
Write-Output "SMB Client signing is $status."
} else {
Write-Output "SMB Client signing settings not found"
}
# Check if the registry value exists
if (Test-Path $SmbServerSettingsPath) {
$value = Get-ItemPropertyValue -Path $SmbServerSettingsPath -Name "RequireSecuritySignature" -ErrorAction SilentlyContinue
$status = if ($value -eq 1) { "Required" } else { "NOT Required" }
Write-Output "SMB Server signing is $status."
} else {
Write-Output "SMB Server signing settings not found"
}
}
Get-SMBSigningStatus
What about adding a check to see if there's a vulnerable driver like the project https://github.com/FourCoreLabs/LolDriverScan/blob/master/loldriverscan.go
I ran the script on a Server 2022 system with KB5033118 installed. Since this update apparently doesn't create a registry key in the expected format Get-HotFixList misses this update.
As far as I can tell parsing update information from the registry is an unsupported hack, so I think it would make sense in the long term if the script parsed both the registry and Get-HotFix, and warn the user if Get-Hotfix shows an update not collected from the registry.
In order to secure your system, you must confirm that the following registry settings are set to 0 (zero) or are not defined (Note: These registry keys do not exist by default, and therefore are already at the secure setting.):
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint
NoWarningNoElevationOnInstall = 0 (DWORD) or not defined (default setting)
NoWarningNoElevationOnUpdate = 0 (DWORD) or not defined (default setting)
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527
https://twitter.com/gentilkiwi/status/1412771368534528001
https://github.com/tothi/CVE-2021-1675
If Point and Print is enabled, the PrintNightmare patch can be completely bypassed, and PrintNightmare works for RCE and LPE. If NoWarningNoElevationOnInstall (and I assume NoWarningNoElevationOnUpdate) are enabled, the patch can be bypassed for LPE. Microsoft has stated that these vulnerable configurations are not something that will be patched.
I think if would be good to add these registry keys to PrivescCheck to check if the system is vulnerable to privilege escalation using PrintNightmare.
Hi,
Would it be possible to add a remote parameter to the Invoke-WinlogonCheck to search in the GPP files in the SYSVOL share, similarly like you implemented in the Invoke-GPPPasswordCheck function?
Hi, thanks for your effort in developing this enumeration script. It's a really nice project and it is really useful for engagements to quickly find privesc vulns, however, sadly this is only fully usable on an interactive powershell session on the system. Somehow the script is not fully usable using reflections or using powershell import commands and executing it, or by executing it via Metasploit. The script starts to execute but stops after the first enumeration.
I was trying to execute the script via metasploit and another commercial C2 without success, would it be possible to make the script more compatible for offensive red-team operations where you only have a session via a beacon / metasploit session etc. and importing it e.g. in your own HostingCLR to execute it?
OS: Windows 11 22621.1105
Steps to reproduce:
$env:USERPROFILE\Desktop\vuln.exe
BUILTIN\Administrators
group to execute vuln.exe
and also tick the checkmark "Run with highest privileges"Expected result:
PrivescCheck detects the vulnerable task, since the current user has permission to write to his Desktop folder, as well as replacing vuln.exe
for any file of his choice
Actual result:
PrivescCheck gives OK status in the Scheduled Task: Binary Exploitation section and doesn't list the task.
SIDENOTE:
The group for executing the task doesn't have to be strictly BUILTIN\Administrators
, it can be any high privileged User.
It can be even the current user but with "Run with highest privileges" checkmark.
I also tried exporting the task to XML file, changing the actual author within the file and importing it back, to simulate creation of task by a different user. Sadly, same result.
Hey, great tool!
I am testing on a Windows 10 Enterprise (20H2), it's spitting out a lot of errors.
Actual script output is diverted to a text file, so only errors are showing in PS console, I also have local admin privs but did not run PS as administrator.
Let me know if you need more details!
PS D:\Toolz\AVtest> Invoke-PrivescCheck -Extended > privescReport.txt
Get-ItemProperty : Specified cast is not valid.
At D:\Toolz\AVtest\PrivescCheck.ps1:1385 char:27
+ ... roperties = Get-ItemProperty -Path $RegService.PSPath -ErrorAction Si ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ItemProperty], InvalidCastException
+ FullyQualifiedErrorId : System.InvalidCastException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
Get-Item : Could not find item C:\ProgramData\Tencent\QQPCMgr\QMConfig.hiv.LOG1.
At D:\Toolz\AVtest\PrivescCheck.ps1:1570 char:27
+ if ($(Get-Item -Path $ResolvedPath) -is [System.I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\ProgramData\...Config.hiv.LOG1:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Could not find item C:\ProgramData\Tencent\QQPCMgr\QMConfig.hiv.LOG2.
At D:\Toolz\AVtest\PrivescCheck.ps1:1570 char:27
+ if ($(Get-Item -Path $ResolvedPath) -is [System.I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\ProgramData\...Config.hiv.LOG2:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Could not find item C:\ProgramData\Tencent\QQPCMgr\QMConfig.hiv{f8fce59d-bade-11ea-b83e-d43d7e187ce5}.TM.blf.
At D:\Toolz\AVtest\PrivescCheck.ps1:1570 char:27
+ if ($(Get-Item -Path $ResolvedPath) -is [System.I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\ProgramData\...e187ce5}.TM.blf:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Could not find item C:\ProgramData\Tencent\QQPCMgr\QMConfig.hiv{f8fce59d-bade-11ea-b83e-d43d7e187ce5}.TMContainer00000000000000000001.regtrans-ms.
At D:\Toolz\AVtest\PrivescCheck.ps1:1570 char:27
+ if ($(Get-Item -Path $ResolvedPath) -is [System.I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\ProgramData\...001.regtrans-ms:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Could not find item C:\ProgramData\Tencent\QQPCMgr\QMConfig.hiv{f8fce59d-bade-11ea-b83e-d43d7e187ce5}.TMContainer00000000000000000002.regtrans-ms.
At D:\Toolz\AVtest\PrivescCheck.ps1:1570 char:27
+ if ($(Get-Item -Path $ResolvedPath) -is [System.I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\ProgramData\...002.regtrans-ms:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Hello again,
So in a training lab, they implemented a (not so common) privesc scenario where the service control manager itself suffers from permissive rights (see https://docs.microsoft.com/en-us/windows/win32/services/service-security-and-access-rights).
This builtin service can not be listed in the function Get-ServiceList
which enumerates all keys in the reg path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
.
How i was able to spot it:
PS C:\> sc.exe sdshow scmanager
D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;S-1-5-21-948911695-1962824784-4291460660-1124)(A;;KA;;;BA)(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205)
PS C:\> ConvertFrom-SddlString -Sddl "D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;S-1-5-21-948911695-1962824784-4291460660-1124)(A;;KA;;;BA)(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205)" | select -ExpandProperty DiscretionaryAcl
NT AUTHORITY\INTERACTIVE: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, WriteExtendedAttributes)
NT AUTHORITY\SERVICE: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, WriteExtendedAttributes)
NT AUTHORITY\Authenticated Users: AccessAllowed (ListDirectory)
NT AUTHORITY\SYSTEM: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, Traverse, WriteExtendedAttributes)
BUILTIN\Administrators: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
DOM\REDACTEDGroup: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES: AccessAllowed (ListDirectory)
: AccessAllowed (ListDirectory)
Do you think it could be a good idea to add this kind of check ? i can help / work on it also but before i would like to confirm it s relevant from your point of view.
Cheers !
When building the script, the file src\02_Helpers.ps1
is blocked by AMSI.
C:\PATH\TO\PrivescCheck>powershell -ep bypass -c ".\Build.ps1"
[OK] Loaded module file 00_Main.ps1
[OK] Loaded module file 01_Win32.ps1
[KO] Failed to load module file 02_Helpers.ps1
[ERROR] At C:\_WORKSPACE\PrivescCheck\src\02_Helpers.ps1:1 char:1
+ function Test-IsRunningInConsole {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
[OK] Loaded module file 03_User.ps1
[OK] Loaded module file 04_Services.ps1
[OK] Loaded module file 05_Applications.ps1
[OK] Loaded module file 06_ScheduledTasks.ps1
[OK] Loaded module file 07_Hardening.ps1
[OK] Loaded module file 08_Config.ps1
[OK] Loaded module file 09_Network.ps1
[OK] Loaded module file 10_Updates.ps1
[OK] Loaded module file 11_Credentials.ps1
[OK] Loaded module file 99_Misc.ps1
This can be worked around by disabling "Windows Security" during build, but it would be nice to improve the Builder script in order to bypass detection earlier in the process.
Hi,
Even though it won't be useful very often, would it make sense to add SeRelabelPrivilege to the HighPotentialPrivileges?
hey, I got this when I ran the latest version of the script (with and without -extended):
Get-ItemProperty : Specified cast is not valid.
At line:787 char:26
+ ... roperties = Get-ItemProperty -Path "Registry::$ServiceRegPath" -Error ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ItemProperty], InvalidCastException
+ FullyQualifiedErrorId : System.InvalidCastException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
Powershell 5.1
Windows 11 (21H2) 64bit
Let me know if more details are needed!
Cheers
C:\temp>powershell -ep bypass -c "C:\temp\PrivescCheck.ps1; Invoke-PrivescCheck"
At C:\temp\PrivescCheck.ps1:40 char:60
~~~~~
Unexpected token ':"en"' in expression or statement.
At C:\temp\PrivescCheck.ps1:40 char:65
~
Missing argument in parameter list.
At C:\temp\PrivescCheck.ps1:40 char:285
~
The '<' operator is reserved for future use.
At C:\temp\PrivescCheck.ps1:227 char:84
~
Unexpected token ':' in expression or statement.
At C:\temp\PrivescCheck.ps1:227 char:88
~
The '<' operator is reserved for future use.
At C:\temp\PrivescCheck.ps1:264 char:205
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.