Skip to content

Commit 2b9ce48

Browse files
committed
Saved current version of SPNEGO, wip not functionnal for now
1 parent 6748158 commit 2b9ce48

File tree

8 files changed

+1578
-0
lines changed

8 files changed

+1578
-0
lines changed

network/smb/smb_v10/spnego/auth.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package spnego
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/TheManticoreProject/Manticore/network/smb/smb_v10/spnego/ntlm"
8+
"github.com/TheManticoreProject/Manticore/utils/encoding/utf16"
9+
)
10+
11+
// AuthType represents the authentication type
12+
type AuthType int
13+
14+
const (
15+
AuthTypeNTLM AuthType = iota
16+
AuthTypeKerberos
17+
)
18+
19+
// AuthContext holds the state for an authentication session
20+
type AuthContext struct {
21+
Type AuthType
22+
Domain string
23+
Username string
24+
Password string
25+
Workstation string
26+
UseUnicode bool
27+
28+
// NTLM specific fields
29+
NTLMChallenge *ntlm.ChallengeMessage
30+
}
31+
32+
// NewAuthContext creates a new authentication context
33+
func NewAuthContext(authType AuthType, domain, username, password, workstation string, useUnicode bool) *AuthContext {
34+
return &AuthContext{
35+
Type: authType,
36+
Domain: domain,
37+
Username: username,
38+
Password: password,
39+
Workstation: workstation,
40+
UseUnicode: useUnicode,
41+
}
42+
}
43+
44+
// ProcessChallengeToken processes the server's challenge token and prepares the authenticate token
45+
func (ctx *AuthContext) ProcessChallengeToken(token []byte) ([]byte, error) {
46+
// Parse the SPNEGO token
47+
resp, err := ParseNegTokenResp(token)
48+
if err != nil {
49+
return nil, fmt.Errorf("failed to parse SPNEGO token: %v", err)
50+
}
51+
52+
// Check if the server accepted our mechanism
53+
if resp.NegState == Reject {
54+
return nil, errors.New("server rejected authentication")
55+
}
56+
57+
// Extract the inner token
58+
innerToken, err := ExtractNTLMToken(token)
59+
if err != nil {
60+
return nil, fmt.Errorf("failed to extract inner token: %v", err)
61+
}
62+
63+
switch ctx.Type {
64+
case AuthTypeNTLM:
65+
// Parse the NTLM CHALLENGE message
66+
challenge, err := ntlm.ParseChallengeMessage(innerToken)
67+
if err != nil {
68+
return nil, fmt.Errorf("failed to parse NTLM CHALLENGE message: %v", err)
69+
}
70+
71+
// Store the challenge for later use
72+
ctx.NTLMChallenge = challenge
73+
74+
// Create NTLM AUTHENTICATE message
75+
ntlmAuth, err := ntlm.CreateAuthenticateMessage(challenge, ctx.Username, ctx.Password, ctx.Domain, ctx.Workstation)
76+
if err != nil {
77+
return nil, fmt.Errorf("failed to create NTLM AUTHENTICATE message: %v", err)
78+
}
79+
80+
// Wrap in SPNEGO
81+
return CreateNegTokenInit(ntlmAuth)
82+
83+
case AuthTypeKerberos:
84+
return nil, errors.New("kerberos authentication is not yet implemented")
85+
86+
default:
87+
return nil, fmt.Errorf("unsupported authentication type: %v", ctx.Type)
88+
}
89+
}
90+
91+
// PrepareSessionSetupRequest prepares the SMB session setup request with SPNEGO token
92+
func PrepareSessionSetupRequest(token []byte, useUnicode bool) []byte {
93+
if useUnicode {
94+
return utf16.EncodeUTF16LE(string(token))
95+
} else {
96+
return token
97+
}
98+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package spnego
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/TheManticoreProject/Manticore/network/smb/smb_v10/spnego/ntlm"
8+
)
9+
10+
// CreateNegotiateToken creates the initial SPNEGO token with NTLM negotiate message
11+
// Parameters:
12+
// - ctx: The authentication context containing domain, username, password, and other settings
13+
//
14+
// Returns:
15+
// - []byte: The SPNEGO token containing the NTLM negotiate message
16+
// - error: An error if token creation fails
17+
func (ctx *AuthContext) CreateNegotiateToken() ([]byte, error) {
18+
switch ctx.Type {
19+
case AuthTypeNTLM:
20+
// Create NTLM NEGOTIATE message
21+
ntlmNegotiate, err := ntlm.CreateNegotiateMessage(ctx.Domain, ctx.Workstation, ctx.UseUnicode)
22+
if err != nil {
23+
return nil, fmt.Errorf("failed to create NTLM NEGOTIATE message: %v", err)
24+
}
25+
26+
// Wrap in SPNEGO
27+
return CreateNegTokenInit(ntlmNegotiate)
28+
29+
case AuthTypeKerberos:
30+
return nil, errors.New("kerberos authentication is not yet implemented")
31+
32+
default:
33+
return nil, fmt.Errorf("unsupported authentication type: %v", ctx.Type)
34+
}
35+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package ntlm
2+
3+
// NTLM Negotiate Flags
4+
// During NTLM authentication, each of the following flags is a possible value of
5+
// the NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, and
6+
// AUTHENTICATE_MESSAGE, unless otherwise noted. These flags define client or server
7+
// NTLM capabilities supported by the sender.
8+
// Source: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832
9+
const (
10+
// A (1 bit): If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
11+
// The A and B bits are evaluated together as follows:
12+
// A==1: The choice of character set encoding MUST be Unicode.
13+
// A==0 and B==1: The choice of character set encoding MUST be OEM.
14+
// A==0 and B==0: The protocol MUST return SEC_E_INVALID_TOKEN.
15+
NTLMSSP_NEGOTIATE_UNICODE uint32 = 0x00000001
16+
17+
// B (1 bit): If set, requests OEM character set encoding. An alternate name for this field is NTLM_NEGOTIATE_OEM. See bit A for details.
18+
NTLMSSP_NEGOTIATE_OEM uint32 = 0x00000002
19+
20+
// C (1 bit): If set, a TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be supplied. An alternate name for this field is NTLMSSP_REQUEST_TARGET.
21+
NTLMSSP_REQUEST_TARGET uint32 = 0x00000004
22+
23+
// r10 (1 bit): This bit is unused and MUST be zero.
24+
NTLMSSP_REQUEST_R10 uint32 = 0x00000008
25+
26+
// D (1 bit): If set, requests session key negotiation for message signatures. If the client sends NTLMSSP_NEGOTIATE_SIGN to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE. An alternate name for this field is NTLMSSP_NEGOTIATE_SIGN.
27+
NTLMSSP_NEGOTIATE_SIGN uint32 = 0x00000010
28+
29+
// E (1 bit): If set, requests session key negotiation for message confidentiality. If the client sends NTLMSSP_NEGOTIATE_SEAL to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the CHALLENGE_MESSAGE. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_SEAL.
30+
NTLMSSP_NEGOTIATE_SEAL uint32 = 0x00000020
31+
32+
// F (1 bit): If set, requests connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then NTLMSSP_NEGOTIATE_KEY_EXCH MUST always be set in the AUTHENTICATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is NTLMSSP_NEGOTIATE_DATAGRAM.
33+
NTLMSSP_NEGOTIATE_DATAGRAM uint32 = 0x00000040
34+
35+
// G (1 bit): If set, requests LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_LM_KEY and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be used, and extended session security signing and sealing requires support from the client and the server to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_LM_KEY.
36+
NTLMSSP_NEGOTIATE_LM_KEY uint32 = 0x00000080
37+
38+
// r9 (1 bit): This bit is unused and MUST be zero.
39+
NTLMSSP_REQUEST_R9 uint32 = 0x00000100
40+
41+
// H (1 bit): If set, requests usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST be set in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is NTLMSSP_NEGOTIATE_NTLM.
42+
NTLMSSP_NEGOTIATE_NTLM uint32 = 0x00000200
43+
44+
// r8 (1 bit): This bit is unused and SHOULD be zero.
45+
NTLMSSP_REQUEST_R8 uint32 = 0x00000400
46+
47+
// J (1 bit): If set, the connection SHOULD be anonymous.
48+
NTLMSSP_NEGOTIATE_ANONYMOUS uint32 = 0x00000800
49+
50+
// K (1 bit): If set, the domain name is provided (section 2.2.1.1). An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED.
51+
NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED uint32 = 0x00001000
52+
53+
// L (1 bit): This flag indicates whether the Workstation field is present. If this flag is not set, the Workstation field MUST be ignored. If this flag is set, the length of the Workstation field specifies whether the workstation name is nonempty or not. An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED.
54+
NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED uint32 = 0x00002000
55+
56+
// r7 (1 bit): This bit is unused and MUST be zero.
57+
NTLMSSP_REQUEST_R7 uint32 = 0x00004000
58+
59+
// M (1 bit): If set, a session key is generated regardless of the states of NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL. A session key MUST always exist to generate the MIC (section 3.1.5.1.2) in the authenticate message. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden by NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_ALWAYS_SIGN.
60+
NTLMSSP_NEGOTIATE_ALWAYS_SIGN uint32 = 0x00008000
61+
62+
// N (1 bit): If set, TargetName MUST be a domain name. The data corresponding to this flag is provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is NTLMSSP_TARGET_TYPE_DOMAIN.
63+
NTLMSSP_TARGET_TYPE_DOMAIN uint32 = 0x00010000
64+
65+
// O (1 bit): If set, TargetName MUST be a server name. The data corresponding to this flag is provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set. This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is NTLMSSP_TARGET_TYPE_SERVER.
66+
NTLMSSP_TARGET_TYPE_SERVER uint32 = 0x00020000
67+
68+
// r6 (1 bit): This bit is unused and MUST be zero.
69+
NTLMSSP_REQUEST_R6 uint32 = 0x00040000
70+
71+
// P (1 bit): If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a misnomer because it is not NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and NTLMSSP_NEGOTIATE_LM_KEY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be used, and extended session security signing and sealing requires support from the client and the server in order to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.
72+
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY uint32 = 0x00080000
73+
74+
// Q (1 bit): If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY.
75+
NTLMSSP_NEGOTIATE_IDENTIFY uint32 = 0x00100000
76+
77+
// r5 (1 bit): This bit is unused and MUST be zero.
78+
NTLMSSP_REQUEST_R5 uint32 = 0x00200000
79+
80+
// R (1 bit): If set, requests the usage of the LMOWF. An alternate name for this field is NTLMSSP_REQUEST_NON_NT_SESSION_KEY.
81+
NTLMSSP_REQUEST_NON_NT_SESSION_KEY uint32 = 0x00400000
82+
83+
// S (1 bit): If set, indicates that the TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated. An alternate name for this field is NTLMSSP_NEGOTIATE_TARGET_INFO.
84+
NTLMSSP_NEGOTIATE_TARGET_INFO uint32 = 0x00800000
85+
86+
// r4 (1 bit): This bit is unused and MUST be zero.
87+
NTLMSSP_REQUEST_R4 uint32 = 0x01000000
88+
89+
// T (1 bit): If set, requests the protocol version number. The data corresponding to this flag is provided in the Version field of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the AUTHENTICATE_MESSAGE. An alternate name for this field is NTLMSSP_NEGOTIATE_VERSION.
90+
NTLMSSP_NEGOTIATE_VERSION uint32 = 0x02000000
91+
92+
// r1 (1 bit): This bit is unused and MUST be zero.
93+
NTLMSSP_REQUEST_R1 uint32 = 0x04000000
94+
95+
// r2 (1 bit): This bit is unused and MUST be zero.
96+
NTLMSSP_REQUEST_R2 uint32 = 0x08000000
97+
98+
// r3 (1 bit): This bit is unused and MUST be zero.
99+
NTLMSSP_REQUEST_R3 uint32 = 0x10000000
100+
101+
// U (1 bit): If set, requests 128-bit session key negotiation. An alternate name for this field is NTLMSSP_NEGOTIATE_128. If the client sends NTLMSSP_NEGOTIATE_128 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the client sets NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if it is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_128.
102+
NTLMSSP_NEGOTIATE_128 uint32 = 0x20000000
103+
104+
// V (1 bit): If set, requests an explicit key exchange. This capability SHOULD be used because it improves security for message integrity or confidentiality. See sections 3.2.5.1.2, 3.2.5.2.1, and 3.2.5.2.2 for details. An alternate name for this field is NTLMSSP_NEGOTIATE_KEY_EXCH.
105+
NTLMSSP_NEGOTIATE_KEY_EXCH uint32 = 0x40000000
106+
107+
// W (1 bit): If set, requests 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN with NTLMSSP_NEGOTIATE_56 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to the client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_56.
108+
NTLMSSP_NEGOTIATE_56 uint32 = 0x80000000
109+
)

0 commit comments

Comments
 (0)