AD Password Must Change — NT_STATUS_PASSWORD_MUST_CHANGE

Ctrl+F: NT_STATUS_PASSWORD_MUST_CHANGE · Clock skew too great · kpasswd · smbpasswd · port 464 · port 646 · krb5-user · kinit · klist · BABY.VL · caroline.robinson

You have the correct username and password, but auth fails with:

NT_STATUS_PASSWORD_MUST_CHANGE

Meaning:

  • Username is valid
  • Password is correct
  • Account must change its password before normal logon (first logon, expired password, admin “user must change password at next logon”)
NT_STATUS_PASSWORD_MUST_CHANGE
STATUS_PASSWORD_MUST_CHANGE
0xC0000224
User must change password before logging on

Fix: change the password remotely, then log in with the new password everywhere.

Common when CrackMapExec - nxc, smbclient, evil-winrm, or Impacket returns the error instead of a shell.

Related ports: 464 kpasswd · 646 LDP (not password change — do not confuse with 464) · 88 Kerberos · 389 LDAP

Tools: krb5-user · Time Sync-Clock Skew · Kerberos


1. Confirm the error

Look for any of:

NT_STATUS_PASSWORD_MUST_CHANGE
STATUS_PASSWORD_MUST_CHANGE
0xC0000224
User must change password before logging on

2. Verify DC exposes Kerberos password change

Scan the domain controller:

nmap -p88,389,464,636 DC_IP -sV

Look for:

88/tcp   open  kerberos-sec
389/tcp  open  ldap
464/tcp  open  kpasswd5
464/udp  open  kpasswd5

Do not confuse port 646 with 464: 646 = LDP (MPLS networking). 464 = kpasswd (Kerberos password change). See UseCases for ports > Port 646 — LDP (Label Distribution Protocol).

Port 464 = kpasswd (Kerberos Change/Set Password — RFC 3244). Both TCP and UDP.

Also scan 88 + 389 — you need Kerberos and LDAP working for normal AD auth after the change.

Full port reference → UseCases for ports > Port 464 — KPASSWD (Kerberos Password Change)


3. Sync time first

Kerberos fails with clock skew before you can change the password.

sudo timedatectl set-ntp false
sudo ntpdate -u DC_IP
sudo ntpdate -q DC_IP
date

Symptoms if skipped: Clock skew too great, KRB_AP_ERR_SKEW

Turn off Kali auto NTP first (timedatectl set-ntp false) or internet sync will override the DC.

Full guide → Time Sync-Clock Skew · quick: Time Sync-Clock Skew > Fix the clock (OSCP lab workflow)


4. Install tools (Kali)

Kerberos client (kpasswd, kinit, klist)

sudo apt update
sudo apt install krb5-user
which kpasswd kinit klist

See krb5-user for all commands.

Samba password change (alternative to kpasswd)

sudo apt install samba-common-bin
which smbpasswd

5. Configure /etc/krb5.conf

Full workflow: Kerberos Setup - krb5.confnxc --generate-krb5-file · cat file | sudo tee /etc/krb5.conf · ntpdate

Manual template (if not using nxc generator):

sudo nano /etc/krb5.conf

Template:

[libdefaults]
    default_realm = DOMAIN.LOCAL
    dns_lookup_realm = false
    dns_lookup_kdc = false
 
[realms]
    DOMAIN.LOCAL = {
        kdc = DC_IP
        admin_server = DC_IP
    }
 
[domain_realm]
    .domain.local = DOMAIN.LOCAL
    domain.local = DOMAIN.LOCAL

Example (baby.vl style lab):

[libdefaults]
    default_realm = BABY.VL
    dns_lookup_realm = false
    dns_lookup_kdc = false
 
[realms]
    BABY.VL = {
        kdc = 10.129.xx.xx
        admin_server = 10.129.xx.xx
    }
 
[domain_realm]
    .baby.vl = BABY.VL
    baby.vl = BABY.VL

Add DC to /etc/hosts if DNS does not resolve:

echo "10.129.xx.xx dc.baby.vl baby.vl" | sudo tee -a /etc/hosts

kinit user@DOMAIN.LOCAL
# enter current (must-change) password
 
klist

If kinit works, Kerberos and time sync are good — proceed to change password.


7. Change password — Method A: kpasswd (port 464)

Uses Kerberos kpasswd on TCP/UDP 464 to the KDC.

kpasswd user@DOMAIN.LOCAL

