Skip to content

fix: use target FQDN directly for Kerberos SPN when host is already fully qualified#6

Open
aconite33 wants to merge 1 commit intomainfrom
fix/kerberos-spn-fqdn-mismatch
Open

fix: use target FQDN directly for Kerberos SPN when host is already fully qualified#6
aconite33 wants to merge 1 commit intomainfrom
fix/kerberos-spn-fqdn-mismatch

Conversation

@aconite33
Copy link
Copy Markdown

Problem

When using Kerberos authentication (-k / --use-kcache) against a target specified as an FQDN, NXC reconstructs the remote name used for SPN lookup as {netbios_hostname}.{targetDomain} (smb.py:285):

self.remoteName = self.host if not self.kerberos else f"{self.hostname}.{self.targetDomain}"

This breaks in environments where a host's DNS suffix differs from the AD Kerberos realm. For example:

  • Target passed: host.example.com
  • NetBIOS name returned by SMB: HOST
  • Kerberos realm returned by SMB: domain.example.com
  • SPN NXC requests: cifs/host.domain.example.com@DOMAIN.EXAMPLE.COM
  • SPN registered in AD: cifs/host.example.com@DOMAIN.EXAMPLE.COM

The KDC returns KDC_ERR_S_PRINCIPAL_UNKNOWN because the reconstructed SPN doesn't match what the machine has registered. To make things worse, the return value of kerberos_login() is not checked in the --use-kcache path (connection.py), so NXC prints "Successfully authenticated using Kerberos cache" even after the failure and then hits a connection reset when trying to enumerate shares.

This is confirmed by Impacket's smbclient.py -k -debug, which shows it uses the target hostname as-is for the SPN and lets the KDC resolve it:

[+] SPN CIFS/HOST.EXAMPLE.COM@DOMAIN.EXAMPLE.COM not found in cache
[+] AnySPN is True, looking for another suitable SPN
[+] Returning cached credential for KRBTGT/DOMAIN.EXAMPLE.COM@DOMAIN.EXAMPLE.COM
[+] Using TGT from cache

Fix

When the target is already an FQDN (contains a dot), use it directly as remoteName so the SPN matches the host's actual AD registration. Only fall back to constructing {hostname}.{targetDomain} when a bare hostname (no dot) is passed, since there is no FQDN to use in that case.

self.remoteName = self.host if (not self.kerberos or "." in self.host) else f"{self.hostname}.{self.targetDomain}"

Test plan

  • nxc smb host.example.com -k --use-kcache --shares where host.example.com has a DNS suffix different from the AD domain — confirm auth succeeds and shares enumerate
  • nxc smb host.domain.example.com -k --use-kcache --shares where DNS suffix matches AD domain — confirm no regression
  • nxc smb BAREHOST -k --use-kcache --shares passing a bare hostname — confirm fallback to {hostname}.{domain} construction still works
  • DCOM execution path with Kerberos — confirm no regression

Reconstructing the remote name as {netbios_hostname}.{targetDomain} produces
the wrong SPN when a host's DNS suffix differs from the AD domain name
(e.g. host.aepsc.com registered in AD vs the constructed host.corp.aepsc.com),
resulting in KDC_ERR_S_PRINCIPAL_UNKNOWN. Use self.host directly when it is
already an FQDN, matching Impacket's smbclient behaviour.
@github-actions
Copy link
Copy Markdown

It looks like the PR template may not have been filled out. The following sections appear to be missing:

  • Description

  • Type of change

  • Setup guide for the review

  • Checklist

Please edit your PR description to include them. The template helps reviewers understand and test your changes. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant