projectdiscovery/nuclei · error
could not resolve %q to a DN
Error message
could not resolve %q to a DN
What it means
DCSync's target must resolve to a distinguished name. If the argument does not already start with CN=, the code cracks it twice: first as an NT4 account name (DOMAIN\\user) and then as a SID. If both DsCrackNames attempts fail or return an empty name, the target does not exist (or cannot be cracked by this principal) and this error is returned.
Source
Thrown at pkg/js/libs/secretsdump/secretsdump.go:156
dcInfo, err := gpdrs.DsDomainControllerInfo(rpc, bind.Handle, c.Domain)
if err != nil {
return nil, fmt.Errorf("ds dc info: %w", err)
}
domainDN, err := gpdrs.GetDomainDN(rpc, bind.Handle, c.Domain)
if err != nil {
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),View on GitHub (pinned to 265b3a3dec)
Solutions
- Pass the exact sAMAccountName, e.g. DCSync('krbtgt')
- Or pass the full DN directly: DCSync('CN=Administrator,CN=Users,DC=acme,DC=local')
- Or pass the objectSid: DCSync('S-1-5-21-...-500')
- Verify the account exists with an LDAP search before syncing
Example fix
// before
const s = c.DCSync('administrator@acme.local'); // UPN form cannot be cracked
// after
const s = c.DCSync('Administrator'); Defensive patterns
Strategy: validation
Validate before calling
// Resolve or verify the target before DCSync
if !strings.HasPrefix(target, "CN=") && !strings.HasPrefix(target, "S-1-") {
// will be cracked as DOMAIN\\sAMAccountName — confirm it exists via LDAP first
if !samExists(dc, domain, target) {
return fmt.Errorf("target %q does not exist", target)
}
} Type guard
func isResolvableTarget(t string) bool {
return strings.HasPrefix(t, "CN=") || strings.HasPrefix(t, "cn=") ||
strings.HasPrefix(t, "S-1-") || !strings.Contains(t, "@")
} Try / catch
secret, err := c.DCSync(target)
if err != nil && strings.Contains(err.Error(), "could not resolve") {
// account name wrong or UPN form used: retry with sAMAccountName or SID
secret, err = c.DCSync(samFromSid(sid))
} Prevention
- Pass sAMAccountName or objectSid, never UPN (user@domain)
- Prefetch SIDs or DNs during recon and feed those into DCSync
- Treat crack-names failure as a signal to re-enumerate the account, not to retry blindly
When it happens
Trigger: DCSync('Admistrator') with a typo; DCSync('user@acme.local') — a UPN is neither the NT4 sAMAccountName form nor a SID; account lives in another trusted domain; caller lacks rights to crack names.
Common situations: UPN passed where sAMAccountName is expected; usernames harvested from email addresses; deleted or renamed accounts.
Related errors
- no input provider found
- could not create request: %s
- invalid ASRepRoastRequest: %w
- Username, Domain and KDCHost are required
- invalid KerberoastRequest: %w
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/9e9e98eea175c320.
Report an issue: GitHub.