diff --git a/pkg/transport/tcp.go b/pkg/transport/tcp.go index fed17d3..721c0ae 100644 --- a/pkg/transport/tcp.go +++ b/pkg/transport/tcp.go @@ -71,7 +71,8 @@ func DialTLS(network, address string, config *tls.Config) (*tls.Conn, error) { } // Dialer is a value-typed dialer suitable for APIs that expect a struct with a -// Dial method (e.g. pkg/smb, pkg/ldap). Respects the configured proxy. +// Dial or DialContext method (e.g. pkg/smb, pkg/ldap, go-msrpc/dcerpc). +// Respects the configured proxy. type Dialer struct { TimeoutSec int } @@ -81,6 +82,13 @@ func (d *Dialer) Dial(network, address string) (net.Conn, error) { return DialTimeout(network, address, d.TimeoutSec) } +// DialContext establishes a TCP connection, honoring ctx for cancellation and +// deadline. Routes through the proxy if configured. Satisfies the +// go-msrpc/dcerpc.Dialer interface. +func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return DialContext(ctx, network, address) +} + func splitHostPort(address string) (host, port string, err error) { host, port, err = net.SplitHostPort(address) if err != nil { diff --git a/tools/dcomexec/main.go b/tools/dcomexec/main.go index 8750fb1..6133736 100644 --- a/tools/dcomexec/main.go +++ b/tools/dcomexec/main.go @@ -56,6 +56,7 @@ import ( "github.com/mandiant/gopacket/pkg/kerberos" "github.com/mandiant/gopacket/pkg/session" "github.com/mandiant/gopacket/pkg/smb" + "github.com/mandiant/gopacket/pkg/transport" ) // IDispatch invoke flags @@ -330,8 +331,13 @@ func (e *DCOMExec) connect() error { host = e.creds.DCIP } + // Route DCE/RPC TCP connects through gopacket's transport so -proxy / + // proxychains take effect. Without this, upstream falls back to net.Dialer + // which bypasses both the SOCKS5 dialer and the libc connect() hook. + dialer := dcerpc.WithDialer(&transport.Dialer{}) + // Connect to endpoint mapper (port 135) - conn, err := dcerpc.Dial(e.ctx, net.JoinHostPort(host, "135")) + conn, err := dcerpc.Dial(e.ctx, net.JoinHostPort(host, "135"), dialer) if err != nil { return fmt.Errorf("failed to connect to endpoint mapper: %v", err) } @@ -400,7 +406,7 @@ func (e *DCOMExec) connect() error { } // Connect to the OXID endpoint - oxidConn, err := dcerpc.Dial(e.ctx, host, endpoints...) + oxidConn, err := dcerpc.Dial(e.ctx, host, append([]dcerpc.Option{dialer}, endpoints...)...) if err != nil { return fmt.Errorf("failed to connect to OXID endpoint: %v", err) } diff --git a/tools/wmiexec/main.go b/tools/wmiexec/main.go index 80aec45..111a727 100644 --- a/tools/wmiexec/main.go +++ b/tools/wmiexec/main.go @@ -59,6 +59,7 @@ import ( "github.com/mandiant/gopacket/pkg/kerberos" "github.com/mandiant/gopacket/pkg/session" "github.com/mandiant/gopacket/pkg/smb" + "github.com/mandiant/gopacket/pkg/transport" ) var ( @@ -193,9 +194,14 @@ func main() { ctx := gssapi.NewSecurityContext(context.Background()) + // Route DCE/RPC TCP connects through gopacket's transport so -proxy / + // proxychains take effect. Without this, upstream falls back to net.Dialer + // which bypasses both the SOCKS5 dialer and the libc connect() hook. + dialer := dcerpc.WithDialer(&transport.Dialer{}) + // 1. Connect to Endpoint Mapper (Port 135) log.Info().Msgf("Connecting to %s:135", target.Host) - cc, err := dcerpc.Dial(ctx, net.JoinHostPort(target.Host, "135")) + cc, err := dcerpc.Dial(ctx, net.JoinHostPort(target.Host, "135"), dialer) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial 135 failed: %v\n", err) os.Exit(1) @@ -249,7 +255,7 @@ func main() { os.Exit(1) } - wcc, err := dcerpc.Dial(ctx, target.Host, endpoints...) + wcc, err := dcerpc.Dial(ctx, target.Host, append([]dcerpc.Option{dialer}, endpoints...)...) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial WMI failed: %v\n", err) os.Exit(1) @@ -510,15 +516,16 @@ func (e *WMIExec) retrieveOutput(filename string) (string, error) { content, err := smbClient.Cat(filename) if err == nil { // Delete the output file - smbClient.Rm(filename) + if err := smbClient.Rm(filename); err != nil { + // If sharing violation, command is still running + if strings.Contains(err.Error(), "share access flags are incompatible") { + e.log.Debug().Msg("Output file in use, waiting...") + continue + } + } return content, nil } - // If sharing violation, command is still running - if strings.Contains(err.Error(), "STATUS_SHARING_VIOLATION") { - e.log.Debug().Msg("Output file in use, waiting...") - continue - } // If file not found, keep waiting if strings.Contains(err.Error(), "STATUS_OBJECT_NAME_NOT_FOUND") { diff --git a/tools/wmipersist/main.go b/tools/wmipersist/main.go index 366865f..1f6f060 100644 --- a/tools/wmipersist/main.go +++ b/tools/wmipersist/main.go @@ -52,6 +52,7 @@ import ( "github.com/mandiant/gopacket/pkg/flags" "github.com/mandiant/gopacket/pkg/kerberos" "github.com/mandiant/gopacket/pkg/session" + "github.com/mandiant/gopacket/pkg/transport" ) var ( @@ -289,9 +290,14 @@ func main() { connectAddr = target.IP } + // Route DCE/RPC TCP connects through gopacket's transport so -proxy / + // proxychains take effect. Without this, upstream falls back to net.Dialer + // which bypasses both the SOCKS5 dialer and the libc connect() hook. + dialer := dcerpc.WithDialer(&transport.Dialer{}) + // 1. Connect to Endpoint Mapper (Port 135) log.Info().Msgf("Connecting to %s:135", connectAddr) - cc, err := dcerpc.Dial(ctx, net.JoinHostPort(connectAddr, "135")) + cc, err := dcerpc.Dial(ctx, net.JoinHostPort(connectAddr, "135"), dialer) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial 135 failed: %v\n", err) os.Exit(1) @@ -350,7 +356,7 @@ func main() { os.Exit(1) } - wcc, err := dcerpc.Dial(ctx, connectAddr, endpoints...) + wcc, err := dcerpc.Dial(ctx, connectAddr, append([]dcerpc.Option{dialer}, endpoints...)...) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial WMI failed: %v\n", err) os.Exit(1) diff --git a/tools/wmiquery/main.go b/tools/wmiquery/main.go index c85086f..e6cec13 100644 --- a/tools/wmiquery/main.go +++ b/tools/wmiquery/main.go @@ -56,6 +56,7 @@ import ( "github.com/mandiant/gopacket/pkg/flags" "github.com/mandiant/gopacket/pkg/kerberos" "github.com/mandiant/gopacket/pkg/session" + "github.com/mandiant/gopacket/pkg/transport" ) // WBEM flags @@ -204,9 +205,14 @@ func main() { ctx := gssapi.NewSecurityContext(context.Background()) + // Route DCE/RPC TCP connects through gopacket's transport so -proxy / + // proxychains take effect. Without this, upstream falls back to net.Dialer + // which bypasses both the SOCKS5 dialer and the libc connect() hook. + dialer := dcerpc.WithDialer(&transport.Dialer{}) + // 1. Connect to Endpoint Mapper (Port 135) log.Info().Msgf("Connecting to %s:135", target.Host) - cc, err := dcerpc.Dial(ctx, net.JoinHostPort(target.Host, "135")) + cc, err := dcerpc.Dial(ctx, net.JoinHostPort(target.Host, "135"), dialer) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial 135 failed: %v\n", err) os.Exit(1) @@ -265,7 +271,7 @@ func main() { os.Exit(1) } - wcc, err := dcerpc.Dial(ctx, target.Host, endpoints...) + wcc, err := dcerpc.Dial(ctx, target.Host, append([]dcerpc.Option{dialer}, endpoints...)...) if err != nil { fmt.Fprintf(os.Stderr, "[-] Dial WMI failed: %v\n", err) os.Exit(1)