Merge dev into main (#22)

* Bump adauth to v0.5.0

* Open remote output file as RW

* Removed out-of-date TODO.md

* Add `--epm`; deprecate `--no-epm`

* Fix parsing of `--epm`/`--no-epm`

* Resolve #21
This commit is contained in:
Bryan McNulty
2025-09-08 19:16:39 -05:00
committed by GitHub
parent 72f12b26b6
commit 47d7be87cb
5 changed files with 329 additions and 401 deletions
-80
View File
@@ -1,80 +0,0 @@
# TODO
We wanted to make development of this project as transparent as possible, so we've included our development TODOs in this file.
## TSCH
- [X] Clean up TSCH module
- [X] Session hijacking
- [X] Generate random name/path
- [X] Output
- [X] Add `tsch change`
- [ ] Serialize XML with default indent level?
### `tsch change`
- [ ] Add `--session` (like `tsch demand`)
- [ ] Add the option to avoid direct task start using TimeTrigger (similar to `tsch create`)
## SCMR
- [X] Clean up SCMR module
- [X] add dynamic string binding support
- [X] general cleanup. Use TSCH & WMI as reference
- [ ] Output
## DCOM
- [X] Add DCOM module
- [X] MMC20.Application method
- [X] Output
## WMI
- [X] Add WMI module
- [X] Clean up WMI module
- [X] Output
- [ ] WMI `reg` subcommand - read & edit the registry
- [ ] File transfer functionality
## Other
- [X] Add proxy support - see https://github.com/oiweiwei/go-msrpc/issues/21
- [X] README
- [X] pprof integration (hidden flag(s))
- [X] Descriptions for all modules and methods
- [ ] Add SMB file transfer interface
## Bugs
- [X] (Fixed) SMB transport for SCMR module - `rpc_s_cannot_support: The requested operation is not supported.`
- [X] (Fixed) Proxy - EPM doesn't use the proxy dialer
- [X] (Fixed) Kerberos requests don't dial through proxy
- [X] (Fixed) Panic when closing nil log file
- [X] `scmr change` doesn't revert service cmdline
- [X] Fix SCMR `change` method so that dependencies field isn't permanently overwritten
## Lower Priority
- [ ] `--shell` option
- [ ] Add Go tests
- [ ] ability to specify multiple targets
### TSCH
- [ ] Add more trigger types
### SCMR
- [ ] `psexec` with PsExeSVC.exe AND NOT Impacket's RemCom build - https://sensepost.com/blog/2025/psexecing-the-right-way-and-why-zero-trust-is-mandatory/
### DCOM
- [X] ShellWindows
- [ ] ShellBrowserWindow
### WinRM
- [ ] Add basic WinRM module - https://github.com/bryanmcnulty/winrm
- [ ] File transfer functionality
- [ ] Shell functionality
+113 -106
View File
@@ -1,34 +1,42 @@
package cmd
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
func registerLoggingFlags(fs *pflag.FlagSet) {
fs.SortFlags = false
fs.BoolVarP(&logDebug, "debug", "D", false, "Enable debug logging")
fs.StringVarP(&logOutput, "log-file", "O", "", "Write JSON logging output to `file`")
fs.BoolVarP(&logJson, "json", "j", false, "Write logging output in JSON lines")
fs.BoolVarP(&logQuiet, "quiet", "q", false, "Disable info logging")
fs.SortFlags = false
fs.BoolVarP(&logDebug, "debug", "D", false, "Enable debug logging")
fs.StringVarP(&logOutput, "log-file", "O", "", "Write JSON logging output to `file`")
fs.BoolVarP(&logJson, "json", "j", false, "Write logging output in JSON lines")
fs.BoolVarP(&logQuiet, "quiet", "q", false, "Disable info logging")
}
func registerNetworkFlags(fs *pflag.FlagSet) {
fs.StringVarP(&proxy, "proxy", "x", "", "Proxy `URI`")
fs.StringVarP(&rpcClient.Filter, "epm-filter", "F", "", "String binding to filter endpoints returned by the RPC endpoint mapper (EPM)")
fs.StringVar(&rpcClient.Endpoint, "endpoint", "", "Explicit RPC endpoint definition")
fs.BoolVar(&rpcClient.NoEpm, "no-epm", false, "Don't use EPM to discover RPC endpoints")
fs.BoolVar(&rpcClient.NoSign, "no-sign", false, "Disable signing on DCERPC messages")
fs.BoolVar(&rpcClient.NoSeal, "no-seal", false, "Disable packet stub encryption on DCERPC messages")
fs.StringVarP(&proxy, "proxy", "x", "", "Proxy `URI`")
fs.StringVarP(&rpcClient.Filter, "epm-filter", "F", "", "String binding to filter endpoints returned by the RPC endpoint mapper (EPM)")
fs.StringVar(&rpcClient.Endpoint, "endpoint", "", "Explicit RPC endpoint definition")
fs.BoolVar(&rpcClient.NoEpm, "no-epm", false, "Don't use EPM to discover RPC endpoints")
fs.BoolVar(&rpcClient.UseEpm, "epm", false, "Use EPM to discover available bindings")
fs.BoolVar(&rpcClient.NoSign, "no-sign", false, "Disable signing on DCERPC messages")
fs.BoolVar(&rpcClient.NoSeal, "no-seal", false, "Disable packet stub encryption on DCERPC messages")
//cmd.MarkFlagsMutuallyExclusive("endpoint", "epm-filter")
//cmd.MarkFlagsMutuallyExclusive("no-epm", "epm-filter")
if err := fs.MarkHidden("no-epm"); err != nil {
panic(err)
}
if err := fs.MarkDeprecated("no-epm", "use --epm=false instead"); err != nil {
panic(err)
}
//cmd.MarkFlagsMutuallyExclusive("endpoint", "epm-filter")
//cmd.MarkFlagsMutuallyExclusive("no-epm", "epm-filter")
}
// FUTURE: automatically stage & execute file
@@ -40,127 +48,126 @@ func registerStageFlags(fs *pflag.FlagSet) {
*/
func registerExecutionFlags(fs *pflag.FlagSet) {
fs.StringVarP(&exec.Input.Executable, "exec", "e", "", "Remote Windows executable to invoke")
fs.StringVarP(&exec.Input.Arguments, "args", "a", "", "Process command line arguments")
fs.StringVarP(&exec.Input.Command, "command", "c", "", "Windows process command line (executable & arguments)")
fs.StringVarP(&exec.Input.Executable, "exec", "e", "", "Remote Windows executable to invoke")
fs.StringVarP(&exec.Input.Arguments, "args", "a", "", "Process command line arguments")
fs.StringVarP(&exec.Input.Command, "command", "c", "", "Windows process command line (executable & arguments)")
//cmd.MarkFlagsOneRequired("executable", "command")
//cmd.MarkFlagsMutuallyExclusive("executable", "command")
//cmd.MarkFlagsOneRequired("executable", "command")
//cmd.MarkFlagsMutuallyExclusive("executable", "command")
}
func registerExecutionOutputFlags(fs *pflag.FlagSet) {
fs.StringVarP(&outputPath, "out", "o", "", `Fetch execution output to file or "-" for standard output`)
fs.StringVarP(&outputMethod, "out-method", "m", "smb", "Method to fetch execution output")
//fs.StringVar(&exec.Output.RemotePath, "out-remote", "", "Location to temporarily store output on remote filesystem")
fs.BoolVar(&exec.Output.NoDelete, "no-delete-out", false, "Preserve output file on remote filesystem")
fs.StringVarP(&outputPath, "out", "o", "", `Fetch execution output to file or "-" for standard output`)
fs.StringVarP(&outputMethod, "out-method", "m", "smb", "Method to fetch execution output")
//fs.StringVar(&exec.Output.RemotePath, "out-remote", "", "Location to temporarily store output on remote filesystem")
fs.BoolVar(&exec.Output.NoDelete, "no-delete-out", false, "Preserve output file on remote filesystem")
}
func args(reqs ...func(*cobra.Command, []string) error) (fn func(*cobra.Command, []string) error) {
return func(cmd *cobra.Command, args []string) (err error) {
return func(cmd *cobra.Command, args []string) (err error) {
for _, req := range reqs {
if err = req(cmd, args); err != nil {
return
}
}
return
}
for _, req := range reqs {
if err = req(cmd, args); err != nil {
return
}
}
return
}
}
func argsAcceptValues(name string, in *string, valid ...string) func(*cobra.Command, []string) error {
return func(*cobra.Command, []string) error {
for _, v := range valid {
if *in == v {
return nil
}
}
if j, err := json.Marshal(valid); err == nil {
return fmt.Errorf("parse %s: %q doesn't match any accepted values: %s", name, *in, string(j))
} else {
return err
}
}
return func(*cobra.Command, []string) error {
for _, v := range valid {
if *in == v {
return nil
}
}
if j, err := json.Marshal(valid); err == nil {
return fmt.Errorf("parse %s: %q doesn't match any accepted values: %s", name, *in, string(j))
} else {
return err
}
}
}
func argsTarget(proto string) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
return func(cmd *cobra.Command, args []string) (err error) {
if len(args) != 1 {
return errors.New("command require exactly one positional argument: [target]")
}
if len(args) != 1 {
return errors.New("command require exactly one positional argument: [target]")
}
if credential, target, err = adAuthOpts.WithTarget(context.TODO(), proto, args[0]); err != nil {
return fmt.Errorf("failed to parse target: %w", err)
}
if credential, target, err = adAuthOpts.WithTarget(context.TODO(), proto, args[0]); err != nil {
return fmt.Errorf("failed to parse target: %w", err)
}
if credential == nil {
return errors.New("no credentials supplied")
}
if target == nil {
return errors.New("no target supplied")
}
return
}
if credential == nil {
return errors.New("no credentials supplied")
}
if target == nil {
return errors.New("no target supplied")
}
return
}
}
func argsSmbClient() func(cmd *cobra.Command, args []string) error {
return args(
argsTarget("cifs"),
return args(
argsTarget("cifs"),
func(_ *cobra.Command, _ []string) error {
func(_ *cobra.Command, _ []string) error {
smbClient.Credential = credential
smbClient.Target = target
smbClient.Proxy = proxy
smbClient.Credential = credential
smbClient.Target = target
smbClient.Proxy = proxy
return smbClient.Parse(context.TODO())
},
)
return smbClient.Parse(context.TODO())
},
)
}
func argsRpcClient(proto string, endpoint string) func(cmd *cobra.Command, args []string) error {
return args(
argsTarget(proto),
return args(
argsTarget(proto),
func(cmd *cobra.Command, args []string) (err error) {
if rpcClient.Endpoint == "" {
if endpoint != "" {
rpcClient.Endpoint = endpoint
rpcClient.NoEpm = true
} else {
rpcClient.NoEpm = false
}
}
rpcClient.Target = target
rpcClient.Credential = credential
rpcClient.Proxy = proxy
func(cmd *cobra.Command, args []string) (err error) {
switch {
case rpcClient.Endpoint != "":
case endpoint == "":
rpcClient.UseEpm = true
default:
rpcClient.Endpoint = endpoint
}
rpcClient.Target = target
rpcClient.Credential = credential
rpcClient.Proxy = proxy
return rpcClient.Parse(context.TODO())
},
)
return rpcClient.Parse(context.TODO())
},
)
}
func argsOutput(methods ...string) func(cmd *cobra.Command, args []string) error {
var as []func(*cobra.Command, []string) error
var as []func(*cobra.Command, []string) error
for _, method := range methods {
if method == "smb" {
as = append(as, argsSmbClient())
}
}
for _, method := range methods {
if method == "smb" {
as = append(as, argsSmbClient())
}
}
return args(append(as, func(*cobra.Command, []string) (err error) {
return args(append(as, func(*cobra.Command, []string) (err error) {
if outputPath != "" {
if outputPath == "-" {
exec.Output.Writer = os.Stdout
if outputPath != "" {
if outputPath == "-" {
exec.Output.Writer = os.Stdout
} else if exec.Output.Writer, err = os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
log.Fatal().Err(err).Msg("Failed to open output file")
}
}
return
})...)
} else if exec.Output.Writer, err = os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
log.Fatal().Err(err).Msg("Failed to open output file")
}
}
return
})...)
}
+67 -67
View File
@@ -1,111 +1,111 @@
package dce
import (
"context"
"fmt"
"context"
"fmt"
"github.com/RedTeamPentesting/adauth/smbauth"
"github.com/oiweiwei/go-msrpc/dcerpc"
"github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3"
msrpcSMB2 "github.com/oiweiwei/go-msrpc/smb2"
"github.com/rs/zerolog"
"github.com/RedTeamPentesting/adauth/smbauth"
"github.com/oiweiwei/go-msrpc/dcerpc"
"github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3"
msrpcSMB2 "github.com/oiweiwei/go-msrpc/smb2"
"github.com/rs/zerolog"
)
type Client struct {
Options
Options
conn dcerpc.Conn
conn dcerpc.Conn
}
func (c *Client) String() string {
return ClientName
return ClientName
}
func (c *Client) Reconnect(ctx context.Context, opts ...dcerpc.Option) (err error) {
c.DcerpcOptions = append(c.DcerpcOptions, opts...)
c.DcerpcOptions = append(c.DcerpcOptions, opts...)
return c.Connect(ctx)
return c.Connect(ctx)
}
func (c *Client) Dce() (dce dcerpc.Conn) {
return c.conn
return c.conn
}
func (c *Client) Logger(ctx context.Context) (log zerolog.Logger) {
return zerolog.Ctx(ctx).With().
Str("client", c.String()).Logger()
return zerolog.Ctx(ctx).With().
Str("client", c.String()).Logger()
}
func (c *Client) Connect(ctx context.Context) (err error) {
log := c.Logger(ctx)
ctx = log.WithContext(ctx)
log := c.Logger(ctx)
ctx = log.WithContext(ctx)
var do, eo []dcerpc.Option
var do, eo []dcerpc.Option
do = append(do, c.DcerpcOptions...)
do = append(do, c.authOptions...)
do = append(do, c.DcerpcOptions...)
do = append(do, c.authOptions...)
if c.Smb {
var so []msrpcSMB2.DialerOption
if c.Smb {
var so []msrpcSMB2.DialerOption
if !c.NoSign {
so = append(so, msrpcSMB2.WithSign())
eo = append(eo, dcerpc.WithSign())
}
if !c.NoSeal {
so = append(so, msrpcSMB2.WithSeal())
eo = append(eo, dcerpc.WithSeal())
}
if !c.NoSign {
so = append(so, msrpcSMB2.WithSign())
eo = append(eo, dcerpc.WithSign())
}
if !c.NoSeal {
so = append(so, msrpcSMB2.WithSeal())
eo = append(eo, dcerpc.WithSeal())
}
if smbDialer, err := smbauth.Dialer(ctx, c.Credential, c.Target, &smbauth.Options{
SMBOptions: so,
KerberosDialer: c.dialer,
}); err != nil {
return fmt.Errorf("parse smb auth: %w", err)
if smbDialer, err := smbauth.Dialer(ctx, c.Credential, c.Target, &smbauth.Options{
SMBOptions: so,
KerberosDialer: c.dialer,
}); err != nil {
return fmt.Errorf("parse smb auth: %w", err)
} else {
do = append(do, dcerpc.WithSMBDialer(smbDialer))
}
} else {
} else {
do = append(do, dcerpc.WithSMBDialer(smbDialer))
}
} else {
if !c.NoSign {
do = append(do, dcerpc.WithSign())
eo = append(eo, dcerpc.WithSign())
}
if !c.NoSeal {
do = append(do, dcerpc.WithSeal())
eo = append(eo, dcerpc.WithSeal())
}
}
if !c.NoSign {
do = append(do, dcerpc.WithSign())
eo = append(eo, dcerpc.WithSign())
}
if !c.NoSeal {
do = append(do, dcerpc.WithSeal())
eo = append(eo, dcerpc.WithSeal())
}
}
if !c.NoLog {
do = append(do, dcerpc.WithLogger(log))
eo = append(eo, dcerpc.WithLogger(log))
}
if !c.NoLog {
do = append(do, dcerpc.WithLogger(log))
eo = append(eo, dcerpc.WithLogger(log))
}
if !c.NoEpm {
log.Debug().Msg("Using endpoint mapper")
if c.UseEpm && !c.NoEpm {
log.Debug().Msg("Using endpoint mapper")
eo = append(eo, c.EpmOptions...)
eo = append(eo, c.authOptions...)
eo = append(eo, c.EpmOptions...)
eo = append(eo, c.authOptions...)
do = append(do, epm.EndpointMapper(ctx, c.Host, eo...))
}
do = append(do, epm.EndpointMapper(ctx, c.Host, eo...))
}
for _, e := range c.stringBindings {
do = append(do, dcerpc.WithEndpoint(e.String()))
}
for _, e := range c.stringBindings {
do = append(do, dcerpc.WithEndpoint(e.String()))
}
if c.conn, err = dcerpc.Dial(ctx, c.Host, do...); err != nil {
if c.conn, err = dcerpc.Dial(ctx, c.Host, do...); err != nil {
log.Error().Err(err).Msgf("Failed to connect to %s endpoint", c.String())
return fmt.Errorf("dial %s: %w", c.String(), err)
}
log.Error().Err(err).Msgf("Failed to connect to %s endpoint", c.String())
return fmt.Errorf("dial %s: %w", c.String(), err)
}
return
return
}
func (c *Client) Close(ctx context.Context) (err error) {
return c.conn.Close(ctx)
return c.conn.Close(ctx)
}
+92 -89
View File
@@ -1,118 +1,121 @@
package dce
import (
"context"
"fmt"
"net"
"context"
"fmt"
"net"
"github.com/FalconOpsLLC/goexec/pkg/goexec"
"github.com/RedTeamPentesting/adauth"
"github.com/RedTeamPentesting/adauth/dcerpcauth"
"github.com/oiweiwei/go-msrpc/dcerpc"
"github.com/FalconOpsLLC/goexec/pkg/goexec"
"github.com/RedTeamPentesting/adauth"
"github.com/RedTeamPentesting/adauth/dcerpcauth"
"github.com/oiweiwei/go-msrpc/dcerpc"
)
type Options struct {
goexec.ClientOptions
goexec.AuthOptions
goexec.ClientOptions
goexec.AuthOptions
// NoSign disables packet signing by omitting dcerpc.WithSign()
NoSign bool `json:"no_sign" yaml:"no_sign"`
// NoSign disables packet signing by omitting dcerpc.WithSign()
NoSign bool `json:"no_sign" yaml:"no_sign"`
// NoSeal disables packet stub encryption by omitting dcerpc.WithSeal()
NoSeal bool `json:"no_seal" yaml:"no_seal"`
// NoSeal disables packet stub encryption by omitting dcerpc.WithSeal()
NoSeal bool `json:"no_seal" yaml:"no_seal"`
// NoLog disables logging by omitting dcerpc.WithLogger(...)
NoLog bool `json:"no_log" yaml:"no_log"`
// NoLog disables logging by omitting dcerpc.WithLogger(...)
NoLog bool `json:"no_log" yaml:"no_log"`
// NoEpm disables DCE endpoint mapper communications
NoEpm bool `json:"no_epm" yaml:"no_epm"`
// UseEpm enables DCE endpoint mapper communications
UseEpm bool `json:"use_epm" yaml:"use_epm"`
// Endpoint stores the explicit DCE string binding to use
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
// NoEpm disables DCE endpoint mapper communications
NoEpm bool `json:"no_epm" yaml:"no_epm"` // Deprecated in favor of UseEpm
// Filter stores the filter for returned endpoints from an endpoint mapper
Filter string `json:"filter,omitempty" yaml:"filter,omitempty"`
// Endpoint stores the explicit DCE string binding to use
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
// Smb enables SMB transport for DCE/RPC
Smb bool `json:"use_smb" yaml:"use_smb"`
// Filter stores the filter for returned endpoints from an endpoint mapper
Filter string `json:"filter,omitempty" yaml:"filter,omitempty"`
stringBindings []*dcerpc.StringBinding
dialer goexec.Dialer
authOptions []dcerpc.Option
DcerpcOptions []dcerpc.Option
EpmOptions []dcerpc.Option
// Smb enables SMB transport for DCE/RPC
Smb bool `json:"use_smb" yaml:"use_smb"`
stringBindings []*dcerpc.StringBinding
dialer goexec.Dialer
authOptions []dcerpc.Option
DcerpcOptions []dcerpc.Option
EpmOptions []dcerpc.Option
}
func (c *Client) Parse(ctx context.Context) (err error) {
// Reset internals
{
c.dialer = nil
c.stringBindings = []*dcerpc.StringBinding{}
c.authOptions = []dcerpc.Option{}
c.DcerpcOptions = []dcerpc.Option{}
c.EpmOptions = []dcerpc.Option{
dcerpc.WithSign(), // Require signing for EPM
}
}
// Reset internals
{
c.dialer = nil
c.stringBindings = []*dcerpc.StringBinding{}
c.authOptions = []dcerpc.Option{}
c.DcerpcOptions = []dcerpc.Option{}
c.EpmOptions = []dcerpc.Option{
dcerpc.WithSign(), // Require signing for EPM
}
}
if !c.NoSeal {
// Enable encryption
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy))
c.EpmOptions = append(c.EpmOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy))
}
if !c.NoSign {
// Enable signing
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSign())
}
if !c.NoSeal {
// Enable encryption
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy))
c.EpmOptions = append(c.EpmOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy))
}
if !c.NoSign {
// Enable signing
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSign())
}
// Parse DCERPC endpoint
if c.Endpoint != "" {
sb, err := dcerpc.ParseStringBinding(c.Endpoint)
if err != nil {
return err
}
if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe {
c.Smb = true
}
c.stringBindings = append(c.stringBindings, sb)
}
// Parse DCERPC endpoint
if c.Endpoint != "" {
sb, err := dcerpc.ParseStringBinding(c.Endpoint)
if err != nil {
return err
}
if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe {
c.Smb = true
}
c.stringBindings = append(c.stringBindings, sb)
}
// Parse EPM filter
if c.Filter != "" {
sb, err := dcerpc.ParseStringBinding(c.Filter)
if err != nil {
return err
}
if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe {
c.Smb = true
}
c.stringBindings = append(c.stringBindings, sb)
}
// Parse EPM filter
if c.Filter != "" {
sb, err := dcerpc.ParseStringBinding(c.Filter)
if err != nil {
return err
}
if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe {
c.Smb = true
}
c.stringBindings = append(c.stringBindings, sb)
}
if c.Proxy != "" {
// Parse proxy URL
c.dialer, err = goexec.ParseProxyURI(c.Proxy)
if err != nil {
return err
}
if c.Proxy != "" {
// Parse proxy URL
c.dialer, err = goexec.ParseProxyURI(c.Proxy)
if err != nil {
return err
}
d := adauth.AsContextDialer(c.dialer)
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithDialer(d))
c.EpmOptions = append(c.EpmOptions, dcerpc.WithDialer(d))
d := adauth.AsContextDialer(c.dialer)
c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithDialer(d))
c.EpmOptions = append(c.EpmOptions, dcerpc.WithDialer(d))
} else {
c.dialer = &net.Dialer{}
}
} else {
c.dialer = &net.Dialer{}
}
// Parse authentication parameters
if c.authOptions, err = dcerpcauth.AuthenticationOptions(ctx, c.Credential, c.Target, &dcerpcauth.Options{
KerberosDialer: c.dialer, // Use the same net dialer as dcerpc
}); err != nil {
return fmt.Errorf("parse auth c: %w", err)
}
// Parse authentication parameters
if c.authOptions, err = dcerpcauth.AuthenticationOptions(ctx, c.Credential, c.Target, &dcerpcauth.Options{
KerberosDialer: c.dialer, // Use the same net dialer as dcerpc
}); err != nil {
return fmt.Errorf("parse auth c: %w", err)
}
c.Host = c.Target.AddressWithoutPort()
c.Host = c.Target.AddressWithoutPort()
return
return
}
+57 -59
View File
@@ -1,99 +1,97 @@
package goexec
import (
"context"
"fmt"
"io"
"strings"
"context"
"fmt"
"io"
"strings"
)
type OutputProvider interface {
GetOutput(ctx context.Context, writer io.Writer) (err error)
Clean(ctx context.Context) (err error)
GetOutput(ctx context.Context, writer io.Writer) (err error)
Clean(ctx context.Context) (err error)
}
type ExecutionIO struct {
Cleaner
Cleaner
Input *ExecutionInput
Output *ExecutionOutput
Input *ExecutionInput
Output *ExecutionOutput
}
type ExecutionOutput struct {
NoDelete bool
RemotePath string
Provider OutputProvider
Writer io.WriteCloser
NoDelete bool
RemotePath string
Provider OutputProvider
Writer io.WriteCloser
}
type ExecutionInput struct {
StageFile io.ReadCloser
Executable string
ExecutablePath string
Arguments string
Command string
StageFile io.ReadCloser
Executable string
ExecutablePath string
Arguments string
Command string
}
func (execIO *ExecutionIO) GetOutput(ctx context.Context) (err error) {
if execIO.Output.Provider != nil {
return execIO.Output.Provider.GetOutput(ctx, execIO.Output.Writer)
}
return nil
if execIO.Output.Provider != nil {
return execIO.Output.Provider.GetOutput(ctx, execIO.Output.Writer)
}
return nil
}
func (execIO *ExecutionIO) Clean(ctx context.Context) (err error) {
if execIO.Output.Provider != nil {
return execIO.Output.Provider.Clean(ctx)
}
return nil
if execIO.Output.Provider != nil {
return execIO.Output.Provider.Clean(ctx)
}
return nil
}
func (execIO *ExecutionIO) CommandLine() (cmd []string) {
if execIO.Output.Provider != nil && execIO.Output.RemotePath != "" {
return []string{
`C:\Windows\System32\cmd.exe`,
fmt.Sprintf(`/C %s > %s 2>&1`, execIO.Input.String(), execIO.Output.RemotePath),
}
}
return execIO.Input.CommandLine()
if execIO.Output.Provider != nil && execIO.Output.RemotePath != "" {
return []string{
`C:\Windows\System32\cmd.exe`,
fmt.Sprintf(`/C %s > %s 2>&1`, execIO.Input.String(), execIO.Output.RemotePath),
}
}
return execIO.Input.CommandLine()
}
func (execIO *ExecutionIO) String() (str string) {
cmd := execIO.CommandLine()
// Ensure that executable paths are quoted
if strings.Contains(cmd[0], " ") {
str = fmt.Sprintf(`%q %s`, cmd[0], strings.Join(cmd[1:], " "))
} else {
str = strings.Join(cmd, " ")
}
return strings.Trim(str, " \t\n\r") // trim whitespace
cmd := execIO.CommandLine()
// Ensure that executable paths are quoted
if strings.Contains(cmd[0], " ") {
str = fmt.Sprintf(`%q %s`, cmd[0], strings.Join(cmd[1:], " "))
} else {
str = strings.Join(cmd, " ")
}
return strings.Trim(str, " \t\n\r") // trim whitespace
}
func (i *ExecutionInput) CommandLine() (cmd []string) {
cmd = make([]string, 2)
cmd[1] = i.Arguments
cmd = make([]string, 2)
cmd[1] = i.Arguments
switch {
case i.Command != "":
return strings.SplitN(i.Command, " ", 2)
switch {
case i.Command != "":
copy(cmd, strings.SplitN(i.Command, " ", 2))
case i.ExecutablePath != "":
cmd[0] = i.ExecutablePath
case i.Executable != "":
cmd[0] = i.Executable
}
case i.ExecutablePath != "":
cmd[0] = i.ExecutablePath
case i.Executable != "":
cmd[0] = i.Executable
}
return cmd
return cmd
}
func (i *ExecutionInput) String() string {
return strings.Join(i.CommandLine(), " ")
return strings.Join(i.CommandLine(), " ")
}
func (i *ExecutionInput) Reader() (reader io.Reader) {
if i.StageFile != nil {
return i.StageFile
}
return strings.NewReader(i.String())
if i.StageFile != nil {
return i.StageFile
}
return strings.NewReader(i.String())
}