nuclei/pkg/js/libs/smb/smb.go
Tarun Koyalwar 19247ae74b
Path-Based Fuzzing SQL fix (#6400)
* setup claude

* migrate to using errkit

* fix unused imports + lint errors

* update settings.json

* fix url encoding issue

* fix lint error

* fix the path fuzzing component

* fix lint error
2025-08-25 13:36:58 +05:30

157 lines
4.4 KiB
Go

package smb
import (
"context"
"fmt"
"time"
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
"github.com/projectdiscovery/go-smb2"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/zmap/zgrab2/lib/smb/smb"
)
type (
// SMBClient is a client for SMB servers.
// Internally client uses github.com/zmap/zgrab2/lib/smb/smb driver.
// github.com/projectdiscovery/go-smb2 driver
// @example
// ```javascript
// const smb = require('nuclei/smb');
// const client = new smb.SMBClient();
// ```
SMBClient struct{}
)
// ConnectSMBInfoMode tries to connect to provided host and port
// and discovery SMB information
// Returns handshake log and error. If error is not nil,
// state will be false
// @example
// ```javascript
// const smb = require('nuclei/smb');
// const client = new smb.SMBClient();
// const info = client.ConnectSMBInfoMode('acme.com', 445);
// log(to_json(info));
// ```
func (c *SMBClient) ConnectSMBInfoMode(ctx context.Context, host string, port int) (*smb.SMBLog, error) {
executionId := ctx.Value("executionId").(string)
return memoizedconnectSMBInfoMode(executionId, host, port)
}
// @memo
func connectSMBInfoMode(executionId string, host string, port int) (*smb.SMBLog, error) {
if !protocolstate.IsHostAllowed(executionId, host) {
// host is not valid according to network policy
return nil, protocolstate.ErrHostDenied.Msgf(host)
}
dialer := protocolstate.GetDialersWithId(executionId)
if dialer == nil {
return nil, fmt.Errorf("dialers not initialized for %s", executionId)
}
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return nil, err
}
// try to get SMBv2/v3 info
result, err := getSMBInfo(conn, true, false)
_ = conn.Close() // close regardless of error
if err == nil {
return result, nil
}
// try to negotiate SMBv1
conn, err = dialer.Fastdialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return nil, err
}
defer func() {
_ = conn.Close()
}()
result, err = getSMBInfo(conn, true, true)
if err != nil {
return result, nil
}
return result, nil
}
// ListSMBv2Metadata tries to connect to provided host and port
// and list SMBv2 metadata.
// Returns metadata and error. If error is not nil,
// state will be false
// @example
// ```javascript
// const smb = require('nuclei/smb');
// const client = new smb.SMBClient();
// const metadata = client.ListSMBv2Metadata('acme.com', 445);
// log(to_json(metadata));
// ```
func (c *SMBClient) ListSMBv2Metadata(ctx context.Context, host string, port int) (*plugins.ServiceSMB, error) {
executionId := ctx.Value("executionId").(string)
if !protocolstate.IsHostAllowed(executionId, host) {
// host is not valid according to network policy
return nil, protocolstate.ErrHostDenied.Msgf(host)
}
return memoizedcollectSMBv2Metadata(executionId, host, port, 5*time.Second)
}
// ListShares tries to connect to provided host and port
// and list shares by using given credentials.
// Credentials cannot be blank. guest or anonymous credentials
// can be used by providing empty password.
// @example
// ```javascript
// const smb = require('nuclei/smb');
// const client = new smb.SMBClient();
// const shares = client.ListShares('acme.com', 445, 'username', 'password');
//
// for (const share of shares) {
// log(share);
// }
//
// ```
func (c *SMBClient) ListShares(ctx context.Context, host string, port int, user, password string) ([]string, error) {
executionId := ctx.Value("executionId").(string)
return memoizedlistShares(executionId, host, port, user, password)
}
// @memo
func listShares(executionId string, host string, port int, user string, password string) ([]string, error) {
if !protocolstate.IsHostAllowed(executionId, host) {
// host is not valid according to network policy
return nil, protocolstate.ErrHostDenied.Msgf(host)
}
dialer := protocolstate.GetDialersWithId(executionId)
if dialer == nil {
return nil, fmt.Errorf("dialers not initialized for %s", executionId)
}
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return nil, err
}
defer func() {
_ = conn.Close()
}()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: user,
Password: password,
},
}
s, err := d.Dial(conn)
if err != nil {
return nil, err
}
defer func() {
_ = s.Logoff()
}()
names, err := s.ListSharenames()
if err != nil {
return nil, err
}
return names, nil
}