{"record":{"id":"30372e21f7a2c88d","repo":"shadow1ng/fscan","slug":"invalid-av-pair-list","errorCode":null,"errorMessage":"Invalid AV_PAIR list","messagePattern":"Invalid AV_PAIR list","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/tpkt/tpkt.go","lineNumber":257,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\tcurrIdx := startIdx\n\t\tfor avPair.AvID != 0 {\n\t\t\tif field, exists := AvIDMap[avPair.AvID]; exists {\n\t\t\t\tvar value string\n\t\t\t\tr := response[currIdx+avPairLen : currIdx+avPairLen+int(avPair.AvLen)]\n\t\t\t\tif avPair.AvID == 7 {\n\t\t\t\t\tunixStamp := binary.LittleEndian.Uint64(r)/10000000 - 11644473600\n\t\t\t\t\ttm := time.Unix(int64(unixStamp), 0)\n\t\t\t\t\tvalue = tm.Format(\"2006-01-02 15:04:05\")\n\t\t\t\t} else {\n\t\t\t\t\tvalue = strings.ReplaceAll(string(r), \"\\x00\", \"\")\n\t\t\t\t}\n\t\t\t\tinfo[field] = value\n\t\t\t}\n\t\t\tcurrIdx += avPairLen + int(avPair.AvLen)\n\t\t\tif currIdx+avPairLen > startIdx+targetInfoLen {\n\t\t\t\treturn fmt.Errorf(\"Invalid AV_PAIR list\")\n\t\t\t}\n\t\t\tavPairBuf = bytes.NewBuffer(response[currIdx : currIdx+avPairLen])\n\t\t\terr = binary.Read(avPairBuf, binary.LittleEndian, &avPair)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tglog.Info(\"get os info by NLA done !\")\n\tglog.Info(\"=======================================\")\n\tfor key, value := range info {\n\t\tglog.Info(key, \":\", value)\n\t}\n\tglog.Info(\"=======================================\")\n\n\t//判断是否存在windows域\n\tif netBiosDomainName, exists := info[\"NetBIOSDomainName\"]; exists {\n\t\tif netBiosComputerName, exists := info[\"NetBIOSComputerName\"]; exists {","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/tpkt/tpkt.go#L239-L275","documentation":"After reading each AV_PAIR in the NTLM CHALLENGE TargetInfo list, recvChallenge advances currIdx and expects another AV_PAIR header to still fit inside the TargetInfo block. This error means the AV_PAIR walk ran past the declared TargetInfo end — the list is not terminated/aligned as the NTLM spec requires, so the library refuses to continue parsing rather than reading garbage.","triggerScenarios":"StartNLA → recvChallenge against a server whose TargetInfo AV_PAIR chain has an AvLen that pushes iteration beyond startIdx+targetInfoLen, or whose TargetInfo bytes were truncated/misparsed so the terminator AV_PAIR (MsvAvEOL) is never reached in bounds.","commonSituations":"Servers with unusual AV_PAIR sets (e.g. Linux rdesktop-style servers, tight gateways); a prior parsing bug shifting currIdx by a few bytes; truncated network reads delivering partial TargetInfo.","solutions":["Ensure the full NTLM CHALLENGE packet is read before parsing (buffer/reassemble instead of a single 1024-byte Read)","Check that avPair.AvLen is parsed from the correct offset so currIdx advances by exactly avPairLen+AvLen","Test against a known-good Windows RDP host to isolate server-side nonconformance","Log startIdx, targetInfoLen, and currIdx at failure to confirm whether the server data or the parser is at fault"],"exampleFix":"// before\ncurrIdx += avPairLen + int(avPair.AvLen)\nif currIdx+avPairLen > startIdx+targetInfoLen {\n    return fmt.Errorf(\"Invalid AV_PAIR list\")\n}\n// after\ncurrIdx += avPairLen + int(avPair.AvLen)\nif currIdx == startIdx+targetInfoLen {\n    break // reached end of TargetInfo normally\n}\nif currIdx+avPairLen > startIdx+targetInfoLen {\n    return fmt.Errorf(\"Invalid AV_PAIR list\")\n}","handlingStrategy":"validation","validationCode":"func avPairsWellFormed(targetInfo []byte) bool {\n    i := 0\n    for i+4 <= len(targetInfo) {\n        avLen := int(binary.LittleEndian.Uint16(targetInfo[i+2 : i+4]))\n        i += 4 + avLen\n        if i == len(targetInfo) { return true }\n        if i+4 > len(targetInfo) { return false }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if err := client.Login(host, user, pass); err != nil {\n    if strings.Contains(err.Error(), \"Invalid AV_PAIR\") {\n        return fmt.Errorf(\"server sent malformed NTLM TargetInfo; try TLS-only security level: %w\", err)\n    }\n    return err\n}","preventionTips":["Validate against a known-good Windows host before blaming credentials","Ensure the full challenge message is buffered before NTLM parsing","Watch for AV_PAIR parsing bugs when modifying grdp internals","Treat non-Windows RDP servers as suspects for nonconformant TargetInfo"],"tags":["rdp","nla","ntlm","protocol-parsing"],"backgroundTag":"unexpected-response-shape","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}