diff options
author | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-09 08:24:04 -0500 |
---|---|---|
committer | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-09 08:24:04 -0500 |
commit | 1d82f299b433a17849b576b6e715a93240b29fd8 (patch) | |
tree | 7a3599e17b57570c9b59b6170956fe35626ba03b /internal | |
parent | 05873b432686fd584a07e98d37d4eb0cc5104da1 (diff) | |
download | goexec-1d82f299b433a17849b576b6e715a93240b29fd8.tar.gz goexec-1d82f299b433a17849b576b6e715a93240b29fd8.zip |
Update TODO; add dynamic namespace to `wmi call`
Diffstat (limited to 'internal')
-rw-r--r-- | internal/client/dce/dce.go | 1 | ||||
-rw-r--r-- | internal/exec/wmi/exec.go | 125 |
2 files changed, 11 insertions, 115 deletions
diff --git a/internal/client/dce/dce.go b/internal/client/dce/dce.go index 142eda9..0230c2a 100644 --- a/internal/client/dce/dce.go +++ b/internal/client/dce/dce.go @@ -21,6 +21,7 @@ type ConnectionMethodDCEConfig struct { Options []dcerpc.Option // Options stores the options that will be passed to all dialers DceOptions []dcerpc.Option // DceOptions are the options passed to dcerpc.Dial EpmOptions []dcerpc.Option // EpmOptions are the options passed to epm.EndpointMapper + Resource string // Resource stores the target network resource (usually for DCOM) } func (cfg *ConnectionMethodDCEConfig) GetDce(ctx context.Context, cred *adauth.Credential, target *adauth.Target, endpoint, object string, arbOpts ...dcerpc.Option) (cc dcerpc.Conn, err error) { diff --git a/internal/exec/wmi/exec.go b/internal/exec/wmi/exec.go index b61bf5c..7ae33ba 100644 --- a/internal/exec/wmi/exec.go +++ b/internal/exec/wmi/exec.go @@ -8,14 +8,12 @@ import ( "github.com/FalconOpsLLC/goexec/internal/client/dce" "github.com/FalconOpsLLC/goexec/internal/exec" "github.com/RedTeamPentesting/adauth" - "github.com/RedTeamPentesting/adauth/dcerpcauth" "github.com/oiweiwei/go-msrpc/dcerpc" "github.com/oiweiwei/go-msrpc/msrpc/dcom" "github.com/oiweiwei/go-msrpc/msrpc/dcom/iactivation/v0" "github.com/oiweiwei/go-msrpc/msrpc/dcom/wmi" "github.com/oiweiwei/go-msrpc/msrpc/dcom/wmi/iwbemlevel1login/v0" "github.com/oiweiwei/go-msrpc/msrpc/dcom/wmi/iwbemservices/v0" - "github.com/oiweiwei/go-msrpc/ssp/gssapi" "github.com/rs/zerolog" ) @@ -72,7 +70,7 @@ func (mod *Module) Connect(ctx context.Context, creds *adauth.Credential, target ORPCThis: ORPCThis, ClassID: wmi.Level1LoginClassID.GUID(), IIDs: []*dcom.IID{iwbemlevel1login.Level1LoginIID}, - RequestedProtocolSequences: []uint16{ProtocolSequenceRPC, ProtocolSequenceNP}, // TODO: dynamic + RequestedProtocolSequences: []uint16{ProtocolSequenceRPC}, // TODO: Named pipe support }) if err != nil { return fmt.Errorf("request remote activation: %w", err) @@ -85,8 +83,13 @@ func (mod *Module) Connect(ctx context.Context, creds *adauth.Credential, target return errors.New("remote activation failed") } ipid := act.InterfaceData[0].GetStandardObjectReference().Std.IPID - for _, sb := range retBinds { - //sb.NetworkAddr = target.AddressWithoutPort() // TODO: check if sb.NetworkAddr contains the port + + for _, b := range retBinds { + sb, err := dcerpc.ParseStringBinding("ncacn_ip_tcp:" + b.NetworkAddr) + if err != nil { + log.Debug().Err(err).Msg("Failed to parse string binding") + } + sb.NetworkAddress = target.AddressWithoutPort() dceOpts = append(dceOpts, dcerpc.WithEndpoint(sb.String())) } @@ -99,7 +102,7 @@ func (mod *Module) Connect(ctx context.Context, creds *adauth.Credential, target } login, err := loginClient.NTLMLogin(ctx, &iwbemlevel1login.NTLMLoginRequest{ This: ORPCThis, - NetworkResource: "//./root/cimv2", // TODO: make this dynamic + NetworkResource: cfg.Resource, }) if err != nil { return fmt.Errorf("ntlm login: %w", err) @@ -107,120 +110,12 @@ func (mod *Module) Connect(ctx context.Context, creds *adauth.Credential, target mod.sc, err = iwbemservices.NewServicesClient(ctx, mod.dce, dcom.WithIPID(login.Namespace.InterfacePointer().IPID())) if err != nil { - return fmt.Errorf("iwbemservices.NewServicesClient: %w", err) + return fmt.Errorf("create services client: %w", err) } } - return } -func (mod *Module) _Connect(ctx context.Context, creds *adauth.Credential, target *adauth.Target, _ *exec.ConnectionConfig) (err error) { - - var baseOpts, authOpts []dcerpc.Option - var ipid *dcom.IPID // This will store the IPID of the remote instance - var bind2Opts []dcerpc.Option - - ctx = gssapi.NewSecurityContext(ctx) - log := zerolog.Ctx(ctx).With(). - Str("module", "tsch"). - Str("func", "Connect").Logger() - - // Assemble DCERPC options - { - baseOpts = []dcerpc.Option{ - dcerpc.WithLogger(log), - dcerpc.WithSign(), // Enforce signing - dcerpc.WithSeal(), // Enforce packet stub encryption - } - // Add target name option if possible - if tn, err := target.Hostname(ctx); err == nil { - baseOpts = append(baseOpts, dcerpc.WithTargetName(tn)) - } else { - log.Debug().Err(err).Msg("Failed to get target hostname") - } - // Parse target and credentials - if authOpts, err = dcerpcauth.AuthenticationOptions(ctx, creds, target, &dcerpcauth.Options{}); err != nil { - return fmt.Errorf("parse authentication options: %w", err) - } - } - - // Establish first connection (REMACT) - { - // Connection options - rp := "ncacn_ip_tcp" // Underlying protocol - ro := 135 // RPC port - rb := fmt.Sprintf("%s:[%d]", rp, ro) // RPC binding - - // Create DCERPC dialer - mod.dce, err = dcerpc.Dial(ctx, target.AddressWithoutPort(), append(baseOpts, append(authOpts, dcerpc.WithEndpoint(rb))...)...) - if err != nil { - return fmt.Errorf("create DCERPC dialer: %w", err) - } - // Create remote activation client - ia, err := iactivation.NewActivationClient(ctx, mod.dce, append(baseOpts, dcerpc.WithEndpoint(rb))...) - if err != nil { - return fmt.Errorf("create activation client: %w", err) - } - // Send remote activation request - act, err := ia.RemoteActivation(ctx, &iactivation.RemoteActivationRequest{ - ORPCThis: ORPCThis, - ClassID: wmi.Level1LoginClassID.GUID(), - IIDs: []*dcom.IID{iwbemlevel1login.Level1LoginIID}, - RequestedProtocolSequences: []uint16{ProtocolSequenceRPC, ProtocolSequenceNP}, // TODO: dynamic - }) - if err != nil { - return fmt.Errorf("request remote activation: %w", err) - } - if act.HResult != 0 { - return fmt.Errorf("remote activation failed with code %d", act.HResult) - } - retBinds := act.OXIDBindings.GetStringBindings() - if len(act.InterfaceData) < 1 || len(retBinds) < 1 { - return errors.New("remote activation failed") - } - ipid = act.InterfaceData[0].GetStandardObjectReference().Std.IPID - - // This ensures that the original target address/hostname is used in the string binding - origBind := retBinds[0].String() - if bind, err := dcerpc.ParseStringBinding(origBind); err != nil { - log.Warn().Str("binding", origBind).Err(err).Msg("Failed to parse binding string returned by server") - bind2Opts = act.OXIDBindings.EndpointsByProtocol(rp) // Try using the server supplied string binding - } else { - bind.NetworkAddress = target.AddressWithoutPort() // Replace address/hostname in new string binding - bs := bind.String() - log.Info().Str("binding", bs).Msg("found binding") - bind2Opts = append(bind2Opts, dcerpc.WithEndpoint(bs)) // Use the new string binding - } - } - - // Establish second connection (WMI) - { - bind2Opts = append(bind2Opts, authOpts...) - mod.dce, err = dcerpc.Dial(ctx, target.AddressWithoutPort(), append(baseOpts, bind2Opts...)...) - if err != nil { - return fmt.Errorf("dial WMI: %w", err) - } - // Create login client - loginClient, err := iwbemlevel1login.NewLevel1LoginClient(ctx, mod.dce, append(baseOpts, dcom.WithIPID(ipid))...) - if err != nil { - return fmt.Errorf("initialize wbem login client: %w", err) - } - login, err := loginClient.NTLMLogin(ctx, &iwbemlevel1login.NTLMLoginRequest{ // TODO: Other login opts/methods? - This: ORPCThis, - NetworkResource: "//./root/cimv2", // TODO: make this dynamic - }) - if err != nil { - return fmt.Errorf("ntlm login: %w", err) - } - - mod.sc, err = iwbemservices.NewServicesClient(ctx, mod.dce, dcom.WithIPID(login.Namespace.InterfacePointer().IPID())) - if err != nil { - return fmt.Errorf("iwbemservices.NewServicesClient: %w", err) - } - } - return nil -} - func (mod *Module) Exec(ctx context.Context, ecfg *exec.ExecutionConfig) (err error) { log := zerolog.Ctx(ctx).With(). Str("module", "tsch"). |