shadow1ng/fscan · warning

service_not_identified

service_not_identified

Error message

service_not_identified: SSH

What it means

The SSH plugin connected and read the banner but could not positively identify the service as SSH, so identifyService returns 'service_not_identified' with the received banner quoted ('SSH'). The banner exchange failed to match the plugin's identification criteria.

Source

Thrown at plugins/services/ssh.go:304

			Error:   err,
		}
	}
	defer func() { _ = conn.Close() }()

	if banner := p.readSSHBanner(conn, session.Config); banner != "" {
		session.LogSuccess(i18n.Tr("ssh_service_identified", target, banner)) //nolint:govet
		return &ScanResult{
			Type:    plugins.ResultTypeService,
			Success: true,
			Service: "ssh",
			Banner:  banner,
		}
	}

	return &ScanResult{
		Success: false,
		Service: "ssh",
		Error:   fmt.Errorf("%s", i18n.Tr("service_not_identified", "SSH")),
	}
}

// readSSHBanner 读取SSH服务器Banner
func (p *SSHPlugin) readSSHBanner(conn net.Conn, config *common.Config) string {
	_ = conn.SetReadDeadline(time.Now().Add(config.ModuleTimeout()))

	// RFC 4253 permits servers to send informational lines before the SSH
	// identification string. Read bounded lines until the protocol banner is
	// found instead of requiring SSH- at the first byte of the first read.
	reader := bufio.NewReaderSize(conn, 256)
	for range 50 {
		line, err := reader.ReadString('\n')
		if len(line) > 255 {
			return ""
		}

		banner := strings.TrimSpace(line)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Manually connect (nc host 22) and inspect the actual banner to confirm it matches SSH format.
  2. Increase the module read timeout so slow banners are captured.
  3. Loosen/extend the banner identification pattern to cover the server's banner variant.
  4. Verify the target port really hosts SSH and not a different or wrapped service.

Example fix

// before
cfg.SetModuleTimeout(2 * time.Second) // banner read times out
// after
cfg.SetModuleTimeout(10 * time.Second) // allow slow SSH banner exchange
Defensive patterns

Strategy: retry

Validate before calling

conn.SetReadDeadline(time.Now().Add(10*time.Second))
buf := make([]byte, 256); n, _ := conn.Read(buf)
if !strings.Contains(string(buf[:n]), "SSH-") { /* warn: not a standard SSH banner */ }

Type guard

func looksLikeSSH(banner string) bool { return strings.HasPrefix(banner, "SSH-") }

Prevention

When it happens

Trigger: Calling Scan when readSSHBanner returns a banner that does not match the SSH identification pattern (or is empty/timeout), causing the final fallback error in identifyService.

Common situations: Server on port 22 is not really SSH (a proxy, tarpit, or honeypot); banner delayed beyond ModuleTimeout; non-standard SSH servers with unusual banners; rate-limiting wrappers that greet differently.

Related errors


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