projectdiscovery/nuclei · error
DsGetNCChanges: %w
Error message
DsGetNCChanges: %w
What it means
DsGetNCChanges is the core DCSync replication call that returns the secret material for the resolved DN. A wrapped failure here almost always means the DC refused replication — the classic cause is the missing 'Replicating Directory Changes' / '... All' extended right on the domain head. Other causes are an invalid DN pair or replication being administratively blocked.
Source
Thrown at pkg/js/libs/secretsdump/secretsdump.go:164
return nil, fmt.Errorf("ds domain dn: %w", err)
}
// Resolve target -> DN if it doesn't already look like one.
userDN := target
if len(target) < 3 || (target[:3] != "CN=" && target[:3] != "cn=") {
cracked, err := gpdrs.DsCrackNames(rpc, bind.Handle, 7 /* DS_NT4_ACCOUNT_NAME */, 1 /* DS_FQDN_1779_NAME */, []string{c.Domain + "\\" + target})
if err != nil || len(cracked) == 0 || cracked[0].Name == "" {
cracked, err = gpdrs.DsCrackNames(rpc, bind.Handle, 11 /* DS_UNIQUE_ID_NAME (SID) */, 1, []string{target})
if err != nil || len(cracked) == 0 || cracked[0].Name == "" {
return nil, fmt.Errorf("could not resolve %q to a DN", target)
}
}
userDN = cracked[0].Name
}
res, err := gpdrs.DsGetNCChanges(rpc, bind.Handle, domainDN, userDN, dcInfo.NtdsDsaObjectGuid, rpc.GetSessionKey())
if err != nil {
return nil, fmt.Errorf("DsGetNCChanges: %w", err)
}
if len(res.Objects) == 0 {
return nil, fmt.Errorf("DsGetNCChanges returned no objects")
}
o := res.Objects[0]
out := &Secret{
SAMAccountName: o.SAMAccountName,
DistinguishedName: o.DN,
RID: o.RID,
NTHash: hex.EncodeToString(o.NTHash),
LMHash: hex.EncodeToString(o.LMHash),
UserAccountControl: o.UserAccountControl,
PwdLastSet: o.PwdLastSet,
}
for _, h := range o.NTHashHistory {
out.NTHashHistory = append(out.NTHashHistory, hex.EncodeToString(h))
}
for _, h := range o.LMHashHistory {View on GitHub (pinned to 265b3a3dec)
Solutions
- Use Domain Admin (or SYSTEM on a DC) credentials
- Grant the ACE to the account: dsacls 'DC=acme,DC=local' /G acme\\user:CA;'Replicating Directory Changes All';
- Double-check the target DN from the crack-names result instead of hand-crafting it
- Inspect the wrapped RPC fault text for access-denied versus invalid-DN hints
Defensive patterns
Strategy: try-catch
Try / catch
secret, err := c.DCSync(target)
if err != nil && strings.Contains(err.Error(), "DsGetNCChanges:") {
// replication denied: verify/obtain 'Replicating Directory Changes (All)' rights
return err
} Prevention
- Prove replication rights (Domain Admin or explicit ACE) before chaining DCSync
- Sync a canary principal (krbtgt) once to validate rights early
- Read the wrapped fault: access-denied points to rights, invalid-DN to path bugs
When it happens
Trigger: Syncing any principal with a plain domain user (no replication ACE); syncing sensitive principals like krbtgt where 'Replicating Directory Changes All' is required; passing a hand-built DN that does not exist under the domain NC.
Common situations: Testing with a non-privileged account captured during a engagement; permissions revoked between recon and exploitation; templates assuming Domain Admin rights on a delegated account.
Related errors
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/cea1396533046e9b.
Report an issue: GitHub.