shadow1ng/fscan · error
NLA auth failed: error code %d (0x%X)
Error message
NLA auth failed: error code %d (0x%X)
What it means
recvPubKeyInc inspects the server's TSRequest during NLA authentication; a nonzero ErrorCode means the server rejected the NTLM credentials (e.g. 0xC000006D STATUS_LOGON_FAILURE for a bad password). The library surfaces the raw NTSTATUS code so the caller can distinguish credential rejection from protocol failures.
Source
Thrown at libs/grdp/protocol/tpkt/tpkt.go:336
}
// ErrNLAAuthSuccess 表示NLA仅验证模式下认证成功(非真正错误)
var ErrNLAAuthSuccess = fmt.Errorf("NLA_AUTH_SUCCESS")
func (t *TPKT) recvPubKeyInc(data []byte) error {
glog.Trace("recvPubKeyInc", hex.EncodeToString(data))
tsreq, err := nla.DecodeDERTRequest(data)
if err != nil {
glog.Info("DecodeDERTRequest", err)
return err
}
// 检查服务器是否返回错误码(认证失败)
// 常见错误码: 0xC000006D = STATUS_LOGON_FAILURE (密码错误)
if tsreq.ErrorCode != 0 {
glog.Error("NLA authentication failed with error code:", tsreq.ErrorCode)
return fmt.Errorf("NLA auth failed: error code %d (0x%X)", tsreq.ErrorCode, uint32(tsreq.ErrorCode))
}
// 验证 PubKeyAuth 不为空(认证成功的标志)
if len(tsreq.PubKeyAuth) == 0 {
glog.Error("NLA authentication failed: empty PubKeyAuth")
return fmt.Errorf("NLA auth failed: empty PubKeyAuth")
}
glog.Trace("PubKeyAuth:", tsreq.PubKeyAuth)
// 尝试解密验证公钥,但不作为强制失败条件
// 因为某些Windows版本的响应格式可能略有不同
pubkey := t.ntlmSec.GssDecrypt(tsreq.PubKeyAuth)
if pubkey == nil {
glog.Debug("GssDecrypt returned nil, but continuing since no ErrorCode was returned")
}
// NLA仅验证模式:凭据已验证成功,不发送credentials,直接返回View on GitHub (pinned to 95cc12e753)
Solutions
- Verify username/password/domain by logging in interactively on the target machine
- Use DOMAIN\user or user@domain format consistently; try '.\user' for local accounts
- Check the account is not locked/expired and has Remote Desktop Users membership
- Read the 0x%X code: 0xC000006D/0xC000006A = bad password, 0xC0000072 = disabled account, 0xC0000234 = locked out
Example fix
// before
err := client.Login("10.0.0.5", "admin", "password")
if err != nil { panic(err) }
// after
var authErr *NLAAuthError
if err := client.Login("10.0.0.5", "admin", password); err != nil {
if errors.As(err, &authErr) && authErr.Code == 0xC000006D {
// bad credentials: re-prompt instead of retrying
return rePromptForCredentials()
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
if user == "" || pass == "" {
return errors.New("NLA requires non-empty credentials; supply username and password before calling Login")
}
if !strings.Contains(user, "\\") && !strings.Contains(user, "@") && domain == "" {
// ambiguous account: will likely fail with STATUS_LOGON_FAILURE
log.Println("warning: no domain qualifier on username")
} Type guard
func isLogonFailure(err error) bool {
var nlaErr *NLAAuthError
return errors.As(err, &nlaErr) && nlaErr.Code == 0xC000006D
} Try / catch
err := client.Login(host, user, pass)
var nlaErr *NLAAuthError
if errors.As(err, &nlaErr) {
switch nlaErr.Code {
case 0xC000006D, 0xC000006A:
return rePromptCredentials()
case 0xC0000072:
return errors.New("account disabled")
case 0xC0000234:
return errors.New("account locked out")
}
return err
} Prevention
- Test credentials interactively (mstsc) before wiring them into automation
- Store credentials in a secrets manager, not hardcoded config, to survive rotation
- Use consistent DOMAIN\user or UPN formats matching what the server expects
- Check account lockout/expiration policies when auth suddenly starts failing
When it happens
Trigger: StartNLA with username/password/domain that the server rejects: wrong password, expired/locked account, user lacking RDP rights, or domain mis specification causing the NTLM exchange to fail server-side.
Common situations: Typo'd or rotated passwords; account lockout policies; connecting with a local account when a domain account is required (or vice versa); user not in 'Remote Desktop Users'; stale cached credentials in automation config.
Related errors
- [dial err] %v
- unexpected connect in auth-only mode
- NLA auth timeout
- Invalid TargetInfoLen value
- Invalid AV_PAIR list
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/072c4ba9009bd373.
Report an issue: GitHub.