{"record":{"id":"a951a16323a7d19e","repo":"shadow1ng/fscan","slug":"invalid-scram-server-first-payload","errorCode":null,"errorMessage":"invalid SCRAM server-first payload","messagePattern":"invalid SCRAM server-first payload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/mongodb.go","lineNumber":507,"sourceCode":"\t\tcase 0x13: // decimal128\n\t\t\tif pos+16 > docLen {\n\t\t\t\treturn reply, fmt.Errorf(\"short bson decimal128\")\n\t\t\t}\n\t\t\tpos += 16\n\t\tdefault:\n\t\t\treturn reply, fmt.Errorf(\"unsupported bson type 0x%02x for key %s\", typ, key)\n\t\t}\n\t}\n\treturn reply, nil\n}\n\nfunc buildMongoSCRAMClientFinal(username, password, clientFirstBare, serverFirst string) (string, error) {\n\tattrs := parseSCRAMAttributes(serverFirst)\n\tserverNonce := attrs[\"r\"]\n\tsaltB64 := attrs[\"s\"]\n\titerText := attrs[\"i\"]\n\tif serverNonce == \"\" || saltB64 == \"\" || iterText == \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid SCRAM server-first payload\")\n\t}\n\tclientNonce := scramAttr(clientFirstBare, \"r\")\n\tif clientNonce == \"\" || !strings.HasPrefix(serverNonce, clientNonce) {\n\t\treturn \"\", fmt.Errorf(\"invalid SCRAM nonce\")\n\t}\n\tsalt, err := base64.StdEncoding.DecodeString(saltB64)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid SCRAM salt: %w\", err)\n\t}\n\titerations, err := strconv.Atoi(iterText)\n\tif err != nil || iterations <= 0 {\n\t\treturn \"\", fmt.Errorf(\"invalid SCRAM iteration count\")\n\t}\n\n\tclientFinalWithoutProof := \"c=biws,r=\" + serverNonce\n\tauthMessage := clientFirstBare + \",\" + serverFirst + \",\" + clientFinalWithoutProof\n\tdigest := md5.Sum([]byte(username + \":mongo:\" + password))\n\tsaltedPassword := pbkdf2.Key([]byte(fmt.Sprintf(\"%x\", digest)), salt, iterations, sha1.Size, sha1.New)","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/mongodb.go#L489-L525","documentation":"buildMongoSCRAMClientFinal parses the server-first SCRAM payload (r=...,s=...,i=...). If any of the nonce, salt, or iteration attributes are missing/empty, the payload is not a valid SCRAM server-first message and this error is returned.","triggerScenarios":"startReply.payload does not decode into 'r=nonce,s=salt,i=iterations' form — e.g. the server sent an error payload, a compressed/truncated payload, or an entirely different protocol message where parseSCRAMAttributes finds no r/s/i keys.","commonSituations":"Talking to a fake/honeypot MongoDB listener; a middlebox corrupting the payload; protocol-level mismatch after server upgrade (e.g. server replying with SCRAM-SHA-256-specific fields the parser ignores).","solutions":["Capture/verify the raw saslStart reply payload contains r=, s=, i= attributes","Confirm the target is real mongod, not a mimicking service on 27017","Rule out network devices stripping or rewriting the OP_MSG body","Check the payload for leading/trailing garbage that breaks attribute parsing"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"re := regexp.MustCompile(`r=[^,]*,s=[^,]*,i=[^,]*`)\nif !re.MatchString(serverFirst) {\n    return errors.New(\"server-first payload missing r/s/i attributes\")\n}","typeGuard":"func looksLikeServerFirst(payload string) bool {\n    a := parseSCRAMAttributes(payload)\n    return a[\"r\"] != \"\" && a[\"s\"] != \"\" && a[\"i\"] != \"\"\n}","tryCatchPattern":"final, err := buildMongoSCRAMClientFinal(u, p, cfb, serverFirst)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid SCRAM\") {\n        log.Warnf(\"target sent non-SCRAM server-first payload: %v\", err)\n        return\n    }\n    return err\n}","preventionTips":["Validate the saslStart payload shape before SCRAM math","Fingerprint the target as genuine mongod first","Log raw payloads (hex) on failure to diagnose middlebox corruption"],"tags":["mongodb","scram","protocol","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}