projectdiscovery/nuclei · error

smb connect: %w

Error message

smb connect: %w

What it means

The DCERPC/SMB JS client could not establish its SMB session: connect() first verifies the host against protocolstate's network policy (a denied host fails earlier with ErrHostDenied, not this), then dials via goimpacket's SMB client bound to an execution-scoped dialer; any failure of smb.Connect() is wrapped as 'smb connect: ...'. The %w preserves goimpacket's error: unreachable host, auth failure, or protocol/signing mismatch.

Source

Thrown at pkg/js/libs/dcerpc/dcerpc.go:164

func (c *Client) SetPort(port int) {
	c.Port = port
	c.target.Port = port
}

// connect lazily establishes the underlying SMB session that all RPC
// transports are tunneled through. The SMB Client is bound to a Dialer that
// captures this client's executionId so every dial inside goimpacket is
// validated against the same network policy.
func (c *Client) connect() error {
	if c.started {
		return nil
	}
	if !protocolstate.IsHostAllowed(c.nj.ExecutionId(), c.Host) {
		return protocolstate.ErrHostDenied.Msgf(c.Host)
	}
	c.smb = gpsmb.NewClientWithDialer(c.target, c.creds, NewExecDialer(c.nj.ExecutionId()))
	if err := c.smb.Connect(); err != nil {
		return fmt.Errorf("smb connect: %w", err)
	}
	c.started = true
	return nil
}

// Close releases the underlying SMB session.
func (c *Client) Close() {
	if c.smb != nil {
		c.smb.Close()
	}
	c.started = false
}

// rpcOverNamedPipe binds the supplied interface UUID over a named pipe and
// returns an authenticated *dcerpc.Client.
func (c *Client) rpcOverNamedPipe(pipe string, uuid [16]byte, major, minor uint16) (*gprpc.Client, error) {
	if err := c.connect(); err != nil {
		return nil, err

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Verify reachability of 445: nc -vz host 445 (or test on 139 and configure accordingly)
  2. Correct the credential format — for domain accounts use DOMAIN\\user with lm/ntlm hashes where expected
  3. Confirm the SMB dialect: targets requiring SMB1 are unsupported by modern clients; enforce signing compatible settings
  4. Remember connect() is idempotent (c.started guard): a failed connect leaves started=false so you may retry after fixing the cause, but call Close() if you abandon the client

Example fix

// before
const c = new Client({ Host: '10.0.0.5', User: 'admin', Hash: '...' });
await c.connect();  // smb connect: ... (445 filtered)

// after
// firewall allows 445, domain-qualified user
const c = new Client({ Host: '10.0.0.5', User: 'CORP\\admin', Hash: 'aad3b435b51404eeaad3b435b51404ee:...' });
await c.connect();
Defensive patterns

Strategy: try-catch

Validate before calling

// in template JS: cheap reachability probe before SMB connect
const ok = await wireguard('tcp', Host, 445); // or a raw TCP dial helper if available
if (!ok) { log('445 closed — skip'); exit(); }

Try / catch

Wrap the connect/usage sequence in try/catch; on 'smb connect:' inspect the wrapped goimpacket error — timeout/unreachable means network (skip host), STATUS_LOGON_FAILURE means credentials (fix creds), STATUS_ACCESS_DENIED means signing/permission config. Call Close() on failure so a later connect() may retry (started is reset).

Prevention

When it happens

Trigger: new dcerpc-style Client connect where tcp/445 is filtered or the service is down, credentials are wrong (NTLM hash/password/username), SMB signing is required but not negotiated, or the target speaks only SMB1.

Common situations: Templates binding to 445 against hosts exposing SMB only on 139; domain-credential formats wrong (user vs DOMAIN\user); firewalls dropping 445 mid-scan; NAT'd lab targets.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/958448ddaa74ce66. Report an issue: GitHub.