shadow1ng/fscan · warning

i18n.GetText("empty_response_received")

Error message

i18n.GetText("empty_response_received")

What it means

After sending the probe packet, checkMongoAuth reads the reply; if the connection yields zero bytes (clean close with no data), it reports the localized 'empty_response_received' error. A real MongoDB must answer an OP_MSG with at least a protocol header, so an empty read means the peer is not speaking MongoDB or dropped the connection.

Source

Thrown at plugins/services/mongodb.go:675

	if _, writeErr := conn.Write(packet); writeErr != nil {
		return "", writeErr
	}

	select {
	case <-ctx.Done():
		return "", ctx.Err()
	default:
	}

	reply := make([]byte, 2048)
	count, err := conn.Read(reply)
	if err != nil && err != io.EOF {
		return "", err
	}

	if count == 0 {
		return "", fmt.Errorf("%s", i18n.GetText("empty_response_received"))
	}

	return string(reply[:count]), nil
}

func createOpMsgPacket() []byte {
	return []byte{
		0x69, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0xdd, 0x07, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00,
		0x00, 0x02, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x67,
		0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61,
		0x72, 0x74, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6e,
		0x69, 0x6e, 0x67, 0x73, 0x00, 0x02, 0x24, 0x64,
		0x62, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x64,
		0x6d, 0x69, 0x6e, 0x00, 0x03, 0x6c, 0x73, 0x69,
		0x64, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x05, 0x69,
		0x64, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x6e,

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Identify what actually listens on the port (banner grab, nmap -sV) before MongoDB-specific checks
  2. Check mongod logs for connection rejections or max-connection limits
  3. Disable tcpwrappers/connThrottle or allowlist the scanner IP
  4. Send a valid hello handshake and confirm a structured BSON reply comes back
Defensive patterns

Strategy: retry

Validate before calling

conn.SetReadDeadline(time.Now().Add(timeout))
n, err := conn.Read(buf)
if err == io.EOF && n == 0 {
    return errors.New("peer closed without responding — likely not MongoDB")
}

Type guard

func isEmptyResponse(n int, err error) bool {
    return n == 0 && (err == io.EOF || err == nil)
}

Try / catch

reply, err := checkMongoAuth(ctx, addr, packet, session)
if err != nil {
    if strings.Contains(i18nText(err), "empty_response") {
        if r2, e2 := checkMongoAuth(ctx, addr, packet, session); e2 == nil {
            reply = r2
        } else {
            log.Warn("target closes connections without replying")
        }
        return
    }
    return err
}

Prevention

When it happens

Trigger: conn.Read returns count==0 (typically with io.EOF) right after the write — the remote closed without responding, e.g. because it is not a MongoDB server or it rejects the crafted packet.

Common situations: Port occupied by an HTTP or other plain-text service that closes on binary input; mongod with aggressive connection throttling closing immediately; tcpwrapped services in inetd-style wrappers.

Related errors


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