Created
May 8, 2024 14:57
-
-
Save egglessness/5035c5b3c1c849b51b596a0ca809f6a4 to your computer and use it in GitHub Desktop.
Parse UAC consent prompt events with information about the called process
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ScanResultsPath = ".\UacPrompts.csv" | |
$DateFormat = "yyyyMMddHHmmss" | |
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") | |
if (-not $isAdmin) { | |
Write-Host "You must run this script with administrator privileges!" | |
exit | |
} | |
$isAuditEnabled = auditpol /get /subcategory:"{0CCE922B-69AE-11D9-BED3-505054503030}" | select-string "Success" -Quiet | |
if ($isAuditEnabled -ne $true) { | |
Write-Warning "Process Creation audit logging has not been enabled. Details will not be available." | |
} | |
try { | |
$ScanResults = Import-Csv -Path $ScanResultsPath | |
if (-not ($ScanResults -is [System.Array])) { | |
$ScanResults = @($ScanResults) | |
} | |
$LastScanDate = [datetime]::ParseExact($ScanResults[0].Timestamp, $DateFormat, $null) | |
Write-Host "Found data from previous scan. Last collected event was at" $LastScanDate | |
} | |
catch { | |
$ScanResults = @() | |
$LastScanDate = $null | |
} | |
Write-Host "Collecting UAC Consent Prompt events (EventID: 4624, ProcessName: consent.exe, ElevatedToken: Yes) ..." | |
$AllUacPrompts = Get-WinEvent -FilterXml @" | |
<QueryList> | |
<Query Id='0' Path='Security'> | |
<Select Path='Security'> | |
*[System[(EventID=4624)] and EventData[Data[@Name='ProcessName']='C:\Windows\System32\consent.exe'] and EventData[Data[@Name='ElevatedToken']='%%1842']] | |
</Select> | |
</Query> | |
</QueryList> | |
"@ | |
if ($LastScanDate) { | |
$UacPrompts = $AllUacPrompts | Where-Object { $_.TimeCreated -gt $LastScanDate.AddSeconds(1) } | |
} | |
else { | |
$UacPrompts = $AllUacPrompts | |
} | |
Write-Host "Correlating with Process Creation events (EventID: 4688, MandatoryLabel: High) ..." | |
$Results = @() | |
foreach ($UacPrompt in $UacPrompts) { | |
$FromTime = $UacPrompt.TimeCreated.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.000Z") | |
$ToTime = $UacPrompt.TimeCreated.AddSeconds(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.000Z") | |
$ProcessCreationEvent = Get-WinEvent -FilterXml @" | |
<QueryList> | |
<Query Id='0' Path='Security'> | |
<Select Path='Security'> | |
*[System[(EventID=4688) and (TimeCreated[@SystemTime>'$FromTime' and @SystemTime<'$ToTime'])]] | |
and | |
*[EventData[Data[@Name='MandatoryLabel']='S-1-16-12288' or Data[@Name='MandatoryLabel']='S-1-16-16384']] | |
</Select> | |
</Query> | |
</QueryList> | |
"@ -ErrorAction SilentlyContinue | Sort-Object TimeCreated | Select-Object -First 1 | |
try { | |
$Results += [PSCustomObject]@{ | |
Timestamp = $UacPrompt.TimeCreated.ToString($DateFormat) | |
Computer = $ProcessCreationEvent.Properties[1].Value | |
Domain = $ProcessCreationEvent.Properties[11].Value | |
User = $ProcessCreationEvent.Properties[10].Value | |
Process = $ProcessCreationEvent.Properties[5].Value | |
} | |
} | |
catch { | |
$Results += [PSCustomObject]@{ | |
Timestamp = $UacPrompt.TimeCreated.ToString($DateFormat) | |
Computer = $null | |
Domain = $null | |
User = $null | |
Process = $null | |
} | |
} | |
} | |
Write-Host "Found" $Results.Length "new events." | |
$Results | Format-Table | |
if ($Results.Length -gt 0) { | |
$ScanResults + $Results | Sort-Object Timestamp -Descending | Export-Csv -Path $ScanResultsPath -NoTypeInformation | |
Write-Host "Scan results saved on file:" $ScanResultsPath | |
} |
I found out that this script does not work on Windows 11, where the UAC interactions are a little bit different.
If you happen to have Defender for Endpoint installed on the machines you want to monitor, you can track UAC elevation prompts just by using the following KQL query to extract the same data for any version of Windows:
let computerName = "XXX";
// UAC consent prompt events
let consentPrompts = DeviceProcessEvents
| where DeviceName contains computerName
| where ActionType == "ProcessCreated" and FileName == "consent.exe"
| project PromptTime = Timestamp, DeviceName;
// Process creation events with high privileges
let processCreationEvents = DeviceProcessEvents
| where ActionType == "ProcessCreated" and DeviceName contains computerName and
ProcessIntegrityLevel == "High" and ProcessTokenElevation == "TokenElevationTypeFull" and
InitiatingProcessFileName == "explorer.exe"
| project ElevationTime = Timestamp, DeviceName, AccountDomain, AccountName,
Process = ProcessVersionInfoOriginalFileName, CommandLine = ProcessCommandLine;
consentPrompts | join kind=inner processCreationEvents on DeviceName
| where (ElevationTime - PromptTime) between (0sec .. 20sec)
| sort by PromptTime desc
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script generates a CSV report containing details about UAC elevation prompt in a computer.
It fetches User Logon logs (EventID: 4624, ProcessName: consent.exe, ElevatedToken: Yes) and correlates them with subsequent Process Creation events with High Integrity Level to get details about the computer name, domain, user, and process.
By default, User Logons are enabled, while Process Creation audit logs must be manually enabled with the following command:
Since those kind of logs rotate very frequently, it is best to run this script every hour. Results are always saved in append onto the output CSV file.
LIMITATION: if a process elevates itself while it's running (some installers do that, like Blender's), process details are not listed.