From 46c9fb1e9538f3f9f7f03e0d6705e948321b5080 Mon Sep 17 00:00:00 2001 From: Gorkem Meydan Date: Wed, 16 Aug 2023 14:52:27 +0300 Subject: [PATCH] add workstation to the user info --- .gitignore | 1 + go.mod | 2 +- go.sum | 0 ntlm/crypto.go | 2 +- ntlm/keys.go | 2 +- ntlm/negotiate_flags.go | 2 +- ntlm/ntlm.go | 15 ++++++++------- ntlm/ntlmv1.go | 14 +++++++++----- ntlm/ntlmv1_test.go | 14 +++++++------- ntlm/ntlmv2.go | 28 ++++++++++++++++++---------- ntlm/ntlmv2_test.go | 8 ++++---- ntlm/signature.go | 18 +++++++++++++----- 12 files changed, 64 insertions(+), 42 deletions(-) delete mode 100644 go.sum diff --git a/.gitignore b/.gitignore index 5fff1d9..6744e24 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ pkg +.idea \ No newline at end of file diff --git a/go.mod b/go.mod index 1ba1d4e..f49ac8d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/vadimi/go-ntlm +module github.com/sematext/go-ntlm go 1.13 diff --git a/go.sum b/go.sum deleted file mode 100644 index e69de29..0000000 diff --git a/ntlm/crypto.go b/ntlm/crypto.go index 21b9e72..ef137ed 100644 --- a/ntlm/crypto.go +++ b/ntlm/crypto.go @@ -10,7 +10,7 @@ import ( rc4P "crypto/rc4" crc32P "hash/crc32" - md4P "github.com/vadimi/go-ntlm/ntlm/md4" + md4P "github.com/sematext/go-ntlm/ntlm/md4" ) func md4(data []byte) []byte { diff --git a/ntlm/keys.go b/ntlm/keys.go index b6b83d9..c44a12f 100644 --- a/ntlm/keys.go +++ b/ntlm/keys.go @@ -41,7 +41,7 @@ func signKey(flags uint32, randomSessionKey []byte, mode string) (signKey []byte return } -// Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as +// Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as func sealKey(flags uint32, randomSessionKey []byte, mode string) (sealKey []byte) { if NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.IsSet(flags) { if NTLMSSP_NEGOTIATE_128.IsSet(flags) { diff --git a/ntlm/negotiate_flags.go b/ntlm/negotiate_flags.go index a3c7b9f..2788035 100644 --- a/ntlm/negotiate_flags.go +++ b/ntlm/negotiate_flags.go @@ -4,7 +4,7 @@ package ntlm // During NTLM authentication, each of the following flags is a possible value of the NegotiateFlags field of the NEGOTIATE_MESSAGE, // CHALLENGE_MESSAGE, and AUTHENTICATE_MESSAGE, unless otherwise noted. These flags define client or server NTLM capabilities -// ssupported by the sender. +// supported by the sender. import ( "bytes" diff --git a/ntlm/ntlm.go b/ntlm/ntlm.go index 03d9da3..6dd001e 100644 --- a/ntlm/ntlm.go +++ b/ntlm/ntlm.go @@ -1,6 +1,6 @@ //Copyright 2013 Thomson Reuters Global Resources. BSD License please see License file for more information -// Package NTLM implements the interfaces used for interacting with NTLMv1 and NTLMv2. +// Package ntlm implements the interfaces used for interacting with NTLMv1 and NTLMv2. // To create NTLM v1 or v2 sessions you would use CreateClientSession and create ClientServerSession. package ntlm @@ -40,7 +40,7 @@ func CreateClientSession(version Version, mode Mode) (n ClientSession, err error } type ClientSession interface { - SetUserInfo(username string, password string, domain string) + SetUserInfo(username string, password string, domain string, workstation string) SetMode(mode Mode) GenerateNegotiateMessage() (*NegotiateMessage, error) @@ -71,8 +71,8 @@ func CreateServerSession(version Version, mode Mode) (n ServerSession, err error } type ServerSession interface { - SetUserInfo(username string, password string, domain string) - GetUserInfo() (string, string, string) + SetUserInfo(username string, password string, domain string, workstation string) + GetUserInfo() (string, string, string, string) SetMode(mode Mode) SetServerChallenge(challenge []byte) @@ -94,9 +94,10 @@ type ServerSession interface { type SessionData struct { mode Mode - user string - password string - userDomain string + user string + password string + userDomain string + workstation string NegotiateFlags uint32 diff --git a/ntlm/ntlmv1.go b/ntlm/ntlmv1.go index cbbe52d..f8dcf79 100644 --- a/ntlm/ntlmv1.go +++ b/ntlm/ntlmv1.go @@ -14,18 +14,22 @@ import ( Shared Session Data and Methods *******************************/ +// V1Session is the shared data and methods for NTLMv1 type V1Session struct { SessionData } -func (n *V1Session) SetUserInfo(username string, password string, domain string) { +// SetUserInfo sets the username, password, domain, and workstation for the session +func (n *V1Session) SetUserInfo(username string, password string, domain string, workstation string) { n.user = username n.password = password n.userDomain = domain + n.workstation = workstation } -func (n *V1Session) GetUserInfo() (string, string, string) { - return n.user, n.password, n.userDomain +// GetUserInfo returns the username, password, domain and workstation for the session +func (n *V1Session) GetUserInfo() (string, string, string, string) { + return n.user, n.password, n.userDomain, n.workstation } func (n *V1Session) SetMode(mode Mode) { @@ -331,7 +335,7 @@ func (n *V1ClientSession) GenerateAuthenticateMessage() (am *AuthenticateMessage am.NtChallengeResponseFields, _ = CreateBytePayload(n.ntChallengeResponse) am.DomainName, _ = CreateStringPayload(n.userDomain) am.UserName, _ = CreateStringPayload(n.user) - am.Workstation, _ = CreateStringPayload("SQUAREMILL") + am.Workstation, _ = CreateStringPayload(n.workstation) am.EncryptedRandomSessionKey, _ = CreateBytePayload(n.encryptedRandomSessionKey) am.NegotiateFlags = n.NegotiateFlags am.Version = &VersionStruct{ProductMajorVersion: uint8(6), ProductMinorVersion: uint8(1), ProductBuild: uint16(7601), NTLMRevisionCurrent: uint8(15)} @@ -359,7 +363,7 @@ func ntowfv1(passwd string) []byte { return md4(utf16FromString(passwd)) } -// ConcatenationOf( DES( UpperCase( Passwd)[0..6],"KGS!@#$%"), DES( UpperCase( Passwd)[7..13],"KGS!@#$%")) +// ConcatenationOf( DES( UpperCase( Passwd)[0..6],"KGS!@#$%"), DES( UpperCase( Passwd)[7..13],"KGS!@#$%")) func lmowfv1(passwd string) ([]byte, error) { asciiPassword := []byte(strings.ToUpper(passwd)) keyBytes := zeroPaddedBytes(asciiPassword, 0, 14) diff --git a/ntlm/ntlmv1_test.go b/ntlm/ntlmv1_test.go index c56960f..1cc9f1c 100644 --- a/ntlm/ntlmv1_test.go +++ b/ntlm/ntlmv1_test.go @@ -58,7 +58,7 @@ func TestNtlmV1ExtendedSessionSecurity(t *testing.T) { if err != nil { t.Errorf("Could not create NTLMv1 session") } - context.SetUserInfo("100001.wcp.thomsonreuters.com", "notmypass", "") + context.SetUserInfo("100001.wcp.thomsonreuters.com", "notmypass", "", "") context.SetServerChallenge(c.ServerChallenge) err = context.ProcessAuthenticateMessage(msg) if err == nil { @@ -81,7 +81,7 @@ func TestNtlmV1(t *testing.T) { flags = NTLMSSP_NEGOTIATE_UNICODE.Set(flags) n := new(V1ClientSession) - n.SetUserInfo("User", "Password", "Domain") + n.SetUserInfo("User", "Password", "Domain", "") n.NegotiateFlags = flags n.responseKeyNT, _ = hex.DecodeString("a4f49c406510bdcab6824ee7c30fd852") n.responseKeyLM, _ = hex.DecodeString("e52cac67419a9a224a3b108f3fa6cb6d") @@ -146,14 +146,14 @@ func TestNtlmV1(t *testing.T) { } client := new(V1ClientSession) - client.SetUserInfo("User", "Password", "Domain") + client.SetUserInfo("User", "Password", "Domain", "") err = client.ProcessChallengeMessage(challengeMessage) if err != nil { t.Errorf("Could not process challenge message: %s", err) } server := new(V1ServerSession) - server.SetUserInfo("User", "Password", "Domain") + server.SetUserInfo("User", "Password", "Domain", "") authenticateMessageBytes, err := hex.DecodeString("4e544c4d5353500003000000180018006c00000018001800840000000c000c00480000000800080054000000100010005c000000100010009c000000358280e20501280a0000000f44006f006d00610069006e00550073006500720043004f004d005000550054004500520098def7b87f88aa5dafe2df779688a172def11c7d5ccdef1367c43011f30298a2ad35ece64f16331c44bdbed927841f94518822b1b3f350c8958682ecbb3e3cb7") authenticateMessage, err := ParseAuthenticateMessage(authenticateMessageBytes, 1) if err == nil { @@ -163,7 +163,7 @@ func TestNtlmV1(t *testing.T) { } server = new(V1ServerSession) - server.SetUserInfo("User", "Password", "Domain") + server.SetUserInfo("User", "Password", "Domain", "") server.serverChallenge = challengeMessage.ServerChallenge err = server.ProcessAuthenticateMessage(authenticateMessage) @@ -212,14 +212,14 @@ func TestNTLMv1WithClientChallenge(t *testing.T) { } client := new(V1ClientSession) - client.SetUserInfo("User", "Password", "Domain") + client.SetUserInfo("User", "Password", "Domain", "") err = client.ProcessChallengeMessage(challengeMessage) if err != nil { t.Errorf("Could not process challenge message: %s", err) } server := new(V1ServerSession) - server.SetUserInfo("User", "Password", "Domain") + server.SetUserInfo("User", "Password", "Domain", "") server.serverChallenge = challengeMessage.ServerChallenge authenticateMessageBytes, _ := hex.DecodeString("4e544c4d5353500003000000180018006c00000018001800840000000c000c00480000000800080054000000100010005c000000000000009c000000358208820501280a0000000f44006f006d00610069006e00550073006500720043004f004d0050005500540045005200aaaaaaaaaaaaaaaa000000000000000000000000000000007537f803ae367128ca458204bde7caf81e97ed2683267232") diff --git a/ntlm/ntlmv2.go b/ntlm/ntlmv2.go index 141a115..dfa5f02 100644 --- a/ntlm/ntlmv2.go +++ b/ntlm/ntlmv2.go @@ -16,24 +16,30 @@ import ( Shared Session Data and Methods *******************************/ +// V2Session is the shared session data and methods for NTLMv2 type V2Session struct { SessionData } -func (n *V2Session) SetUserInfo(username string, password string, domain string) { +// SetUserInfo sets the username, password, and domain for the session +func (n *V2Session) SetUserInfo(username string, password string, domain string, workstation string) { n.user = username n.password = password n.userDomain = domain + n.workstation = workstation } -func (n *V2Session) GetUserInfo() (string, string, string) { - return n.user, n.password, n.userDomain +// GetUserInfo returns the username, password, and domain for the session +func (n *V2Session) GetUserInfo() (string, string, string, string) { + return n.user, n.password, n.userDomain, n.workstation } +// SetMode sets the mode for the session func (n *V2Session) SetMode(mode Mode) { n.mode = mode } +// Version returns the NTLM version of the session func (n *V2Session) Version() int { return 2 } @@ -46,6 +52,7 @@ func (n *V2Session) fetchResponseKeys() (err error) { return } +// GetSessionData returns the session data for the session func (n *V2ServerSession) GetSessionData() *SessionData { return &n.SessionData } @@ -175,11 +182,11 @@ func (n *V2ServerSession) GenerateChallengeMessage() (cm *ChallengeMessage, err // Create the AvPairs we need pairs := new(AvPairs) - pairs.AddAvPair(MsvAvNbDomainName, utf16FromString("REUTERS")) - pairs.AddAvPair(MsvAvNbComputerName, utf16FromString("UKBP-CBTRMFE06")) - pairs.AddAvPair(MsvAvDnsDomainName, utf16FromString("Reuters.net")) - pairs.AddAvPair(MsvAvDnsComputerName, utf16FromString("ukbp-cbtrmfe06.Reuters.net")) - pairs.AddAvPair(MsvAvDnsTreeName, utf16FromString("Reuters.net")) + pairs.AddAvPair(MsvAvNbDomainName, utf16FromString("SEMATEXT")) + pairs.AddAvPair(MsvAvNbComputerName, utf16FromString("SYNTHETICS-HTTP-AGENT")) + pairs.AddAvPair(MsvAvDnsDomainName, utf16FromString("sematext.com")) + pairs.AddAvPair(MsvAvDnsComputerName, utf16FromString("synthetics-http-agent.sematext.com")) + pairs.AddAvPair(MsvAvDnsTreeName, utf16FromString("Sematext.com")) pairs.AddAvPair(MsvAvEOL, make([]byte, 0)) cm.TargetInfo = pairs cm.TargetInfoPayloadStruct, _ = CreateBytePayload(pairs.Bytes()) @@ -197,7 +204,8 @@ func (n *V2ServerSession) ProcessAuthenticateMessage(am *AuthenticateMessage) (e // They should always be correct (I hope) n.user = am.UserName.String() n.userDomain = am.DomainName.String() - log.Printf("(ProcessAuthenticateMessage)NTLM v2 User %s Domain %s", n.user, n.userDomain) + n.workstation = am.Workstation.String() + log.Printf("(ProcessAuthenticateMessage)NTLM v2 User %s Domain %s Workstation %s", n.user, n.userDomain, n.workstation) err = n.fetchResponseKeys() if err != nil { @@ -351,7 +359,7 @@ func (n *V2ClientSession) GenerateAuthenticateMessage() (am *AuthenticateMessage am.NtChallengeResponseFields, _ = CreateBytePayload(n.ntChallengeResponse) am.DomainName, _ = CreateStringPayload(n.userDomain) am.UserName, _ = CreateStringPayload(n.user) - am.Workstation, _ = CreateStringPayload("SQUAREMILL") + am.Workstation, _ = CreateStringPayload(n.workstation) am.EncryptedRandomSessionKey, _ = CreateBytePayload(n.encryptedRandomSessionKey) am.NegotiateFlags = n.NegotiateFlags am.Mic = make([]byte, 16) diff --git a/ntlm/ntlmv2_test.go b/ntlm/ntlmv2_test.go index b36f906..1748e13 100644 --- a/ntlm/ntlmv2_test.go +++ b/ntlm/ntlmv2_test.go @@ -60,7 +60,7 @@ func TestNTLMv2(t *testing.T) { // Challenge message client := new(V2ClientSession) - client.SetUserInfo("User", "Password", "Domain") + client.SetUserInfo("User", "Password", "Domain", "") challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) @@ -76,7 +76,7 @@ func TestNTLMv2(t *testing.T) { } server := new(V2ServerSession) - server.SetUserInfo("User", "Password", "Domain") + server.SetUserInfo("User", "Password", "Domain", "") server.serverChallenge = challengeMessage.ServerChallenge // Authenticate message @@ -123,7 +123,7 @@ func TestNTLMv2(t *testing.T) { // Have the client process this server challenge message client = new(V2ClientSession) - client.SetUserInfo("User", "Password", "Domain") + client.SetUserInfo("User", "Password", "Domain", "") err = client.ProcessChallengeMessage(challenge) if err != nil { t.Errorf("Could not process server generated challenge message: %s", err) @@ -162,7 +162,7 @@ func TestNTLMv2WithDomain(t *testing.T) { authenticateMessage := "TlRMTVNTUAADAAAAGAAYALYAAADSANIAzgAAADQANABIAAAAIAAgAHwAAAAaABoAnAAAABAAEACgAQAAVYKQQgUCzg4AAAAPYQByAHIAYQB5ADEAMgAuAG0AcwBnAHQAcwB0AC4AcgBlAHUAdABlAHIAcwAuAGMAbwBtAHUAcwBlAHIAcwB0AHIAZQBzAHMAMQAwADAAMAAwADgATgBZAEMAVgBBADEAMgBTADIAQwBNAFMAQQBPYrLjU4h0YlWZeEoNvTJtBQMnnJuAeUwsP+vGmAHNRBpgZ+4ChQLqAQEAAAAAAACPFEIFjx7OAQUDJ5ybgHlMAAAAAAIADgBSAEUAVQBUAEUAUgBTAAEAHABVAEsAQgBQAC0AQwBCAFQAUgBNAEYARQAwADYABAAWAFIAZQB1AHQAZQByAHMALgBuAGUAdAADADQAdQBrAGIAcAAtAGMAYgB0AHIAbQBmAGUAMAA2AC4AUgBlAHUAdABlAHIAcwAuAG4AZQB0AAUAFgBSAGUAdQB0AGUAcgBzAC4AbgBlAHQAAAAAAAAAAAANuvnqD3K88ZpjkLleL0NW" server := new(V2ServerSession) - server.SetUserInfo("blahblah", "Welcome1", "blahblah") + server.SetUserInfo("blahblah", "Welcome1", "blahblah", "") authenticateData, _ := base64.StdEncoding.DecodeString(authenticateMessage) a, _ := ParseAuthenticateMessage(authenticateData, 2) diff --git a/ntlm/signature.go b/ntlm/signature.go index 9ae07cc..b650e9e 100644 --- a/ntlm/signature.go +++ b/ntlm/signature.go @@ -62,10 +62,14 @@ func mac(negFlags uint32, handle *rc4P.Cipher, signingKey []byte, seqNum uint32, // Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle, NTLMSSP_MESSAGE_SIGNATURE.Checksum) // Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to RC4(Handle, 0x00000000) // If (connection oriented) -// Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to NTLMSSP_MESSAGE_SIGNATURE.SeqNum XOR SeqNum -// Set SeqNum to SeqNum + 1 +// +// Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to NTLMSSP_MESSAGE_SIGNATURE.SeqNum XOR SeqNum +// Set SeqNum to SeqNum + 1 +// // Else -// Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to NTLMSSP_MESSAGE_SIGNATURE.SeqNum XOR (application supplied SeqNum) +// +// Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to NTLMSSP_MESSAGE_SIGNATURE.SeqNum XOR (application supplied SeqNum) +// // EndIf // Set NTLMSSP_MESSAGE_SIGNATURE.RandomPad to 0 // End @@ -91,9 +95,13 @@ func macWithoutExtendedSessionSecurity(handle *rc4P.Cipher, seqNum uint32, messa // Define MAC(Handle, SigningKey, SeqNum, Message) as // Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001 // if Key Exchange Key Negotiated -// Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle, HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]) +// +// Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle, HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]) +// // else -// Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7] +// +// Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7] +// // end // Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum // Set SeqNum to SeqNum + 1