mirror of
https://github.com/RedTeamPentesting/adauth
synced 2026-06-08 12:20:46 +00:00
Refactoring
This commit is contained in:
@@ -53,9 +53,9 @@ Kerberos authentication is possible even when specifying the target via IP
|
||||
address if reverse lookups are possible. Similarly, the domain can be omitted
|
||||
when the target hostname contains the domain.
|
||||
|
||||
The library also contains helper packages for LDAP and DCERPC, a Kerebros PKINIT
|
||||
implementation as well as helpers for creating and writing CCache files (see
|
||||
examples).
|
||||
The library also contains helper packages for LDAP, SMB and DCERPC, a Kerebros
|
||||
PKINIT implementation as well as helpers for creating and writing CCache files
|
||||
(see examples).
|
||||
|
||||
## Features
|
||||
|
||||
@@ -70,12 +70,14 @@ examples).
|
||||
* Kerberos, NTLM, Simple Bind
|
||||
* mTLS Authentication / Pass-the-Certificate (LDAPS or LDAP+StartTLS)
|
||||
* Channel Binding (Kerberos and NTLM)
|
||||
* SMB
|
||||
* Kerberos, NTLM
|
||||
* Signing and Sealing
|
||||
* DCERPC:
|
||||
* Kerberos, NTLM
|
||||
* Raw endpoits (with port mapping)
|
||||
* Named pipes (SMB)
|
||||
* Signing
|
||||
* Sealing
|
||||
* Signing and Sealing
|
||||
|
||||
## Caveats
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
// function.
|
||||
type Options struct {
|
||||
// SMBOptions holds options for the SMB dialer. This dialer is only used
|
||||
// with the named pipe transport. If SMBOptions is nil, sealing will be
|
||||
// enabled for the smb dialer, specify an empty slice to disable this
|
||||
// default.
|
||||
// with the named pipe transport. If SMBOptions is nil, encryption/sealing
|
||||
// will be enabled for the SMB dialer, specify an empty slice to disable
|
||||
// this default.
|
||||
SMBOptions []smb2.DialerOption
|
||||
// PKINITOptions can be used to modify the Kerberos PKINIT behavior.
|
||||
PKINITOptions []pkinit.Option
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/oiweiwei/go-msrpc/msrpc/dtyp"
|
||||
"github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3"
|
||||
"github.com/oiweiwei/go-msrpc/msrpc/samr/samr/v1"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/gssapi"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
@@ -43,7 +42,7 @@ func run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := gssapi.NewSecurityContext(context.Background())
|
||||
ctx := context.Background()
|
||||
|
||||
dcerpcOpts, err := dcerpcauth.AuthenticationOptions(ctx, creds, target, dcerpcauthOpts)
|
||||
if err != nil {
|
||||
|
||||
+79
-71
@@ -1,97 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/RedTeamPentesting/adauth/smbauth"
|
||||
"github.com/oiweiwei/go-msrpc/smb2"
|
||||
"github.com/oiweiwei/go-msrpc/ssp"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/RedTeamPentesting/adauth"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/gssapi"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/RedTeamPentesting/adauth/smbauth"
|
||||
|
||||
"github.com/RedTeamPentesting/adauth"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
debug bool
|
||||
authOpts = &adauth.Options{
|
||||
Debug: adauth.NewDebugFunc(&debug, os.Stderr, true),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
pflag.CommandLine.BoolVar(&debug, "debug", false, "Enable debug output")
|
||||
authOpts.RegisterFlags(pflag.CommandLine)
|
||||
gssapi.AddMechanism(ssp.SPNEGO)
|
||||
gssapi.AddMechanism(ssp.NTLM)
|
||||
}
|
||||
|
||||
func run() error {
|
||||
pflag.Parse()
|
||||
var (
|
||||
debug bool
|
||||
authOpts = &adauth.Options{
|
||||
Debug: adauth.NewDebugFunc(&debug, os.Stderr, true),
|
||||
}
|
||||
smbauthOpts = &smbauth.Options{
|
||||
Debug: authOpts.Debug,
|
||||
}
|
||||
)
|
||||
|
||||
if len(pflag.Args()) != 1 {
|
||||
return fmt.Errorf("usage: %s <target> [--debug]", binaryName())
|
||||
}
|
||||
pflag.CommandLine.BoolVar(&debug, "debug", false, "Enable debug output")
|
||||
authOpts.RegisterFlags(pflag.CommandLine)
|
||||
pflag.Parse()
|
||||
|
||||
creds, target, err := authOpts.WithTarget(context.Background(), "host", pflag.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pflag.Args()) != 1 {
|
||||
return fmt.Errorf("usage: %s [options] <target>", binaryName())
|
||||
}
|
||||
|
||||
ctx := gssapi.NewSecurityContext(context.Background())
|
||||
creds, target, err := authOpts.WithTarget(context.Background(), "host", pflag.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smbOpts, secOpts, err := smbauth.AuthenticationOptions(ctx, creds, target, &smbauth.Options{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if target.Port == "" {
|
||||
target.Port = "445"
|
||||
}
|
||||
|
||||
// Create go-smb2 Dialer
|
||||
dialer := smb2.NewDialer(append(smbOpts, smb2.WithSecurity(secOpts...))...)
|
||||
ctx := context.Background()
|
||||
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort(target.AddressWithoutPort(), "445"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
smbDialer, err := smbauth.Dialer(ctx, creds, target, smbauthOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setup SMB authentication: %w", err)
|
||||
}
|
||||
|
||||
sess, err := dialer.Dial(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sess.Logoff()
|
||||
conn, err := net.Dial("tcp", target.Address())
|
||||
if err != nil {
|
||||
return fmt.Errorf("dial: %w", err)
|
||||
}
|
||||
|
||||
names, err := sess.ListSharenames()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
for _, name := range names {
|
||||
fmt.Println(name)
|
||||
}
|
||||
return nil
|
||||
sess, err := smbDialer.DialContext(ctx, conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create session: %w", err)
|
||||
}
|
||||
|
||||
defer sess.Logoff()
|
||||
|
||||
shares, err := sess.ListSharenames()
|
||||
if err != nil {
|
||||
return fmt.Errorf("list share names: %w", err)
|
||||
}
|
||||
|
||||
if len(shares) == 0 {
|
||||
fmt.Println("No shares available")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println("Shares:")
|
||||
|
||||
for _, share := range shares {
|
||||
fmt.Printf(" - %s\n", share)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func binaryName() string {
|
||||
executable, err := os.Executable()
|
||||
if err == nil {
|
||||
return filepath.Base(executable)
|
||||
}
|
||||
executable, err := os.Executable()
|
||||
if err == nil {
|
||||
return filepath.Base(executable)
|
||||
}
|
||||
|
||||
if len(os.Args) > 0 {
|
||||
return filepath.Base(os.Args[0])
|
||||
}
|
||||
if len(os.Args) > 0 {
|
||||
return filepath.Base(os.Args[0])
|
||||
}
|
||||
|
||||
return "list-shares"
|
||||
return "smb"
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := run()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
err := run()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ require (
|
||||
github.com/go-ldap/ldap/v3 v3.4.11-0.20250110131057-5d1b644709df
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4
|
||||
github.com/oiweiwei/go-msrpc v1.2.5
|
||||
github.com/oiweiwei/go-smb2.fork v1.0.0
|
||||
github.com/oiweiwei/gokrb5.fork/v9 v9.0.2
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/vadimi/go-ntlm v1.2.1
|
||||
@@ -26,10 +27,9 @@ require (
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/oiweiwei/go-smb2.fork v1.0.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
github.com/rs/zerolog v1.34.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
)
|
||||
|
||||
@@ -55,10 +55,7 @@ github.com/oiweiwei/gokrb5.fork/v9 v9.0.2/go.mod h1:KEnkAYUYqZ5VwzxLFbv3JHlRhCvd
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
@@ -82,8 +79,6 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -102,8 +97,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -124,8 +119,6 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
@@ -146,8 +139,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
+80
-144
@@ -1,167 +1,103 @@
|
||||
package smbauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/RedTeamPentesting/adauth"
|
||||
"github.com/RedTeamPentesting/adauth/pkinit"
|
||||
"github.com/RedTeamPentesting/adauth"
|
||||
"github.com/RedTeamPentesting/adauth/dcerpcauth"
|
||||
"github.com/RedTeamPentesting/adauth/pkinit"
|
||||
|
||||
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||
"github.com/oiweiwei/go-msrpc/smb2"
|
||||
"github.com/oiweiwei/go-msrpc/ssp"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/credential"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/gssapi"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/krb5"
|
||||
"github.com/oiweiwei/go-smb2.fork"
|
||||
|
||||
msrpcSMB2 "github.com/oiweiwei/go-msrpc/smb2"
|
||||
"github.com/oiweiwei/go-msrpc/ssp"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/gssapi"
|
||||
"github.com/oiweiwei/go-msrpc/ssp/krb5"
|
||||
)
|
||||
|
||||
// Options holds options that modify the behavior of the AuthenticationOptions
|
||||
// function.
|
||||
// Options holds options that modify the behavior of the Dialer function.
|
||||
type Options struct {
|
||||
// SMBOptions holds options for the SMB dialer. If SMBOptions is nil,
|
||||
// sealing will be enabled for the smb dialer, specify an empty slice
|
||||
// to disable this default.
|
||||
SMBOptions []smb2.DialerOption
|
||||
// SMBOptions holds options for the SMB dialer. If SMBOptions is nil,
|
||||
// encryption/sealing will be enabled. Specify an empty slice to disable
|
||||
// this default.
|
||||
SMBOptions []msrpcSMB2.DialerOption
|
||||
|
||||
// PKINITOptions can be used to modify the Kerberos PKINIT behavior.
|
||||
PKINITOptions []pkinit.Option
|
||||
// PKINITOptions can be used to modify the Kerberos PKINIT behavior.
|
||||
PKINITOptions []pkinit.Option
|
||||
|
||||
// Debug can be set to enable debug output, for example with
|
||||
// adauth.NewDebugFunc(...).
|
||||
Debug func(string, ...any)
|
||||
// Debug can be set to enable debug output, for example with
|
||||
// adauth.NewDebugFunc(...).
|
||||
Debug func(string, ...any)
|
||||
}
|
||||
|
||||
func (opts *Options) debug(format string, a ...any) {
|
||||
if opts == nil || opts.Debug == nil {
|
||||
return
|
||||
}
|
||||
if opts == nil || opts.Debug == nil {
|
||||
return
|
||||
}
|
||||
|
||||
opts.Debug(format, a...)
|
||||
opts.Debug(format, a...)
|
||||
}
|
||||
|
||||
// AuthenticationOptions returns the security context options for
|
||||
// smb2.WithSecurity. It is possible to configure the SMB, PKINIT
|
||||
// and debug behavior using the optional upstreamOptions argument.
|
||||
func AuthenticationOptions(
|
||||
ctx context.Context, creds *adauth.Credential, target *adauth.Target,
|
||||
upstreamOptions *Options,
|
||||
) (dialOptions []smb2.DialerOption, secOptions []gssapi.ContextOption, err error) {
|
||||
// Dialer returns an SMB dialer which is prepared for authentication with the
|
||||
// given credentials. The dialer can be further customized with
|
||||
// options.SMBDialerOptions.
|
||||
func Dialer(
|
||||
ctx context.Context, creds *adauth.Credential, target *adauth.Target, options *Options,
|
||||
) (*smb2.Dialer, error) {
|
||||
smbCreds, err := dcerpcauth.DCERPCCredentials(ctx, creds, &dcerpcauth.Options{
|
||||
PKINITOptions: options.PKINITOptions,
|
||||
Debug: options.debug,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dialOptions = upstreamOptions.SMBOptions; dialOptions == nil {
|
||||
dialOptions = []smb2.DialerOption{smb2.WithSeal()}
|
||||
}
|
||||
dialerOptions := options.SMBOptions
|
||||
if dialerOptions == nil {
|
||||
dialerOptions = append(dialerOptions, msrpcSMB2.WithSeal())
|
||||
}
|
||||
|
||||
smbCredentials, err := SMBCredentials(ctx, creds, upstreamOptions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch {
|
||||
case target.UseKerberos || creds.ClientCert != nil:
|
||||
spn, err := target.SPN(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build SPN: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case target.UseKerberos || creds.ClientCert != nil:
|
||||
spn, err := target.SPN(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("build SPN: %w", err)
|
||||
}
|
||||
upstreamOptions.debug("Using Kerberos with SPN %q", spn)
|
||||
options.debug("Using Kerberos with SPN %q", spn)
|
||||
|
||||
krbConf, err := creds.KerberosConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("generate Kerberos config: %w", err)
|
||||
}
|
||||
krbConf, err := creds.KerberosConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generate Kerberos config: %w", err)
|
||||
}
|
||||
|
||||
secOptions = append(secOptions,
|
||||
gssapi.WithTargetName(spn),
|
||||
gssapi.WithCredential(smbCredentials),
|
||||
gssapi.WithMechanismFactory(ssp.KRB5, &krb5.Config{
|
||||
KRB5Config: krbConf,
|
||||
CCachePath: creds.CCache,
|
||||
DisablePAFXFAST: true,
|
||||
DCEStyle: true,
|
||||
}),
|
||||
)
|
||||
default:
|
||||
upstreamOptions.debug("Using NTLM")
|
||||
dialerOptions = append(dialerOptions, msrpcSMB2.WithSecurity(
|
||||
gssapi.WithTargetName(spn),
|
||||
gssapi.WithCredential(smbCreds),
|
||||
gssapi.WithMechanismFactory(ssp.KRB5, &krb5.Config{
|
||||
KRB5Config: krbConf,
|
||||
CCachePath: creds.CCache,
|
||||
DisablePAFXFAST: true,
|
||||
}),
|
||||
))
|
||||
|
||||
secOptions = append(secOptions,
|
||||
gssapi.WithCredential(smbCredentials),
|
||||
gssapi.WithMechanismFactory(ssp.NTLM),
|
||||
)
|
||||
// Try fetching SPN
|
||||
if spn, err := target.SPN(ctx); err == nil {
|
||||
secOptions = append(secOptions, gssapi.WithTargetName(spn))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SMBCredentials(ctx context.Context, creds *adauth.Credential, options *Options) (credential.Credential, error) {
|
||||
switch {
|
||||
case creds.Password != "":
|
||||
options.debug("Authenticating with password")
|
||||
|
||||
return credential.NewFromPassword(creds.LogonNameWithUpperCaseDomain(), creds.Password), nil
|
||||
case creds.AESKey != "":
|
||||
options.debug("Authenticating with AES key")
|
||||
|
||||
keyTab, err := creds.Keytab()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keytab: %w", err)
|
||||
}
|
||||
|
||||
return &keytabCredentials{username: creds.Username, domain: creds.Domain, keytab: keyTab}, nil
|
||||
case creds.NTHash != "":
|
||||
options.debug("Authenticating with NT hash")
|
||||
|
||||
return credential.NewFromNTHash(creds.LogonNameWithUpperCaseDomain(), creds.NTHash), nil
|
||||
case creds.PasswordIsEmtpyString:
|
||||
options.debug("Authenticating with empty password")
|
||||
|
||||
return credential.NewFromPassword(strings.ToUpper(creds.Domain)+`\`+creds.Username, ""), nil
|
||||
case creds.ClientCert != nil:
|
||||
options.debug("Authenticating with client certificate (PKINIT)")
|
||||
|
||||
krbConf, err := creds.KerberosConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generate kerberos config: %w", err)
|
||||
}
|
||||
|
||||
ccache, err := pkinit.Authenticate(ctx, creds.Username, strings.ToUpper(creds.Domain),
|
||||
creds.ClientCert, creds.ClientCertKey, krbConf, options.PKINITOptions...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("PKINIT: %w", err)
|
||||
}
|
||||
|
||||
return credential.NewFromCCache(creds.LogonNameWithUpperCaseDomain(), ccache), nil
|
||||
case creds.CCache != "":
|
||||
options.debug("Authenticating with ccache")
|
||||
|
||||
return credential.NewFromPassword(creds.LogonNameWithUpperCaseDomain(), ""), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("no credentials available")
|
||||
}
|
||||
}
|
||||
|
||||
type keytabCredentials struct {
|
||||
keytab *keytab.Keytab
|
||||
username string
|
||||
domain string
|
||||
}
|
||||
|
||||
var _ credential.KeytabV8 = &keytabCredentials{}
|
||||
|
||||
func (ktc *keytabCredentials) DomainName() string {
|
||||
return strings.ToUpper(ktc.domain)
|
||||
}
|
||||
|
||||
func (ktc *keytabCredentials) Workstation() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ktc *keytabCredentials) UserName() string {
|
||||
return ktc.username
|
||||
}
|
||||
|
||||
func (ktc *keytabCredentials) Keytab() *keytab.Keytab {
|
||||
return ktc.keytab
|
||||
return msrpcSMB2.NewDialer(dialerOptions...), nil
|
||||
default:
|
||||
options.debug("Using NTLM")
|
||||
|
||||
secOptions := []gssapi.ContextOption{
|
||||
gssapi.WithCredential(smbCreds),
|
||||
gssapi.WithMechanismFactory(ssp.NTLM),
|
||||
}
|
||||
|
||||
spn, err := target.SPN(ctx)
|
||||
if err == nil {
|
||||
secOptions = append(secOptions, gssapi.WithTargetName(spn))
|
||||
}
|
||||
|
||||
dialerOptions = append(dialerOptions, msrpcSMB2.WithSecurity(secOptions...))
|
||||
|
||||
return msrpcSMB2.NewDialer(dialerOptions...), nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user