Example:

kpasswd Caroline.Robinson@BABY.VL

Prompts:

  1. Current password (the one that gave NT_STATUS_PASSWORD_MUST_CHANGE)
  2. New password
  3. Confirm new password

Meet domain policy (length, complexity, history) or the change fails.


8. Change password — Method B: smbpasswd (Samba RPC)

Alternative when kpasswd fails or you prefer SMB/RPC to the DC. Uses 445/SMB to the domain controller, not port 464.

smbpasswd -U DOMAIN/username -r domain.fqdn

Example:

smbpasswd -U BABY/caroline.robinson -r baby.vl

Prompts for old password, then new password twice.

FlagMeaning
-U DOMAIN/userDomain and username (DOMAIN/user or user@REALM)
-r hostRemote DC / domain DNS name

After success, test with CrackMapExec - nxc, evil-winrm, or Impacket using the new password.


8b. Pre-created computer account — changepasswd.py (rpc-samr)

Different scenario: Machine account was pre-created in AD with a known password. SMB auth fails with:

STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT

The account exists and password is correct, but the machine password must be changed before the account can authenticate normally (pre-Windows 2000 / pre-staged computer account).

Fix: Change password over MS-RPC SAMR (not SMB) using Impacket:

impacket-changepasswd 'retro.vl/banking$:banking@10.129.234.44' \
  -newpass 'kavi123!' \
  -p rpc-samr
FlagMeaning
domain/machine$:password@DC_IPTarget machine account + current password
-newpassNew password to set
-p rpc-samrProtocol — required for pre-created machine accounts (bypasses SMB trust error)
-hashes :NTHASHUse instead of plaintext password

Protocols available: smb-samr (default) · rpc-samr · kpasswd · ldap — see impacket-changepasswd -h

After change:

nxc smb retro.vl -u 'BANKING$' -p 'kavi123!'
nxc ldap retro.vl -u 'BANKING$' -p 'kavi123!' -M adcs

→ Pre-created enum: nxc smb -M pre2K · Impacket · TrustedSec — pre-created computer accounts


9. After password change — use new creds

# SMB check
nxc smb DC_IP -u user -p 'NewPassword123!'
 
# WinRM
evil-winrm -i TARGET -u user -p 'NewPassword123!'
 
# Kerberos ticket for Impacket -k
impacket-getTGT 'DOMAIN.LOCAL/user:NewPassword123!'
export KRB5CCNAME=user.ccache

Chain → Credential Graph — spray/reuse new password on all services.


Troubleshooting

Cannot find KDC for requested realm

cat /etc/krb5.conf
grep -i baby /etc/hosts
host -t SRV _kerberos._tcp.domain.local

Fix realm case (BABY.VL not baby.vl in kinit/kpasswd principal), KDC IP, and /etc/hosts.


Clock skew too great

Clock skew too great
KRB_AP_ERR_SKEW

Always disable Kali auto NTP first, then sync to the DC:

sudo timedatectl set-ntp false
sudo ntpdate -u DC_IP
# or: sudo ntpdate -s DC_IP
 
sudo ntpdate -q DC_IP    # verify offset ≈ 0
date
kinit user@DOMAIN.LOCAL

See Time Sync-Clock Skew


klist empty / no Kerberos ticket

kinit user@DOMAIN.LOCAL
klist

kpasswd connection refused / timed out

  • Confirm 464/tcp open: nmap -p464 DC_IP
  • Firewall between you and DC
  • Try smbpasswd instead (port 445)

Password change rejected

  • Policy: min length, complexity, password history, “cannot change password” flag
  • Try a stronger/different new password
  • Account locked after spray — wait or use another user

Quick cheat sheet

# 1. Sync + scan
sudo timedatectl set-ntp false
sudo ntpdate -u DC_IP
sudo ntpdate -q DC_IP
nmap -p88,389,464 DC_IP -sV
 
# 2. krb5.conf + hosts (once per lab) → [[Kerberos Setup - krb5.conf]]
 
# 3. Change password (pick one)
kpasswd Caroline.Robinson@BABY.VL
smbpasswd -U BABY/caroline.robinson -r baby.vl
 
# Pre-created machine account (STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)
impacket-changepasswd 'domain/machine$:password@DC_IP' -newpass 'NewPass!' -p rpc-samr
 
# 4. Login with NEW password
nxc smb TARGET -u caroline.robinson -p 'NewPass!'