Group Policy Discovery
This detection identifies adversary attempts to enumerate Group Policy Objects (GPOs) and Group Policy settings within an Active Directory environment. Attackers use tools such as gpresult.exe, PowerShell cmdlets (Get-DomainGPO, Get-DomainGPOLocalGroup, Get-GPO), and frameworks like PowerView and BloodHound to discover GPO configurations that reveal privilege escalation paths, security control gaps, and domain trust relationships. Detected activity includes direct invocation of gpresult.exe outside of normal administrative contexts, PowerShell-based GPO enumeration via PowerView or RSAT cmdlets, and LDAP queries targeting GPO-related LDAP attributes. Correlating these patterns with post-discovery activity such as lateral movement or GPO modification attempts allows analysts to identify reconnaissance phases of domain-targeted attacks.
What is T1615 Group Policy Discovery?
Group Policy Discovery (T1615) maps to the Discovery tactic — the adversary is trying to figure out your environment in MITRE ATT&CK.
This page provides production-ready detection logic for Group Policy Discovery, covering the data sources and telemetry it touches: Microsoft Defender for Endpoint. The queries below are rated medium severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Discovery
- Technique
- T1615 Group Policy Discovery
- Canonical reference
- https://attack.mitre.org/techniques/T1615/
let SuspiciousGPOPSFunctions = dynamic([
"Get-DomainGPO", "Get-DomainGPOLocalGroup", "Get-DomainGPOComputerLocalGroupMapping",
"Get-DomainGPOUserLocalGroupMapping", "Get-NetGPO", "Get-GPO",
"Get-GPResultantSetOfPolicy", "Get-GPOReport", "Find-GPOLocation",
"Find-GPOComputerAdmin"
]);
let LegitParents = dynamic(["mmc.exe", "gpedit.msc", "gpmc.msc", "msiexec.exe", "sccmexec.exe", "ccmexec.exe"]);
DeviceProcessEvents
| where TimeGenerated > ago(1d)
| where (
// Direct gpresult enumeration outside standard admin parent processes
(FileName =~ "gpresult.exe"
and not(InitiatingProcessFileName has_any (LegitParents))
and AccountName !endswith "$"
)
// PowerShell GPO enumeration via PowerView, Empire, or RSAT
or (FileName in~ ("powershell.exe", "pwsh.exe")
and ProcessCommandLine has_any (SuspiciousGPOPSFunctions)
)
// WMIC-based GPO queries
or (FileName =~ "wmic.exe"
and ProcessCommandLine has_any ("gpo", "grouppolicy")
)
// net.exe querying GPO-related groups
or (FileName =~ "net.exe"
and ProcessCommandLine matches regex @"(?i)(group\s*policy|gpo)"
)
)
| extend AccountUpn = strcat(AccountDomain, "\\", AccountName)
| project
TimeGenerated,
DeviceName,
AccountUpn,
AccountName,
AccountDomain,
FileName,
ProcessCommandLine,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
InitiatingProcessParentFileName,
FolderPath
| order by TimeGenerated desc Detects Group Policy Discovery activity via gpresult.exe invocations outside standard admin tooling parents, PowerShell use of PowerView and RSAT GPO enumeration functions (Get-DomainGPO, Get-GPO, Get-GPResultantSetOfPolicy, etc.), WMIC queries targeting group policy, and net.exe GPO-related queries. Filters machine accounts and known legitimate parent processes to reduce noise.
Data Sources
Required Tables
False Positives
- IT administrators running gpresult.exe manually or via scripts for compliance auditing and troubleshooting Group Policy application failures
- SCCM/Intune client management processes (ccmexec.exe, msiexec.exe) invoking gpresult.exe during client health checks or software deployments
- Security and compliance tooling (e.g., Tenable, Rapid7, CrowdStrike Spotlight) using PowerShell GPO cmdlets during scheduled configuration assessment scans
- Help desk personnel using GPMC or RSAT tools to diagnose user/computer policy application issues
- Automated GPO compliance checks performed by domain management scripts run from privileged service accounts
Sigma rule & cross-platform mapping
The detection logic for Group Policy Discovery (T1615) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
category: process_creation
product: windows Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for T1615
References (5)
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1GPO Enumeration via gpresult.exe
Expected signal: Sysmon EventCode=1: Image=gpresult.exe with CommandLine containing /z and /scope. Security EventID=4688 if process creation auditing enabled with command line logging. File creation event for C:\Temp\gpo_computer.txt (Sysmon EventCode=11).
- Test 2GPO Enumeration via PowerView Get-DomainGPO
Expected signal: Sysmon EventCode=1: powershell.exe with CommandLine containing Get-DomainGPO. PowerShell Script Block Logging (EventID 4104) capturing the full IEX expression and Get-DomainGPO function body. Sysmon EventCode=3 for LDAP connections to domain controllers (port 389) from powershell.exe.
- Test 3GPO Enumeration via RSAT Get-GPO PowerShell Cmdlet
Expected signal: Sysmon EventCode=1: powershell.exe with CommandLine containing 'Get-GPO' and 'Get-GPResultantSetOfPolicy'. PowerShell EventID 4103/4104 capturing module import of GroupPolicy and cmdlet invocations. Sysmon EventCode=11 for HTML report file creation at C:\Temp\rsop_report.html. LDAP traffic to domain controllers for GPO object queries.
Response Playbook
Triage
- Step 1: Identify the initiating process and parent process chain. For gpresult.exe, a legitimate chain looks like: explorer.exe → cmd.exe → gpresult.exe. Suspicious chains include: cmd.exe spawned by a web server, script engine (wscript.exe, cscript.exe), or an unsigned binary.
- Step 2: Examine the full command-line arguments of the detected process. gpresult.exe run with /z or /v (verbose), /scope with both user and computer, or output redirected to a file are higher-confidence indicators of recon. PowerShell with multiple GPO functions in a single session is a strong signal.
- Step 3: Correlate the AccountName with the device. If the account is a non-admin standard user running GPO enumeration on a server or DC, escalate immediately. Admin accounts should still be verified against expected admin workstation patterns.
- Step 4: Review DeviceProcessEvents in the 30-minute window before and after the detected event on the same DeviceName. Look for preceding LDAP queries (ldap.exe, dsquery.exe), credential access (lsass access via Sysmon 10), or network connections to domain controllers.
- Step 5: Search IdentityQueryEvents (if Microsoft Defender for Identity is deployed) for LDAP queries to gpLink, gPCFileSysPath, or ms-DS-MachineAccountQuota attributes from the same source device, which indicates LDAP-based GPO enumeration bypassing process-level detection.
- Step 6: Check if the tool is a known adversary framework binary. Hash the executing PowerShell script block (Sysmon EventCode=4104) or the initiating binary against threat intel. BloodHound's SharpHound.exe has well-known hashes. PowerView modules leave characteristic script block content.
Containment
- If the account is confirmed compromised: disable the account in Active Directory immediately via 'Disable-ADAccount -Identity <samAccountName>' and force sign-out of all active sessions via 'Revoke-AzureADUserAllRefreshToken' if hybrid-joined.
- Isolate the affected endpoint via Microsoft Defender for Endpoint portal (Device Actions → Isolate Device) or via MDE Live Response to prevent further reconnaissance or lateral movement.
- If a PowerShell script executed PowerView functions, enable Constrained Language Mode via AppLocker or WDAC policy on the affected endpoint to prevent further PowerShell-based enumeration during the investigation window.
- Block the source IP at the network perimeter and firewall if GPO enumeration was initiated from a non-corporate IP (check VPN/proxy logs for source correlation).
- If BloodHound/SharpHound collection is suspected, rotate the krbtgt account password twice (required to invalidate all Kerberos tickets) after confirming scope, coordinating with AD team to minimize impact.
Evidence Collection
- Collect Sysmon event logs from the affected endpoint: export Microsoft-Windows-Sysmon/Operational channel covering EventCodes 1 (process create), 10 (process access), 17/18 (named pipe), and 22 (DNS query) from the incident timeframe.
- Export Windows Security event log for EventIDs 4688 (process creation with command line, requires audit policy), 4624/4625/4648 (logon events), and 4662 (object access on GPO GUID containers in AD).
- Collect the PowerShell script block logs from Microsoft-Windows-PowerShell/Operational (EventID 4103, 4104) on the affected host. These capture the actual PowerShell code executed, including obfuscated or downloaded scripts.
- Retrieve the gpresult output file if it was redirected (e.g., gpresult /z > C:\Temp\output.txt). Use MDE Live Response 'getfile' to collect any output files before they are deleted.
- Capture a memory image of the affected process (if still running) using procdump: 'procdump.exe -ma <PID>' for forensic analysis of in-memory PowerShell scripts or shellcode injected into legitimate processes.
- Export Active Directory audit logs for the time period: run 'Get-ADObject -Filter {ObjectClass -eq "groupPolicyContainer"} -Properties whenChanged | Where-Object {$_.whenChanged -gt (Get-Date).AddHours(-4)}' to identify any GPO modifications following the discovery activity.
Escalation Criteria
- ! Escalate to Tier 3 / Incident Response if GPO discovery is followed within 60 minutes by any of: new local admin account creation (EventID 4720 + 4732), service installation (EventID 7045), scheduled task creation (EventID 4698), or WMI event subscription creation.
- ! Escalate immediately if the source account is a service account, machine account, or a privileged account (Domain Admin, Enterprise Admin, Schema Admin) — these should never be used interactively for GPO enumeration.
- ! Escalate if multiple distinct hosts in the same subnet show GPO discovery activity within a short time window (>3 hosts in 30 minutes), which indicates lateral movement with systematic domain reconnaissance.
- ! Escalate if BloodHound-related tooling (SharpHound.exe, bloodhound-python, known file hashes) is identified — BloodHound is explicitly designed for attack path mapping and its presence indicates active compromise planning.
- ! Escalate if the discovery activity correlates with known threat actor TTPs from threat intelligence (e.g., Turla using gpresult during C2 check-in, DUSTTRAP targeting AD environments) as documented in MITRE ATT&CK procedure examples.
Investigation Guide
Forensic Artifacts
- >
Prefetch files: %SystemRoot%\Prefetch\GPRESULT.EXE-*.pf — timestamps indicate when gpresult was last executed - >
PowerShell history file: %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt — may contain PowerView commands - >
Windows event log: Microsoft-Windows-PowerShell/Operational (EventID 4104) — captures script block content including PowerView module imports - >
SYSVOL access artifacts: File access logs showing reads from \\<DOMAIN>\SYSVOL\<DOMAIN>\Policies\ — indicates direct SYSVOL GPO file enumeration - >
Amcache.hve / ShimCache: Records of gpresult.exe or SharpHound.exe execution including first/last run timestamps - >
UserAssist registry key: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist — tracks GUI-launched tools related to GPMC - >
DNS cache: ipconfig /displaydns output or event logs for DNS lookups to domain controllers, which may reveal LDAP-based GPO enumeration endpoints - >
Network PCAP: LDAP traffic (port 389/636) with filter attributes for 'gpLink', 'gPCFileSysPath', 'displayName' in the dn=CN=Policies,CN=System context
Tuning Guidance
Start by building an allowlist of accounts and parent processes that legitimately run gpresult.exe — common callers include SCCM (ccmexec.exe), MDT, and IT admin scripts. Add these as exclusions in the InitiatingProcessFileName filter. For PowerShell detections, if Get-GPO is heavily used by your IT team for legitimate GPO management, scope the detection to non-admin OUs or restrict to non-privileged accounts only. If Microsoft Defender for Identity is deployed, tune toward the LDAP-based hunting query which has fewer false positives than process-based detection. Consider increasing severity to 'high' if the alert fires on a server or domain controller rather than a workstation, as interactive GPO enumeration on DCs is almost never legitimate.
Hunting Queries
Hunts for direct SYSVOL Policies directory file access by non-standard processes, which indicates GPO file enumeration bypassing process-level detection. High file counts from a single session suggest automated enumeration.
// Hunt for SYSVOL GPO directory access patterns indicating direct file-based enumeration
DeviceFileEvents
| where TimeGenerated > ago(7d)
| where FolderPath matches regex @"(?i)\\SYSVOL\\[^\\]+\\Policies\\"
| where ActionType in ("FileRead", "FileAccessed")
| where InitiatingProcessFileName !in~ ("gpupdate.exe", "svchost.exe", "lsass.exe", "mmc.exe", "dfsr.exe", "dfsrs.exe")
| summarize
FileCount = count(),
UniqueFiles = dcount(FileName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| where FileCount > 5
| order by FileCount desc index=* sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=11
| where match(TargetFilename, "(?i)\\\\SYSVOL\\\\[^\\\\]+\\\\Policies\\\\")
| where NOT match(Image, "(?i)(gpupdate|svchost|lsass|mmc|dfsr)")
| stats count as file_access_count, dc(TargetFilename) as unique_files, earliest(_time) as first_seen, latest(_time) as last_seen by Computer, User, Image, CommandLine
| where file_access_count > 5
| sort - file_access_count Hunts for LDAP object access events (4662) targeting Group Policy Container objects in Active Directory, which captures GPO enumeration that occurs via LDAP queries rather than process execution — a technique used by BloodHound and custom scripts to avoid process-based detections.
// Hunt for LDAP-based GPO enumeration using IdentityQueryEvents (requires Microsoft Defender for Identity)
IdentityQueryEvents
| where TimeGenerated > ago(7d)
| where QueryType == "Ldap"
| where QueryTarget contains "Policies" or QueryTarget contains "groupPolicyContainer"
or AdditionalFields has "gpLink" or AdditionalFields has "gPCFileSysPath"
| summarize
QueryCount = count(),
UniqueDCs = dcount(DestinationDeviceName),
FirstQuery = min(TimeGenerated),
LastQuery = max(TimeGenerated)
by AccountName, AccountDomain, DeviceName, QueryType
| where QueryCount > 3
| order by QueryCount desc index=* sourcetype="WinEventLog:Security" EventCode=4662
| search ObjectType="groupPolicyContainer"
| where NOT match(SubjectUserName, "(?i)(dfsr|krbtgt|\\$$)")
| stats count as access_count, dc(ObjectName) as unique_gpo_count by SubjectUserName, SubjectDomainName, IpAddress
| where access_count > 5
| sort - access_count Correlates GPO discovery events with subsequent lateral movement (network/remote interactive logons) by the same account within 4 hours on different hosts. This hunt identifies the reconnaissance-to-lateral-movement chain characteristic of post-compromise domain attacks.
// Hunt for bulk GPO enumeration correlated with subsequent lateral movement indicators
let GPODiscovery = DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where (FileName =~ "gpresult.exe"
or (FileName in~ ("powershell.exe", "pwsh.exe")
and ProcessCommandLine has_any ("Get-DomainGPO", "Get-NetGPO", "Get-GPO", "Get-GPResultantSetOfPolicy")))
| summarize GPODiscoveryTime = min(TimeGenerated) by DeviceName, AccountName;
DeviceLogonEvents
| where TimeGenerated > ago(7d)
| where LogonType in ("RemoteInteractive", "Network")
| where ActionType == "LogonSuccess"
| join kind=inner GPODiscovery on AccountName
| where TimeGenerated > GPODiscoveryTime
| where TimeGenerated < datetime_add('hour', 4, GPODiscoveryTime)
| where DeviceName != DeviceName1
| project
TimeGenerated,
SourceDevice = DeviceName1,
TargetDevice = DeviceName,
AccountName,
LogonType,
RemoteIPType,
GPODiscoveryTime index=* sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
(match(Image, "(?i)gpresult\.exe") OR (match(Image, "(?i)(powershell|pwsh)\.exe") AND match(CommandLine, "(?i)(get-domaingpo|get-netgpo|get-gpo|gpresultantsetofpolicy)")))
| eval gpo_discovery_time=_time, source_host=Computer, discovery_user=User
| table gpo_discovery_time, source_host, discovery_user
| join type=inner discovery_user [
search index=* sourcetype="WinEventLog:Security" EventCode=4624 LogonType IN (3, 10)
| eval lateral_time=_time, target_host=Computer, lateral_user=TargetUserName
| table lateral_time, target_host, lateral_user
| rename lateral_user as discovery_user
]
| where lateral_time > gpo_discovery_time AND lateral_time < gpo_discovery_time + 14400
| table gpo_discovery_time, source_host, target_host, discovery_user, lateral_time Atomic Red Team Tests
Simulates adversary use of the built-in gpresult.exe utility to dump all applied Group Policy settings for the current user and computer. This is the simplest and most common GPO discovery technique observed in Turla and other APT campaigns.
Command
gpresult /z /scope computer > C:\Temp\gpo_computer.txt
gpresult /z /scope user > C:\Temp\gpo_user.txt
type C:\Temp\gpo_computer.txt Cleanup
del C:\Temp\gpo_computer.txt /f /q 2>nul
del C:\Temp\gpo_user.txt /f /q 2>nul Expected Telemetry
Sysmon EventCode=1: Image=gpresult.exe with CommandLine containing /z and /scope. Security EventID=4688 if process creation auditing enabled with command line logging. File creation event for C:\Temp\gpo_computer.txt (Sysmon EventCode=11).
Expected Detection
KQL/SPL alert on gpresult.exe process creation where parent process is cmd.exe or PowerShell rather than a known admin tool.
Simulates attacker use of PowerView's Get-DomainGPO function (part of PowerSploit/Empire frameworks) to enumerate all GPOs in the domain. This is the technique used by adversaries leveraging Empire and BloodHound-adjacent tooling for AD reconnaissance. Requires domain connectivity.
Command
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "
$WebClient = New-Object System.Net.WebClient;
# In a real test, PowerView would be loaded from attacker infra. For atomic test, use local copy:
IEX (Get-Content .\PowerView.ps1 -Raw);
Get-DomainGPO | Select-Object displayname, gpcfilesyspath | Format-List
" Cleanup
Remove-Item .\PowerView.ps1 -Force -ErrorAction SilentlyContinue
Clear-History Expected Telemetry
Sysmon EventCode=1: powershell.exe with CommandLine containing Get-DomainGPO. PowerShell Script Block Logging (EventID 4104) capturing the full IEX expression and Get-DomainGPO function body. Sysmon EventCode=3 for LDAP connections to domain controllers (port 389) from powershell.exe.
Expected Detection
KQL/SPL alert matching powershell.exe ProcessCommandLine containing 'Get-DomainGPO'. PowerShell script block logging alert on suspicious module load patterns from Empire/PowerSploit.
Simulates an attacker with local admin or domain user privileges using built-in RSAT Group Policy cmdlets to enumerate all GPOs. Unlike PowerView, this uses Microsoft's own RSAT module, making it harder to detect based on script signatures. Requires RSAT Group Policy Management Tools to be installed.
Command
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "
Import-Module GroupPolicy -ErrorAction Stop;
Get-GPO -All | Select-Object DisplayName, Id, GpoStatus, CreationTime, ModificationTime | Format-Table -AutoSize;
Get-GPResultantSetOfPolicy -ReportType Html -Path C:\Temp\rsop_report.html -Computer $env:COMPUTERNAME;
Write-Host 'GPO enumeration complete. Report saved to C:\Temp\rsop_report.html'
" Cleanup
Remove-Item C:\Temp\rsop_report.html -Force -ErrorAction SilentlyContinue Expected Telemetry
Sysmon EventCode=1: powershell.exe with CommandLine containing 'Get-GPO' and 'Get-GPResultantSetOfPolicy'. PowerShell EventID 4103/4104 capturing module import of GroupPolicy and cmdlet invocations. Sysmon EventCode=11 for HTML report file creation at C:\Temp\rsop_report.html. LDAP traffic to domain controllers for GPO object queries.
Expected Detection
KQL/SPL alert on powershell.exe ProcessCommandLine containing 'Get-GPResultantSetOfPolicy' or 'Get-GPO'. File creation alert for rsop_report.html in non-standard location.