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 -sVLook 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
dateSymptoms 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 klistSee krb5-user for all commands.
Samba password change (alternative to kpasswd)
sudo apt install samba-common-bin
which smbpasswd5. Configure /etc/krb5.conf
→ Full workflow: Kerberos Setup - krb5.conf — nxc --generate-krb5-file · cat file | sudo tee /etc/krb5.conf · ntpdate
Manual template (if not using nxc generator):
sudo nano /etc/krb5.confTemplate:
[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.LOCALExample (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.VLAdd DC to /etc/hosts if DNS does not resolve:
echo "10.129.xx.xx dc.baby.vl baby.vl" | sudo tee -a /etc/hosts6. Verify Kerberos (optional but recommended)
kinit user@DOMAIN.LOCAL
# enter current (must-change) password
klistIf 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.LOCALExample:
kpasswd Caroline.Robinson@BABY.VLPrompts:
- Current password (the one that gave
NT_STATUS_PASSWORD_MUST_CHANGE) - New password
- 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.fqdnExample:
smbpasswd -U BABY/caroline.robinson -r baby.vlPrompts for old password, then new password twice.
| Flag | Meaning |
|---|---|
-U DOMAIN/user | Domain and username (DOMAIN/user or user@REALM) |
-r host | Remote 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| Flag | Meaning |
|---|---|
domain/machine$:password@DC_IP | Target machine account + current password |
-newpass | New password to set |
-p rpc-samr | Protocol — required for pre-created machine accounts (bypasses SMB trust error) |
-hashes :NTHASH | Use 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.ccacheChain → 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.localFix 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.LOCALklist empty / no Kerberos ticket
kinit user@DOMAIN.LOCAL
klistkpasswd 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!'Related Tools
- krb5-user
- Kerbrute
- Impacket
- Certipy & Certify
- AD CS ESC
- CrackMapExec - nxc
- evil-winrm
- Time Sync-Clock Skew