{"record":{"id":"19b53c5e09a4b2c7","repo":"shadow1ng/fscan","slug":"invalid-reply","errorCode":null,"errorMessage":"invalid reply","messagePattern":"invalid reply","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/nfs.go","lineNumber":126,"sourceCode":"func (p *NFSPlugin) getExports(conn interface {\n\tRead([]byte) (int, error)\n\tWrite([]byte) (int, error)\n}) ([]string, error) {\n\t// Sun RPC call: program=MOUNT(100005), version=3, procedure=EXPORT(5)\n\txid := uint32(0x12345678)\n\trpcCall := p.buildRPCCall(xid, 100005, 3, 5, nil)\n\trpcFragment := p.wrapRPCFragment(rpcCall)\n\n\tif _, err := conn.Write(rpcFragment); err != nil {\n\t\treturn nil, err\n\t}\n\n\treply, err := readRPCFragment(conn, 4096)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(reply) < 24 {\n\t\treturn nil, fmt.Errorf(\"invalid reply\")\n\t}\n\n\treplyXID := binary.BigEndian.Uint32(reply[0:4])\n\tif replyXID != xid {\n\t\treturn nil, fmt.Errorf(\"xid mismatch\")\n\t}\n\tmsgType := binary.BigEndian.Uint32(reply[4:8])\n\tif msgType != 1 { // REPLY\n\t\treturn nil, fmt.Errorf(\"not a reply\")\n\t}\n\treplyStatus := binary.BigEndian.Uint32(reply[8:12])\n\tif replyStatus != 0 { // MSG_ACCEPTED\n\t\treturn nil, fmt.Errorf(\"reply rejected\")\n\t}\n\n\t// Skip auth verifier\n\toffset := 12\n\tif offset+8 > len(reply) {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/nfs.go#L108-L144","documentation":"getExports performs an NFS EXPORTS (mount protocol) RPC over a record-marked TCP connection. After reading one reply fragment with readRPCFragment, it checks that at least 24 bytes came back — the minimum for an RPC reply header (XID, message type, reply status, auth verifier fields). A shorter response means the server (or something else on the wire) sent a non-conformant or partial reply, so the library rejects it rather than parsing garbage.","triggerScenarios":"Calling Scan or TestNFSGetExportsHandlesVerifierPadding against an endpoint whose reply fragment is shorter than 24 bytes — e.g. an HTTP server on port 2049/111, a plaintext banner, or a truncated TCP response.","commonSituations":"Pointing the NFS scanner at a non-NFS service that echoes short responses; a firewall/proxy that truncates packets; a server that closes the connection mid-reply; a misconfigured target port.","solutions":["Verify the target host:port is actually an NFS/mountd server (rpcinfo -p <host>)","Confirm no proxy or firewall is truncating the TCP stream on port 2049/111","Re-run the scan; a transient short read may succeed on retry","Check the server is not replying over a different protocol (e.g. TLS) that breaks the record-mark framing"],"exampleFix":"// before\nreply, err := readRPCFragment(conn, 4096) // reply came from wrong service\n// after\n// ensure the connection targets the mountd/NFS port before calling getExports\nconn, err := net.DialTimeout(\"tcp\", net.JoinHostPort(host, \"111\"), timeout)","handlingStrategy":"validation","validationCode":"if err := rpcinfoCheck(host, 100005); err != nil { return fmt.Errorf(\"%s is not an NFS/mountd host: %w\", host, err) }","typeGuard":"func isPlausibleRPCReply(reply []byte) bool { return len(reply) >= 24 && binary.BigEndian.Uint32(reply[4:8]) == 1 }","tryCatchPattern":"exports, err := getExports(conn, xid)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid reply\") {\n        log.Printf(\"host did not return a valid RPC reply; skipping\")\n        return nil\n    }\n    return err\n}","preventionTips":["Validate the target runs NFS (rpcinfo) before scanning","Use fresh connections per request to avoid stale bytes","Check for intercepting proxies on the scan path"],"tags":["network","rpc","nfs","protocol"],"backgroundTag":"unexpected-api-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"}