aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorBryan McNulty <bryanmcnulty@protonmail.com>2025-04-09 08:24:04 -0500
committerBryan McNulty <bryanmcnulty@protonmail.com>2025-04-09 08:24:04 -0500
commit1d82f299b433a17849b576b6e715a93240b29fd8 (patch)
tree7a3599e17b57570c9b59b6170956fe35626ba03b /internal
parent05873b432686fd584a07e98d37d4eb0cc5104da1 (diff)
downloadgoexec-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.go1
-rw-r--r--internal/exec/wmi/exec.go125
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").