Skip to content

Instantly share code, notes, and snippets.

@egglessness
Created May 8, 2024 14:57
Show Gist options
  • Save egglessness/5035c5b3c1c849b51b596a0ca809f6a4 to your computer and use it in GitHub Desktop.
Save egglessness/5035c5b3c1c849b51b596a0ca809f6a4 to your computer and use it in GitHub Desktop.
Parse UAC consent prompt events with information about the called process
$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&gt;'$FromTime' and @SystemTime&lt;'$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
}
@egglessness
Copy link
Author

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:

auditpol /set /subcategory:"{0CCE922B-69AE-11D9-BED3-505054503030}" /success:enable /failure:disable

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.

@egglessness
Copy link
Author

egglessness commented May 16, 2024

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