shadow1ng/fscan · error
failed to connect target: %s
Error message
failed to connect target: %s
What it means
smb2Grooms opens `grooms` parallel TCP connections to the target to spray SMB2 groom packets. The first net.Dial that fails aborts the whole loop, closes already-open connections, and returns 'failed to connect target'. This is the SMB2 stage's TCP connect failure.
Source
Thrown at plugins/services/ms17010_exp.go:922
func smb2Grooms(address string, grooms int) ([]net.Conn, error) {
header := makeSMB2Header()
var (
conns []net.Conn
ok bool
)
defer func() {
if ok {
return
}
for i := 0; i < len(conns); i++ {
_ = conns[i].Close()
}
}()
for i := 0; i < grooms; i++ {
conn, err := net.Dial("tcp", address)
if err != nil {
return nil, fmt.Errorf("failed to connect target: %s", err)
}
_, err = conn.Write(header)
if err != nil {
return nil, fmt.Errorf("failed to send SMB2 header: %s", err)
}
conns = append(conns, conn)
}
ok = true
return conns, nil
}
func makeSMB2Header() []byte {
buf := bytes.Buffer{}
buf.Write([]byte{0x00, 0x00, 0xFF, 0xF7, 0xFE})
buf.WriteString("SMB")
buf.Write(makeZero(124))
return buf.Bytes()
}View on GitHub (pinned to 95cc12e753)
Solutions
- Reduce the grooms count (default is tuned; excessive values trigger failures)
- Verify port 445 reachability with a single connect test first
- Check firewall/rate-limiting on the target and intermediate devices
- Add backoff/retry on individual dial failures instead of aborting
Example fix
// before
conn, err := net.Dial("tcp", address)
if err != nil { return nil, fmt.Errorf("failed to connect target: %s", err) }
// after
conn, err := net.Dial("tcp", address)
if err != nil {
time.Sleep(100 * time.Millisecond)
conn, err = net.Dial("tcp", address)
if err != nil { return nil, fmt.Errorf("failed to connect target: %s", err) }
} Defensive patterns
Strategy: validation
Validate before calling
// before grooms, verify a single dial succeeds and tune the count
if err := canConnect(address); err != nil {
return fmt.Errorf("target unreachable, skipping grooms: %w", err)
}
const maxReasonableGrooms = 100
if grooms > maxReasonableGrooms { grooms = maxReasonableGrooms } Try / catch
conns, err := smb2Grooms(address, grooms, header)
if err != nil {
var derr *net.OpError
if errors.As(err, &derr) && isRefused(derr.Err) {
// back off and retry with fewer grooms
}
return err
} Prevention
- Keep the grooms count within the target's connection backlog capacity
- Pre-test connectivity with one dial before the loop
- Add per-iteration backoff instead of aborting on the first failure
- Check rate limiting on firewalls between scanner and target
When it happens
Trigger: exploit → smb2Grooms(address, grooms, header) → net.Dial fails on iteration i: connection refused, host unreachable, or the target's backlog is exhausted by the groom flood itself (too many grooms).
Common situations: Setting grooms too high exhausts the target's connection backlog or triggers rate limiting; firewall blocks subsequent connections; target drops connections under load.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- service_target_unreachable: %w
- service_conn_port_failed: %w
- ms17010_connection_error: %w
- ms17010_set_timeout_error: %w
- failed to send SMB2 header: %s
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/9598794cda1e131f.
Report an issue: GitHub.