Conversation
Exploit the AD CS certificate-enrollment "cdc chase" fallback (CVE-2026-54121) so a low-privileged domain user can obtain a certificate impersonating a Domain Controller and recover its NT hash. The CA trusts two requester-supplied enrollment attributes -- cdc (the host the CA connects to for directory data) and rmd (the DC principal to look up there) -- without verifying the cdc host is a real DC. - lib/certificate.py: create_csr_attributes() gains a backward-compatible request_attributes parameter - lib/req.py: Request accepts cdc/rmd/request_attribute and threads them into the enrollment attribute list (RPC/DCOM/Web uniformly) - commands/parsers/req.py: -cdc / -rmd / -request-attribute flags - lib/rogue.py: rogue DC-identity oracle (RogueServer) -- rogue LDAP + SMB/LSA with NetLogon pass-through - commands/chase.py + commands/parsers/chase.py: the chase command, reusing Account, Request and Authenticate - commands/parsers/__init__.py: register chase Credit: @H0j3n and @aniqfakhrul (vulnerability research and PoC).
…bugs Follow-up to the CVE-2026-54121 (Certighost) chase feature: align it with Certipy's conventions and fix defects in the rogue DC-identity oracle. lib/rogue.py: - conn.send -> conn.sendall to avoid silently truncated sealed responses - tear down the NetLogon secure channel per bind (NLOracle.disconnect in a finally) instead of leaking a DCE connection to the DC on every callback - split the blocking run_lsa into build_smb_lsa so RogueServer.shutdown can actually stop the SMB/LSA listener; add clean bind-failure handling - raise load-bearing failures (NetLogon rejection, bind errors) from debug to logging.warning + handle_error, matching the project error convention style/conventions: - module docstring form, parenthesized multi-line help, lowercase metavars, the standard add_subparser docstring paragraph and a fuller class docstring - server-only wait via threading.Event instead of a busy sleep loop Lint/type gates (flake8 ./certipy, isort, black, pyright) pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds support for CVE-2026-54121 ("Certighost"), an AD CS
elevation-of-privilege vulnerability (CVSS 8.8, patched July 2026) that lets a
low-privileged domain user obtain a certificate impersonating a Domain
Controller and recover the DC's NT hash.
The vulnerable code path is the AD CS enrollment "cdc chase" fallback: the CA
trusts two requester-supplied enrollment attributes —
cdc(the host the CAconnects to for directory data) and
rmd(the DC principal to look up there) —without verifying that the
cdchost is a legitimate DC. By pointingcdcat anattacker-controlled oracle that returns a target DC's identity, the CA issues a
certificate bound to the DC.
Credit for the vulnerability research and the original PoC goes to
@h0j3n and
@aniqfakhrul.
What's added
New
certipy chasecommand — orchestrates the full attack, reusing existingCertipy primitives:
Account.pass-through) that authenticates the CA callback as the machine account but
answers directory lookups with the target DC's identity.
cdc/rmdset, reusingRequest.Authenticate.Modes:
-server-only(just run the oracle and print the matchingcertipy reqcommand),
-no-pkinit(stop after the certificate),-computer-name/-computer-pass/-computer-hash(reuse an account),
-target-account(choose the DC),-listener,-template(default
Machine),-web/-dcomtransports.certipy reqgains generic request attributes —-cdc,-rmd, and arepeatable
-request-attribute key:value, appended verbatim to the enrollmentattribute blob, so the request half of the attack can also be driven manually
against a separately-run oracle.
Files
certipy/lib/certificate.py—create_csr_attributes()gains a trailing,backward-compatible
request_attributesparam.certipy/lib/req.py—Requestacceptscdc/rmd/request_attribute.certipy/commands/parsers/req.py— new-cdc/-rmd/-request-attributeflags.certipy/lib/rogue.py— new: the rogue DC-identity oracle (RogueServer).certipy/commands/chase.py+certipy/commands/parsers/chase.py— new: the command.certipy/commands/parsers/__init__.py— registerschase.Testing
Requires a lab AD CS deployment with the chase fallback enabled
(
EDITF_ENABLECHASECLIENTDC) on an unpatched CA, a template built from AD /DNS name flags (e.g. the default
Machinetemplate), and a domain account withmachine-account-quota > 0. Run from a Linux host (root, for ports 389/445):
Lint/type gates (
flake8 ./certipy,isort --check,black --check,pyright)pass.
Notes
_ValidateChaseTargetIsDC. Mitigationon unpatched CAs:
certutil -setreg policy\EditFlags -EDITF_ENABLECHASECLIENTDC.lib/rogue.pyis a near-verbatim port of the disclosed PoC's protocol logic,restructured into a typed, logged library class; no new third-party deps.
References