shadow1ng/fscan · error

invalid SCRAM iteration count

Error message

invalid SCRAM iteration count

What it means

The i= attribute of the SCRAM server-first message is the PBKDF2 iteration count. If it is not a positive integer (strconv.Atoi fails or it is <= 0), the plugin rejects it as an invalid iteration count.

Source

Thrown at plugins/services/mongodb.go:519

func buildMongoSCRAMClientFinal(username, password, clientFirstBare, serverFirst string) (string, error) {
	attrs := parseSCRAMAttributes(serverFirst)
	serverNonce := attrs["r"]
	saltB64 := attrs["s"]
	iterText := attrs["i"]
	if serverNonce == "" || saltB64 == "" || iterText == "" {
		return "", fmt.Errorf("invalid SCRAM server-first payload")
	}
	clientNonce := scramAttr(clientFirstBare, "r")
	if clientNonce == "" || !strings.HasPrefix(serverNonce, clientNonce) {
		return "", fmt.Errorf("invalid SCRAM nonce")
	}
	salt, err := base64.StdEncoding.DecodeString(saltB64)
	if err != nil {
		return "", fmt.Errorf("invalid SCRAM salt: %w", err)
	}
	iterations, err := strconv.Atoi(iterText)
	if err != nil || iterations <= 0 {
		return "", fmt.Errorf("invalid SCRAM iteration count")
	}

	clientFinalWithoutProof := "c=biws,r=" + serverNonce
	authMessage := clientFirstBare + "," + serverFirst + "," + clientFinalWithoutProof
	digest := md5.Sum([]byte(username + ":mongo:" + password))
	saltedPassword := pbkdf2.Key([]byte(fmt.Sprintf("%x", digest)), salt, iterations, sha1.Size, sha1.New)
	clientKey := mongoHMAC(saltedPassword, []byte("Client Key"))
	storedKey := sha1.Sum(clientKey)
	clientSignature := mongoHMAC(storedKey[:], []byte(authMessage))
	proof := make([]byte, len(clientKey))
	for i := range clientKey {
		proof[i] = clientKey[i] ^ clientSignature[i]
	}
	return clientFinalWithoutProof + ",p=" + base64.StdEncoding.EncodeToString(proof), nil
}

func parseSCRAMAttributes(payload string) map[string]string {
	attrs := make(map[string]string)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Inspect the i= value in the server-first payload for non-numeric content
  2. Verify the server is a standard mongod emitting a positive integer iteration count
  3. Consider clamping/validating the iteration count range before use to reject absurd values
  4. Retry against a known-good MongoDB instance to isolate whether the target is misbehaving

Example fix

// before
iterations, err := strconv.Atoi(iterText)
if err != nil || iterations <= 0 {
    return "", fmt.Errorf("invalid SCRAM iteration count")
}
// after
iterations, err := strconv.Atoi(iterText)
if err != nil || iterations <= 0 || iterations > 1<<24 {
    return "", fmt.Errorf("invalid SCRAM iteration count: %q", iterText)
}
Defensive patterns

Strategy: validation

Validate before calling

it, err := strconv.Atoi(scramAttr(serverFirst, "i"))
if err != nil || it <= 0 || it > 1<<24 {
    return fmt.Errorf("iteration count out of accepted range")
}

Type guard

func isValidIterationCount(s string) bool {
    n, err := strconv.Atoi(s)
    return err == nil && n > 0 && n <= 1<<24
}

Try / catch

if _, err := buildMongoSCRAMClientFinal(u, p, cfb, serverFirst); err != nil && strings.Contains(err.Error(), "iteration count") {
    log.Warnf("target reported unusable iteration count: %v", err)
    return
}

Prevention

When it happens

Trigger: iterText is empty at this point only if attributes were partially present, or contains non-numeric text (e.g. '10000x', negative, or 0) — usually from a malformed or hostile server-first payload.

Common situations: Honeypot/fake MongoDB returning junk i= values; corrupted payload; extremely old or custom servers with non-numeric iteration fields.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/e181482d57721549. Report an issue: GitHub.