Many organizations rely on Microsoft Active Directory to manage users, computers, logins, and access permissions. Domain Controllers are the central systems that enforce these decisions.
In many environments, Active Directory Certificate Services is used alongside Active Directory to issue digital certificates to users and computers. These certificates act as proof of identity and can be used for authentication.
Certighost (CVE-2026-54121) allows a low-privileged domain user to trick Active Directory Certificate Services into issuing a certificate that identifies the attacker as a Domain Controller. On a vulnerable system, the attacker can use this certificate to authenticate as the Domain Controller and ultimately extract credentials for every account in the domain, including domain administrators and the krbtgt account.
We reproduced the complete attack end-to-end in a controlled lab. This post first explains how the vulnerability works and then walks through every step of the exploit, from the initial machine account creation to Domain Controller impersonation and DCSync. We also show which traces each step leaves in Certificate Authority, Domain Controller, and network logs.
The final part maps seven Sigma rules to the attack timeline. For each rule, we explain when it would have triggered during our exploit, which event or behavior caused the match, and why that activity is suspicious. We also cover the logging settings required to generate these events, a read-only checker for assessing exposure, and the available remediation options.
Technical Analysis of Certighost
The following sections examine the vulnerable Certificate Authority configuration, the complete exploit chain, and the activity it generates across the affected systems.
The vulnerability requires an optional but commonly found CA configuration flag: EDITF_ENABLECHASECLIENTDC (bit 0x00100000 in EditFlags). When set, the CA honors a requester-supplied cdc (Client DC) attribute in certificate requests. This attribute was designed for cross-domain/cross-forest enrollment scenarios, letting a client in a child domain tell the CA which DC to contact for identity lookups when the CA cannot reach that domain directly.
The problem is that on unpatched systems there is no validation that the cdc value actually resolves to a real Domain Controller – the CA connects to whatever address the requester supplies. A detailed technical writeup of the vulnerability mechanics is available here. To check whether a CA has the flag enabled, run the following on the CA server:
certutil -getreg policy\EditFlags
If the flag is active, the output will explicitly name it:
If EDITF_ENABLECHASECLIENTDC does not appear in the output, the chase fallback is disabled and the CA is not vulnerable through this path.
July 2026 patch adds _ValidateChaseTargetIsDC, which rejects any cdc value that does not resolve to a legitimate DC object in Active Directory (a computer with the SERVER_TRUST_ACCOUNT / 0x2000 userAccountControl bit set) before following the chase.
How the Attack/Exploit Works
The full attack chain from zero to DCSync has six stages. A public PoC is available at aniqfakhrul/CVE-2026-54121.
Stage 0 – Create a Ghost Machine Account
Active Directory allows any domain user to create up to 10 machine accounts by default (ms-DS-MachineAccountQuota = 10). The attacker creates a throwaway account – GHOST<random>$ – using tools like impacket-addcomputer or New-MachineAccount. This account has no special privileges; it is only needed to submit an authenticated certificate request.
Stage 1 – Submit the Malicious Certificate Request
The ghost account sends a certificate request to the CA with two non-standard attributes:
cdc: <attacker_ip_or_domain> # IP or domain the CA should contact for identity lookup rmd: <target_dc_fqdn> # principal to look up at that address
The Subject Alternative Name in the request specifies the target DC’s FQDN:
SubjectAlternativeName: DNS Name=DC-01.domain.com
This is the critical mismatch: the requester is a ghost account, but the requested identity is the DC’s. From the attacker’s perspective this is a single operation – the PoC sends the request and blocks waiting for the certificate to be returned. Stages 2-4 below happen inside that same enrollment transaction, typically completing within seconds.
Stage 2 – CA Connects to the Attacker’s Rogue Services
Because EDITF_ENABLECHASECLIENTDC is set, the CA follows the cdc address. It opens an outbound SMB (445) and LDAP (389) connection to the attacker’s IP. Under normal operation, certsrv.exe never makes outbound connections to arbitrary hosts except its own DCs in cross-domain enrollment scenarios – it resolves identities via LDAP to local DCs, not arbitrary hosts. Any outbound SMB or LDAP from the CA process to an unknown address is suspicious.
Stage 3 – Rogue Server Returns a Forged DC Identity
The attacker runs rogue LDAP and SMB services on their machine. When the CA queries for the identity of DC-01.domain.com, the rogue server responds with DC-01’s SID, DNS name, and attributes. The unpatched CA accepts this response without cross-checking it against Active Directory.
Stage 4 – Certificate Issued with DC Identity
The CA issues a certificate carrying DC-01’s identity. At this point the attacker holds a certificate that Kerberos will accept as proof of DC-01’s identity via PKINIT (pre-authentication type 16/17).
Stage 5 – PKINIT: Authenticate as the DC
Using the forged certificate, the attacker performs PKINIT (Kerberos pre-authentication type 16, PA-PK-AS-REQ) from their own workstation, requesting a TGT as DC-01$. The KDC validates the certificate, finds a matching DC object, and issues a legitimate TGT for DC-01$ to the attacker’s machine.
This is where the PoC ends. The attacker now holds a valid Kerberos TGT for a Domain Controller machine account, issued to a workstation IP.
Stage 6 – DCSync: Replicate All Secrets
DCSync is a separate step. The PoC writes the obtained TGT to a ccache file which is then passed to secretsdump via the KRB5CCNAME environment variable:
export KRB5CCNAME=/home/ubuntu/CVE-2026-54121/dc-01.ccache
python3 secretsdump.py \
-k -no-pass \
-dc-ip 172.31.6.247 \
'DC-01$@DC-01.midgardnet.tech'
-k instructs secretsdump to use Kerberos authentication from the ccache rather than a password or hash. The tool requests a service ticket for DRSUAPI (the Directory Replication Service interface) and calls DRSGetNCChanges to pull all account hashes from the DC – including krbtgt, which enables Golden Ticket attacks, and all domain admin hashes.
This is standard DCSync behaviour; the only difference is that the TGT was obtained via a forged certificate rather than a stolen password or hash.
Building the Vulnerable Lab
Before writing a single detection rule, the attack had to be reproduced end-to-end in a controlled environment. This section documents what was needed to make a system vulnerable and confirms what an attacker must find before exploitation is possible.
Lab topology:
- Windows Server 2022 Domain Controller –
DC-01.midgardnet.tech(172.31.6.247) - Windows Server 2022 CA – ADCS role installed on the DC itself
- Ubuntu attacker machine –
172.31.40.101, running the PoC
Making the CA Vulnerable
Two steps were needed after installing the ADCS role:
1. Enable the chase fallback flag.
EDITF_ENABLECHASECLIENTDC was not set in the lab and had to be explicitly enabled:
certutil -setreg policy\EditFlags +EDITF_ENABLECHASECLIENTDC net stop CertSvc & net start CertSvc
Confirming it is set (see screenshot above):
2. Restart the CA service after the ADCS role install.
A common mistake during lab setup: installing the ADCS role and immediately enrolling without restarting. The CA might not be fully operational until the service has started at least once after role configuration. Certificate operations silently fail until this happens.
Checking Your Exposure
To avoid guessing, a read-only Python checker was written that assesses the three prerequisites required for exploitation without creating any accounts or requesting any certificates.
python3 check_certighost.py -d lab.local -u lowuser -p 'Password1!' --dc-ip 192.168.1.10
The checker performs three checks over LDAP and remote registry (SMB/RRP):
Check 1 – ms-DS-MachineAccountQuota
Reads the domain object via LDAP. A quota above zero means any domain user can create the ghost machine account needed to submit the certificate request.
Check 2 – EDITF_ENABLECHASECLIENTDC
Connects to the CA’s remote registry via ncacn_np (named pipe \pipe\winreg) and reads:
HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA name>\
PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\EditFlags
Checks bit 0x00100000. The CA name is auto-discovered by enumerating registry subkeys, falling back to the CDP container and certificationAuthority LDAP objects if the enrollment services container is empty.
Check 3 – Machine template enrollment rights
Searches CN=Certificate Templates,CN=Public Key Services,CN=Services,<ConfigDN> for the Machine template. Checks the nTSecurityDescriptor for the Certificate-Enrollment extended right GUID (0e10c968-78fb-11d2-90d4-00c04f79dc55). If the SD is unreadable (low-priv user), falls back to a schema heuristic: the default Machine template (schema v1, RA signatures = 0) ships with Domain Computers having Enroll rights unless that ACE was explicitly removed.
Sample output – vulnerable system:
The checker is a read-only vulnerability assessment script – no accounts created, no certificates requested. The checker is available at GitHub.
Research: Capturing the Evidence
With the lab confirmed vulnerable, the PoC was run and every event captured across the CA, DC, and network layers.
Key Discovery – Two-Layer ADCS Auditing
The most important operational finding during the research was that EventID 4886 and 4887 require two independent controls, both of which must be active. GPO alone is not sufficient: without bit 0x04 (AUDIT_CERTSRV_REQUESTFLAGS) set in CA\AuditFilter, certsrv.exe never calls ReportEvent() for certificate operations regardless of OS policy. The full configuration steps are in Enabling the Logging below.
After both controls were in place, running the PoC produced EventID 4886 (certificate requested) and EventID 4887 (certificate issued) on the CA in quick succession.
EventID 4886 – Certificate Request:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4886</EventID><Version>1</Version><Level>0</Level><Task>12805</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:19.7844703Z'/><EventRecordID>973242</EventRecordID><Correlation ActivityID='{58a91e5c-1fec-0001-c81e-a958ec1fdd01}'/><Execution ProcessID='696' ThreadID='2076'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='RequestId'>6</Data><Data Name='Requester'>MIDGARDNET\GHOSTVZBVHNRM$</Data><Data Name='Attributes'>CertificateTemplate:Machine
SAN:dns=DC-01.midgardnet.tech
cdc:172.31.40.101
rmd:DC-01.midgardnet.tech</Data><Data Name='Subject'>CN=GHOSTVZBVHNRM.midgardnet.tech</Data><Data Name='SubjectAlternativeName'>DNS Name=DC-01.midgardnet.tech
</Data><Data Name='CertificateTemplate'>Machine</Data><Data Name='RequestOSVersion'></Data><Data Name='RequestCSPProvider'></Data><Data Name='RequestClientInfo'></Data><Data Name='AuthenticationService'>NTLM</Data><Data Name='AuthenticationLevel'>Privacy</Data><Data Name='DCOMorRPC'>RPC</Data></EventData></Event>
Three signals stand out immediately: the requester is a ghost machine account (GHOST*$), cdc: points to a non-DC value, and the SAN carries a DC’s DNS name rather than the requester’s own hostname. The issuance event (EventID 4887) confirms the CA followed the chase and accepted the forged identity – the attacker now holds a valid certificate for DC-01.midgardnet.tech. The full log is covered under Rule 4 in the Detection Coverage section below.
Simultaneously, Sysmon EventID 3 (network connection) captured:
Image: C:\Windows\System32\certsrv.exe Initiated: true DestinationIp: 172.31.40.101 DestinationPort: 389
certsrv.exe making an outbound LDAP connection to the attacker’s IP – confirming the chase happened at the network layer independently of any CA-side audit logging.
Detection Coverage
Seven Sigma rules were written to cover the full attack chain. The rules use |expand placeholders so defenders can populate them with their environment’s DC IPs, DC machine accounts, and provisioning account lists without modifying rule logic.
Rule 1 – Ghost Machine Account Creation (T+0)
EventID 4741 – fires specifically on machine accounts whose name starts with GHOST and ends with $, matching the naming convention used by the Certighost PoC (GHOST<random>$). Unlike a generic “domain user creates machine account” rule, scoping to the GHOST prefix makes this virtually FP-free – no legitimate provisioning workflow uses that prefix. This is a tool-specific indicator rather than a behavioural one, but given the PoC is the primary known exploit for this path it provides high-confidence early warning.
detection:
selection:
EventID: 4741
TargetUserName|startswith: 'GHOST'
TargetUserName|endswith: '$'
condition: selection
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4741</EventID><Version>0</Version><Level>0</Level><Task>13825</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:18.3966102Z'/><EventRecordID>973234</EventRecordID><Correlation ActivityID='{58a91e5c-1fec-0001-c81e-a958ec1fdd01}'/><Execution ProcessID='696' ThreadID='3016'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='TargetUserName'>GHOSTVZBVHNRM$</Data><Data Name='TargetDomainName'>MIDGARDNET</Data><Data Name='TargetSid'>S-1-5-21-1938467512-983293709-721003795-1119</Data><Data Name='SubjectUserSid'>S-1-5-21-1938467512-983293709-721003795-1103</Data><Data Name='SubjectUserName'>SwachchhandaP</Data><Data Name='SubjectDomainName'>MIDGARDNET</Data><Data Name='SubjectLogonId'>0xa1e8ec</Data><Data Name='PrivilegeList'>SeMachineAccountPrivilege</Data><Data Name='SamAccountName'>GHOSTVZBVHNRM$</Data><Data Name='DisplayName'>%%1793</Data><Data Name='UserPrincipalName'>-</Data><Data Name='HomeDirectory'>%%1793</Data><Data Name='HomePath'>%%1793</Data><Data Name='ScriptPath'>%%1793</Data><Data Name='ProfilePath'>%%1793</Data><Data Name='UserWorkstations'>%%1793</Data><Data Name='PasswordLastSet'>%%1794</Data><Data Name='AccountExpires'>%%1794</Data><Data Name='PrimaryGroupId'>515</Data><Data Name='AllowedToDelegateTo'>-</Data><Data Name='OldUacValue'>0x0</Data><Data Name='NewUacValue'>0x84</Data><Data Name='UserAccountControl'>
%%2082
%%2087</Data><Data Name='UserParameters'>%%1792</Data><Data Name='SidHistory'>-</Data><Data Name='LogonHours'>%%1793</Data><Data Name='DnsHostName'>-</Data><Data Name='ServicePrincipalNames'>-</Data></EventData></Event>
Rule 2 – Certificate Request with CDC Chase Attribute (T+1)
EventID 4886 – the most specific Certighost indicator. Fires when a cert request carries a cdc: attribute pointing to a value not in %known_cdcs%. In a patched environment this rule covers any attempt even if it fails. In an unpatched environment it fires immediately before the cert is issued.
The Attributes field in a malicious request looks like:
CertificateTemplate:Machine SAN:dns=<target-dc-fqdn> cdc:<attacker-ip-or-domain> rmd:<target-dc-fqdn>
The cdc: value is the attacker’s IP; rmd: is the target DC’s FQDN. The filter suppresses this event only when cdc: points to a known DC hostname or IP – any other value fires the alert.
%known_cdcs% should be populated with the hostnames and IP addresses of all Domain Controllers in the environment. In a cross-domain/cross-forest setup with EDITF_ENABLECHASECLIENTDC intentionally configured, cdc: pointing to one of these values is a legitimate enrollment and should not alert.
detection:
selection:
EventID: 4886
Attributes|contains: 'cdc:'
filter_main_known_cdc:
Attributes|contains|expand: '%known_cdcs%'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4886</EventID><Version>1</Version><Level>0</Level><Task>12805</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:19.7844703Z'/><EventRecordID>973242</EventRecordID><Correlation ActivityID='{58a91e5c-1fec-0001-c81e-a958ec1fdd01}'/><Execution ProcessID='696' ThreadID='2076'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='RequestId'>6</Data><Data Name='Requester'>MIDGARDNET\GHOSTVZBVHNRM$</Data><Data Name='Attributes'>CertificateTemplate:Machine
SAN:dns=DC-01.midgardnet.tech
cdc:172.31.40.101
rmd:DC-01.midgardnet.tech</Data><Data Name='Subject'>CN=GHOSTVZBVHNRM.midgardnet.tech</Data><Data Name='SubjectAlternativeName'>DNS Name=DC-01.midgardnet.tech
</Data><Data Name='CertificateTemplate'>Machine</Data><Data Name='RequestOSVersion'></Data><Data Name='RequestCSPProvider'></Data><Data Name='RequestClientInfo'></Data><Data Name='AuthenticationService'>NTLM</Data><Data Name='AuthenticationLevel'>Privacy</Data><Data Name='DCOMorRPC'>RPC</Data></EventData></Event>
Rule 3 – Certificate Services Outbound SMB/LDAP (T+2)
Sysmon network_connection – certsrv.exe initiating an outbound connection on port 389 or 445 to a non-loopback, non-DC host. This is a network-layer corroboration of the chase. Notably, this rule is not Certighost-specific: any future vulnerability or misconfiguration that causes the CA process to reach out to an arbitrary host will trigger it.
%legit_ips% should contain IPs that certsrv.exe is permitted to connect to – typically Domain Controllers and any LDAP servers in a multi-CA or cross-forest setup. Leave it empty to alert on all outbound certsrv.exe connections except loopback.
detection:
selection:
Image|endswith: '\certsrv.exe'
Initiated: 'true'
DestinationPort:
- 389
- 445
filter_main_loopback:
DestinationIp:
- '127.0.0.1'
- '::1'
- '0:0:0:0:0:0:0:1'
filter_main_known_legit_ips:
DestinationIp|expand: '%legit_ips%'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Sysmon' Guid='{5770385f-c22a-43e0-bf4c-06f5698ffbd9}'/><EventID>3</EventID><Version>5</Version><Level>4</Level><Task>3</Task><Opcode>0</Opcode><Keywords>0x8000000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:21.3166476Z'/><EventRecordID>602558</EventRecordID><Correlation/><Execution ProcessID='3228' ThreadID='4584'/><Channel>Microsoft-Windows-Sysmon/Operational</Channel><Computer>DC-01.midgardnet.tech</Computer><Security UserID='S-1-5-18'/></System><EventData><Data Name='RuleName'>-</Data><Data Name='UtcTime'>2026-07-30 11:03:19.385</Data><Data Name='ProcessGuid'>{b09f0141-eea1-6a6a-3f00-000000005d02}</Data><Data Name='ProcessId'>2948</Data><Data Name='Image'>C:\Windows\System32\certsrv.exe</Data><Data Name='User'>NT AUTHORITY\SYSTEM</Data><Data Name='Protocol'>tcp</Data><Data Name='Initiated'>true</Data><Data Name='SourceIsIpv6'>false</Data><Data Name='SourceIp'>172.31.6.247</Data><Data Name='SourceHostname'>DC-01.midgardnet.tech</Data><Data Name='SourcePort'>51637</Data><Data Name='SourcePortName'>-</Data><Data Name='DestinationIsIpv6'>false</Data><Data Name='DestinationIp'>172.31.40.101</Data><Data Name='DestinationHostname'>-</Data><Data Name='DestinationPort'>389</Data><Data Name='DestinationPortName'>ldap</Data></EventData></Event>
Rule 4 – Certificate Issued via CDC Chase (T+3)
EventID 4887 – the issuance counterpart to 4886. Fires when a cert containing cdc: or rmd: attributes is actually issued against a non-DC target. If this fires after Rule 2, the attacker has a valid DC certificate in hand. Uses the same %known_cdcs% filter as Rule 2 – same population applies.
detection:
selection:
EventID: 4887
Attributes|contains:
- 'cdc:'
- 'rmd:'
filter_main_known_cdc_ips:
Attributes|contains|expand: '%known_cdcs%'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4887</EventID><Version>1</Version><Level>0</Level><Task>12805</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:20.3064906Z'/><EventRecordID>973326</EventRecordID><Correlation ActivityID='{58a91e5c-1fec-0001-c81e-a958ec1fdd01}'/><Execution ProcessID='696' ThreadID='2076'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='RequestId'>6</Data><Data Name='Requester'>MIDGARDNET\GHOSTVZBVHNRM$</Data><Data Name='Attributes'>CertificateTemplate:Machine
SAN:dns=DC-01.midgardnet.tech
cdc:172.31.40.101
rmd:DC-01.midgardnet.tech</Data><Data Name='Disposition'>3</Data><Data Name='SubjectKeyIdentifier'>2b c2 18 68 f0 f4 9a 68 f8 af 59 d5 5c 05 1f 31 b4 27 a5 69</Data><Data Name='Subject'>CN=DC-01.midgardnet.tech</Data><Data Name='SubjectAlternativeName'>DNS Name=DC-01.midgardnet.tech
</Data><Data Name='CertificateTemplate'>Machine</Data><Data Name='SerialNumber'>190000000618c06b74cad19d54000000000006</Data><Data Name='AuthenticationService'>NTLM</Data><Data Name='AuthenticationLevel'>Privacy</Data><Data Name='DCOMorRPC'>RPC</Data></EventData></Event>
Rule 5 – DC Machine Account TGT Request from Non-DC IP (T+4)
EventID 4768 – a successful Kerberos TGT request for a known DC machine account originating from a workstation IP. This is the PKINIT step: the attacker authenticates as DC-01$ from their own machine using the forged certificate. DC machine accounts only request TGTs from their own IPs in
normal operations.
%dc_machine_accounts% should list all DC machine account names in the environment (e.g. DC-01$, DC-02$). These go in the selection – the rule only fires when the target account is a known DC. %dc_ip_addresses% lists the IPs those DCs are expected to authenticate from; requests originating from any other IP are anomalous.
The existing SigmaHQ rule PetitPotam Suspicious Kerberos TGT Request covers a similar pattern but fires on any machine account TGT from a non-DC IP. This rule is more precise – it scopes the selection to known DC machine accounts via
%dc_machine_accounts%, reducing noise in environments where non-DC machine accounts legitimately authenticate from varying IPs, while maintaining high-fidelity detection for the DC impersonation step specifically.
detection:
selection:
EventID: 4768
Status: '0x0'
TargetUserName|endswith: '$'
TargetUserName|expand: '%dc_machine_accounts%'
filter_main_dc_source:
IpAddress|expand: '%dc_ip_addresses%'
filter_main_loopback:
- IpAddress:
- '127.0.0.1'
- '::1'
- '::ffff:127.0.0.1'
- '-'
- IpAddress|startswith: 'fe80:'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4768</EventID><Version>2</Version><Level>0</Level><Task>14339</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:20.4057307Z'/><EventRecordID>973327</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='2192'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='TargetUserName'>DC-01$</Data><Data Name='TargetDomainName'>MIDGARDNET.TECH</Data><Data Name='TargetSid'>S-1-5-21-1938467512-983293709-721003795-1000</Data><Data Name='ServiceName'>krbtgt</Data><Data Name='ServiceSid'>S-1-5-21-1938467512-983293709-721003795-502</Data><Data Name='TicketOptions'>0x40800010</Data><Data Name='Status'>0x0</Data><Data Name='TicketEncryptionType'>0x12</Data><Data Name='PreAuthType'>16</Data><Data Name='IpAddress'>::ffff:172.31.40.101</Data><Data Name='IpPort'>42720</Data><Data Name='CertIssuerName'>MidgardNet-CA</Data><Data Name='CertSerialNumber'>190000000618C06B74CAD19D54000000000006</Data><Data Name='CertThumbprint'>57090E59EB53739C561AF6DC8A4EB586FB369E24</Data><Data Name='ResponseTicket'>fk0ObcNHDD6ojFEXhhhf3mHNmfe4cIJW3WtqSSxXSYE=</Data><Data Name='AccountSupportedEncryptionTypes'>0x1F (DES, RC4, AES128-SHA96, AES256-SHA96)</Data><Data Name='AccountAvailableKeys'>AES-SHA1, RC4</Data><Data Name='ServiceSupportedEncryptionTypes'>0x1F (DES, RC4, AES128-SHA96, AES256-SHA96)</Data><Data Name='ServiceAvailableKeys'>AES-SHA1, RC4</Data><Data Name='DCSupportedEncryptionTypes'>0x1F (DES, RC4, AES128-SHA96, AES256-SHA96)</Data><Data Name='DCAvailableKeys'>AES-SHA1, RC4</Data><Data Name='ClientAdvertizedEncryptionTypes'>
AES256-CTS-HMAC-SHA1-96
AES128-CTS-HMAC-SHA1-96</Data><Data Name='SessionKeyEncryptionType'>0x12</Data><Data Name='PreAuthEncryptionType'>0x0</Data></EventData></Event>
Rule 6 – DC Machine Account TGS Request from Non-DC IP (T+5)
EventID 4769 – a successful service ticket request targeting a DC machine account’s service from a workstation IP. This catches the step where the attacker, holding a DC TGT, requests a DRSUAPI ticket to perform DCSync. Unlike Silver Ticket attacks which forge the TGS and bypass this event entirely, attacks going through the KDC legitimately (as Certighost does after PKINIT) generate this event. %dc_machine_accounts% and %dc_ip_addresses% serve the same purpose as in Rule 5 – same population applies to both rules.
detection:
selection:
EventID: 4769
Status: '0x0'
ServiceName|endswith: '$'
ServiceName|expand: '%dc_machine_accounts%'
filter_main_dc_source:
IpAddress|expand: '%dc_ip_addresses%'
filter_main_loopback:
- IpAddress:
- '127.0.0.1'
- '::1'
- '::ffff:127.0.0.1'
- '-'
- IpAddress|startswith: 'fe80:'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4769</EventID><Version>2</Version><Level>0</Level><Task>14337</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:20.4257966Z'/><EventRecordID>973328</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='2192'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='TargetUserName'>dc-01$@MIDGARDNET.TECH</Data><Data Name='TargetDomainName'>MIDGARDNET.TECH</Data><Data Name='ServiceName'>DC-01$</Data><Data Name='ServiceSid'>S-1-5-21-1938467512-983293709-721003795-1000</Data><Data Name='TicketOptions'>0x40810018</Data><Data Name='TicketEncryptionType'>0x12</Data><Data Name='IpAddress'>::ffff:172.31.40.101</Data><Data Name='IpPort'>42728</Data><Data Name='Status'>0x0</Data><Data Name='LogonGuid'>{1547af17-0097-c1bc-cb48-e6ef800acc8d}</Data><Data Name='TransmittedServices'>-</Data><Data Name='RequestTicketHash'>fk0ObcNHDD6ojFEXhhhf3mHNmfe4cIJW3WtqSSxXSYE=</Data><Data Name='ResponseTicketHash'>CeAfJtUTzfh0V945SuMmYcCHlQ6DlKxMJiARln5THPY=</Data><Data Name='AccountSupportedEncryptionTypes'>N/A</Data><Data Name='AccountAvailableKeys'>N/A</Data><Data Name='ServiceSupportedEncryptionTypes'>0x1F (DES, RC4, AES128-SHA96, AES256-SHA96)</Data><Data Name='ServiceAvailableKeys'>AES-SHA1, RC4</Data><Data Name='DCSupportedEncryptionTypes'>0x1F (DES, RC4, AES128-SHA96, AES256-SHA96)</Data><Data Name='DCAvailableKeys'>AES-SHA1, RC4</Data><Data Name='ClientAdvertizedEncryptionTypes'>
AES256-CTS-HMAC-SHA1-96
RC4-HMAC-NT</Data><Data Name='SessionKeyEncryptionType'>0x12</Data></EventData></Event>
Rule 7 – DC Machine Account Logon from Non-DC IP (Post-exploitation)
EventID 4624 – a network logon for a known DC machine account from a non-DC source IP. Covers the end of the chain (DCSync attempt) as well as Silver Ticket, Pass-the-Ticket, and Overpass-the-Hash attacks that authenticate as a DC from a workstation. Level is critical – a DC machine account authenticating from a workstation has no legitimate explanation. Relies on the same %dc_machine_accounts% and %dc_ip_addresses% placeholders; if these are correctly populated, false positives are practically zero.
detection:
selection:
EventID: 4624
TargetUserName|endswith: '$'
TargetUserName|expand: '%dc_machine_accounts%'
filter_main_dc_source:
IpAddress|expand: '%dc_ip_addresses%'
filter_main_loopback:
- IpAddress:
- '127.0.0.1'
- '::1'
- '::ffff:127.0.0.1'
- '-'
- IpAddress|startswith: 'fe80:'
condition: selection and not 1 of filter_main_*
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4624</EventID><Version>2</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-29T07:25:15.8025835Z'/><EventRecordID>959507</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='3580'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-5-21-1938467512-983293709-721003795-1000</Data><Data Name='TargetUserName'>dc-01$</Data><Data Name='TargetDomainName'>MIDGARDNET.TECH</Data><Data Name='TargetLogonId'>0x15e321e</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>Kerberos</Data><Data Name='AuthenticationPackageName'>Kerberos</Data><Data Name='WorkstationName'>-</Data><Data Name='LogonGuid'>{e9d21ab1-0a46-3dec-9383-aa15fac2e811}</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>172.31.40.101</Data><Data Name='IpPort'>56956</Data><Data Name='ImpersonationLevel'>%%1833</Data><Data Name='RestrictedAdminMode'>-</Data><Data Name='TargetOutboundUserName'>-</Data><Data Name='TargetOutboundDomainName'>-</Data><Data Name='VirtualAccount'>%%1843</Data><Data Name='TargetLinkedLogonId'>0x0</Data><Data Name='ElevatedToken'>%%1842</Data></EventData></Event>
Bonus – NETLOGON Downgraded Secure Channel (EventID 5840)
During the chase, the CA’s identity lookup causes the ghost machine account to establish a Netlogon secure channel from the attacker’s IP to the DC. EventID 5840 (System log, NETLOGON provider) fires when this channel uses a downgraded or non-standard configuration – an anomaly that has no legitimate explanation for a machine account originating from a non-domain-joined host.
This event is not covered by a dedicated rule in this PR but serves as an additional corroborating signal. The key fields to look for: the machine account name (will match the ghost GHOST*$ account) and the source IP (attacker’s machine).
Log sample:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='NETLOGON'/><EventID Qualifiers='0'>5840</EventID><Version>0</Version><Level>3</Level><Task>0</Task><Opcode>0</Opcode><Keywords>0x80000000000000</Keywords><TimeCreated SystemTime='2026-07-30T11:03:20.0472224Z'/><EventRecordID>142440</EventRecordID><Correlation/><Execution ProcessID='0' ThreadID='0'/><Channel>System</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data>GHOSTVZBVHNRM$</Data><Data>midgardnet.tech.</Data><Data>Domain Member</Data><Data>172.31.40.101</Data><Data>600fffff</Data></EventData></Event>
Bonus – DCSync Replication Rights Abuse (EventID 4662)
When secretsdump calls DRSGetNCChanges, the DC logs EventID 4662 (Directory Service Access) for each replication rights exercise. The two GUIDs that matter are:
1131f6aa-9c07-11d1-f79f-00c04fc2dcd2– DS-Replication-Get-Changes1131f6ad-9c07-11d1-f79f-00c04fc2dcd2– DS-Replication-Get-Changes-All
These fire on the DC attributed to DC-01$ – the account the attacker is impersonating. The previous win_security_dcsync.yml (ID 611eab06) explicitly filtered machine accounts out for exactly this reason. In the PR that rule is deleted and replaced by two focused rules: win_security_ad_replication_machine_account.yml (which targets machine account replication, same rule ID) and the updated win_security_ad_replication_non_machine_account.yml (which remains scoped to non-machine accounts and is now critical). The detection YAML below corresponds to win_security_ad_replication_machine_account.yml.
SACL prerequisite. EventID 4662 requires two controls before it fires for a DCSync call:
auditpol /set /subcategory:"Directory Service Access" /success:enable- A SACL on the domain NC root object (
DC=midgardnet,DC=tech) auditing the replication right
GUIDs. Add this via ADSI Edit: navigate to the domain NC root > Properties > Security > Advanced > Auditing > add an ACE for Everyone, Type: Success, Applies to: This object only, rights: DS-Replication-Get-Changes + DS-Replication-Get-Changes-All.
Without both controls, DRSGetNCChanges calls from secretsdump produce no 4662 at all. In the initial lab run (before the SACL was configured), EventID 4662 fired only on the hourly replication schedule – secretsdump ran successfully and returned all hashes, but added zero extra events.
Key finding: SubjectUserSid distinguishes attack from legitimate replication.
After the SACL was added and secretsdump was re-run, the DCSync event appeared – but what was unexpected was that the two events are structurally distinguishable:
| Field | Scheduled replication (legitimate) | DCSync via secretsdump (attack) |
|---|---|---|
SubjectUserSid |
S-1-5-18 (SYSTEM) |
S-1-5-21-...-1000 (domain account SID) |
SubjectLogonId |
0x168d1f |
0x241360a |
| Timing | Exactly every hour | Random / on demand |
Legitimate scheduled replication runs as SYSTEM (S-1-5-18) on the DC. An attacker who obtained a TGT for DC-01$ via PKINIT and calls DRSUAPI from a workstation has a logon session under the actual domain account credential – producing S-1-5-21-...-1000 in SubjectUserSid. The SubjectLogonId in the attack event also ties back to the 4624 logon created when the TGT was used, making the session traceable in a SIEM.
Filtering out SYSTEM effectively eliminates the entire hourly replication noise, leaving only events that correspond to replication performed under a domain logon session – which is anomalous for a DC machine account. Note that multi-DC environments may generate additional false positives from legitimate cross-DC replication; this was not validated in the lab and should be evaluated in your own environment.
%dc_machine_accounts% further scopes the rule to known DC accounts so it does not fire on other machine accounts that might exercise replication rights.
detection:
selection:
EventID: 4662
Properties|contains:
- 'Replicating Directory Changes All' # DS-Replication-Get-Changes-All (human-readable)
- '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' # DS-Replication-Get-Changes-All
- '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' # DS-Replication-Get-Changes
- '9923a32a-3607-11d2-b9be-0000f87a36b2' # DS-Replication-Synchronize
- '89e95b76-444d-4c62-991a-0facbeda640c' # DS-Replication-Get-Changes-In-Filtered-Set
AccessMask: '0x100'
SubjectUserName|endswith: '$'
filter_main_subject_usersid:
SubjectUserSid|startswith: 'S-1-5-18'
condition: selection and not 1 of filter_main_*
Log sample – scheduled replication (suppressed by SYSTEM filter, SubjectUserSid: S-1-5-18):
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4662</EventID><Version>0</Version><Level>0</Level><Task>14080</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T13:41:42.7242411Z'/><EventRecordID>976333</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='812'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-5-18</Data><Data Name='SubjectUserName'>DC-01$</Data><Data Name='SubjectDomainName'>MIDGARDNET</Data><Data Name='SubjectLogonId'>0x168d1f</Data><Data Name='ObjectServer'>DS</Data><Data Name='ObjectType'>%{19195a5b-6da0-11d0-afd3-00c04fd930c9}</Data><Data Name='ObjectName'>%{c42580b9-0a6a-416b-ab87-dd271e16e87f}</Data><Data Name='OperationType'>Object Access</Data><Data Name='HandleId'>0x0</Data><Data Name='AccessList'>%%7688
</Data><Data Name='AccessMask'>0x100</Data><Data Name='Properties'>%%7688
{1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}
{19195a5b-6da0-11d0-afd3-00c04fd930c9}
</Data><Data Name='AdditionalInfo'>-</Data><Data Name='AdditionalInfo2'></Data></EventData></Event>
Log sample – DCSync via secretsdump (fires the rule, SubjectUserSid: S-1-5-21-...-1000):
A full DCSync generates two 4662 events in the same session (SubjectLogonId: 0x241360a) – one for each replication right exercised: DS-Replication-Get-Changes (1131f6aa):
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4662</EventID><Version>0</Version><Level>0</Level><Task>14080</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T14:24:08.2039174Z'/><EventRecordID>977157</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='812'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-5-21-1938467512-983293709-721003795-1000</Data><Data Name='SubjectUserName'>DC-01$</Data><Data Name='SubjectDomainName'>MIDGARDNET</Data><Data Name='SubjectLogonId'>0x241360a</Data><Data Name='ObjectServer'>DS</Data><Data Name='ObjectType'>%{19195a5b-6da0-11d0-afd3-00c04fd930c9}</Data><Data Name='ObjectName'>%{c42580b9-0a6a-416b-ab87-dd271e16e87f}</Data><Data Name='OperationType'>Object Access</Data><Data Name='HandleId'>0x0</Data><Data Name='AccessList'>%%7688
</Data><Data Name='AccessMask'>0x100</Data><Data Name='Properties'>%%7688
{1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}
{19195a5b-6da0-11d0-afd3-00c04fd930c9}
</Data><Data Name='AdditionalInfo'>-</Data><Data Name='AdditionalInfo2'></Data></EventData></Event>
DS-Replication-Get-Changes-All (1131f6ad) – the privileged right, same session:
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4662</EventID><Version>0</Version><Level>0</Level><Task>14080</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2026-07-30T14:24:08.4288124Z'/><EventRecordID>977192</EventRecordID><Correlation/><Execution ProcessID='696' ThreadID='812'/><Channel>Security</Channel><Computer>DC-01.midgardnet.tech</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-5-21-1938467512-983293709-721003795-1000</Data><Data Name='SubjectUserName'>DC-01$</Data><Data Name='SubjectDomainName'>MIDGARDNET</Data><Data Name='SubjectLogonId'>0x241360a</Data><Data Name='ObjectServer'>DS</Data><Data Name='ObjectType'>%{19195a5b-6da0-11d0-afd3-00c04fd930c9}</Data><Data Name='ObjectName'>%{c42580b9-0a6a-416b-ab87-dd271e16e87f}</Data><Data Name='OperationType'>Object Access</Data><Data Name='HandleId'>0x0</Data><Data Name='AccessList'>%%7688
</Data><Data Name='AccessMask'>0x100</Data><Data Name='Properties'>%%7688
{1131f6ad-9c07-11d1-f79f-00c04fc2dcd2}
{19195a5b-6da0-11d0-afd3-00c04fd930c9}
</Data><Data Name='AdditionalInfo'>-</Data><Data Name='AdditionalInfo2'></Data></EventData></Event>
Additional Rules That Fired in the Lab
Beyond the seven dedicated rules, several existing Sigma rules also triggered during the exploit run. These are not Certighost-specific but fire as a natural consequence of what the attack does at each layer.
| Rule | Event | Why it fired |
|---|---|---|
| Potential AD Recon/Enumeration Via LDAP | EventID 30, SearchFilter: (objectCategory=user) |
The PoC performs LDAP enumeration before launching the exploit – standard pre-attack reconnaissance |
| First Time Seen Remote Named Pipe | EventID 5145, ShareName: \\*\IPC$ |
The CA connects to the attacker’s rogue SMB service and accesses IPC$ during the identity lookup (T+2) |
| NTLMv1 Logon Between Client and Server | EventID 6038, Provider: LsaSrv |
The CA authenticates to the attacker’s rogue SMB using NTLMv1 during the chase – the rogue server deliberately accepts weak authentication |
| PetitPotam Suspicious Kerberos TGT Request | EventID 4768, CertThumbprint: '', TargetUserName | contains: $ |
The existing PetitPotam rule fires on the same TGT request as Rule 5, but with a broader condition (any machine account, empty cert thumbprint) |
| Startup State Changed For Remote Registry Service | Registry, TargetObject: \Services\RemoteRegistry\Start |
Fired when the Remote Registry service was started to run the vulnerability checker – not caused by the exploit itself (private Sigma rule in Nextron Valhalla feed) |
The LDAP reconnaissance, IPC$ named pipe access, and NTLMv1 authentication events cluster around T+1/T+2 and can be used for correlation even without the ADCS-specific logs. The NTLMv1 event is particularly notable – a well-hardened environment with NTLMv1 blocked would have prevented the CA from completing the identity lookup against the rogue server entirely.
Attack Chain – Rule Mapping
| Stage | What happens | Event |
|---|---|---|
| T+0 | Ghost machine account created | EventID 4741 |
| T+1 | Cert request with cdc: non-DC value |
EventID 4886 |
| T+2 | certsrv.exe connects to attacker LDAP/SMB |
Sysmon EventID 3 (network_connection) |
| T+3 | Cert issued with cdc:/rmd: attributes |
EventID 4887 |
| T+4 | DC machine account TGT from workstation IP | EventID 4768 |
| T+5 | DC machine account TGS from workstation IP | EventID 4769 |
| T+6 | DC machine account logon from workstation IP | EventID 4624 |
No single event is definitive in isolation; together they form a chain that is difficult to generate legitimately. A SIEM correlation across T+1 through T+4 within a short window is a near-certain indicator of exploitation.
Enabling the Logging
Rules 2 and 4 (EventID 4886/4887) require both controls to be active on the CA server:
# 1. Enable CA-side auditing (certsrv.exe must emit the events) certutil -setreg CA\AuditFilter 127 net stop CertSvc; net start CertSvc # 2. Enable OS-level audit subcategory auditpol /set /subcategory:"Certification Services" /success:enable
GPO alone (configuring the audit subcategory via Group Policy) is not sufficient – CA\AuditFilter must also be set. Without bit 0x04 (AUDIT_CERTSRV_REQUESTFLAGS) in AuditFilter, certsrv.exe never calls ReportEvent() for certificate operations regardless of OS policy. Rules 5-7 (EventID 4768/4769/4624) require Audit Kerberos Authentication Service and Audit Logon Events to be enabled on the DC – typically already active in most environments.
Rules
The rules are available in the SigmaHQ repository: https://github.com/SigmaHQ/sigma/pull/6190
Remediation
Two options exist to eliminate the attack path, in order of preference.
Option 1 – Disable the flag (recommended if cross-domain enrollment is not required):
certutil -setreg policy\EditFlags -EDITF_ENABLECHASECLIENTDC net stop CertSvc & net start CertSvc
Verify the flag is cleared:
certutil -getreg policy\EditFlags
EDITF_ENABLECHASECLIENTDC should no longer appear in the output. If your CA can reach all relevant DCs directly — the case in most single-forest environments — the flag is unnecessary and disabling it removes the attack surface entirely.
Option 2 – Apply the July 2026 patch (required if cross-domain/cross-forest enrollment is in use):
The July 2026 patch adds _ValidateChaseTargetIsDC, which validates the cdc value resolves to a legitimate DC object in Active Directory (SERVER_TRUST_ACCOUNT / userAccountControl 0x2000) before following the chase. This preserves the cross-domain enrollment use case while closing the exploit path — an attacker-supplied IP has no corresponding DC object in AD and is rejected.
On a patched system Rule 2 (EventID 4886) still fires on malicious requests, but Rule 4 (EventID 4887) will not follow since the certificate is never issued.









Tobias Michalski
Boris Deibel
Marius Benthin
Jonathan Peters