1From 202d69267c8550b850438877fb51c3d2c992949d Mon Sep 17 00:00:00 2001
2From: Stefan Metzmacher <metze@samba.org>
3Date: Tue, 1 Dec 2015 08:46:45 +0100
4Subject: [PATCH 01/10] CVE-2016-2110: s3:ntlmssp: set and use
5 ntlmssp_state->allow_lm_key
6MIME-Version: 1.0
7Content-Type: text/plain; charset=UTF-8
8Content-Transfer-Encoding: 8bit
9
10BUG: https://bugzilla.samba.org/show_bug.cgi?id=11644
11
12Signed-off-by: Stefan Metzmacher <metze@samba.org>
13Reviewed-by: G��nther Deschner <gd@samba.org>
14---
15 source3/libsmb/ntlmssp.c | 4 +++-
16 1 file changed, 3 insertions(+), 1 deletion(-)
17
18--- a/source3/libsmb/ntlmssp.c
19+++ b/source3/libsmb/ntlmssp.c
20@@ -176,17 +176,19 @@ void ntlmssp_want_feature_list(struct nt
21 	 * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
22 	 */
23 	if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) {
24-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
25+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
26 	}
27 	if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) {
28-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
29+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
30 	}
31 	if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) {
32-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
33+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
34 	}
35 	if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
36 		ntlmssp_state->use_ccache = true;
37 	}
38+
39+	ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
40 }
41 
42 /**
43@@ -199,17 +201,20 @@ void ntlmssp_want_feature(struct ntlmssp
44 {
45 	/* As per JRA's comment above */
46 	if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
47-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
48+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
49 	}
50 	if (feature & NTLMSSP_FEATURE_SIGN) {
51-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
52+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
53 	}
54 	if (feature & NTLMSSP_FEATURE_SEAL) {
55-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
56+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
57+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
58 	}
59 	if (feature & NTLMSSP_FEATURE_CCACHE) {
60 		ntlmssp_state->use_ccache = true;
61 	}
62+
63+	ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
64 }
65 
66 /**
67@@ -387,7 +392,12 @@ static NTSTATUS ntlmssp_client_initial(s
68 	}
69 
70 	if (ntlmssp_state->use_ntlmv2) {
71-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
72+		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_NTLM2;
73+		ntlmssp_state->allow_lm_key = false;
74+	}
75+
76+	if (ntlmssp_state->allow_lm_key) {
77+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
78 	}
79 
80 	/* generate the ntlmssp negotiate packet */
81@@ -422,6 +432,86 @@ static NTSTATUS ntlmssp_client_initial(s
82 	return NT_STATUS_MORE_PROCESSING_REQUIRED;
83 }
84 
85+static NTSTATUS ntlmssp3_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
86+					  uint32_t flags)
87+{
88+	uint32_t missing_flags = ntlmssp_state->required_flags;
89+
90+	if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
91+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
92+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
93+		ntlmssp_state->unicode = true;
94+	} else {
95+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
96+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
97+		ntlmssp_state->unicode = false;
98+	}
99+
100+	/*
101+	 * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
102+	 * has priority over NTLMSSP_NEGOTIATE_LM_KEY
103+	 */
104+	if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) {
105+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
106+	}
107+
108+	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
109+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
110+	}
111+
112+	if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) {
113+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
114+	}
115+
116+	if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
117+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
118+	}
119+
120+	if (!(flags & NTLMSSP_NEGOTIATE_128)) {
121+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
122+	}
123+
124+	if (!(flags & NTLMSSP_NEGOTIATE_56)) {
125+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
126+	}
127+
128+	if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
129+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
130+	}
131+
132+	if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) {
133+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
134+	}
135+
136+	if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) {
137+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
138+	}
139+
140+	if ((flags & NTLMSSP_REQUEST_TARGET)) {
141+		ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
142+	}
143+
144+	missing_flags &= ~ntlmssp_state->neg_flags;
145+	if (missing_flags != 0) {
146+		NTSTATUS status = NT_STATUS_RPC_SEC_PKG_ERROR;
147+		DEBUG(1, ("%s: Got challenge flags[0x%08x] "
148+			  "- possible downgrade detected! "
149+			  "missing_flags[0x%08x] - %s\n",
150+			  __func__,
151+			  (unsigned)flags,
152+			  (unsigned)missing_flags,
153+			  nt_errstr(status)));
154+		debug_ntlmssp_flags(missing_flags);
155+		DEBUGADD(4, ("neg_flags[0x%08x]\n",
156+			     (unsigned)ntlmssp_state->neg_flags));
157+		debug_ntlmssp_flags(ntlmssp_state->neg_flags);
158+
159+		return status;
160+	}
161+
162+	return NT_STATUS_OK;
163+}
164+
165 /**
166  * Next state function for the Challenge Packet.  Generate an auth packet.
167  *
168@@ -448,6 +538,26 @@ static NTSTATUS ntlmssp_client_challenge
169 	DATA_BLOB encrypted_session_key = data_blob_null;
170 	NTSTATUS nt_status = NT_STATUS_OK;
171 
172+	if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
173+			 "NTLMSSP",
174+			 &ntlmssp_command,
175+			 &server_domain_blob,
176+			 &chal_flags)) {
177+		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
178+		dump_data(2, reply.data, reply.length);
179+
180+		return NT_STATUS_INVALID_PARAMETER;
181+	}
182+	data_blob_free(&server_domain_blob);
183+
184+	DEBUG(3, ("Got challenge flags:\n"));
185+	debug_ntlmssp_flags(chal_flags);
186+
187+	nt_status = ntlmssp3_handle_neg_flags(ntlmssp_state, chal_flags);
188+	if (!NT_STATUS_IS_OK(nt_status)) {
189+		return nt_status;
190+	}
191+
192 	if (ntlmssp_state->use_ccache) {
193 		struct wbcCredentialCacheParams params;
194 		struct wbcCredentialCacheInfo *info = NULL;
195@@ -498,17 +608,6 @@ static NTSTATUS ntlmssp_client_challenge
196 
197 noccache:
198 
199-	if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
200-			 "NTLMSSP",
201-			 &ntlmssp_command,
202-			 &server_domain_blob,
203-			 &chal_flags)) {
204-		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
205-		dump_data(2, reply.data, reply.length);
206-
207-		return NT_STATUS_INVALID_PARAMETER;
208-	}
209-
210 	if (DEBUGLEVEL >= 10) {
211 		struct CHALLENGE_MESSAGE *challenge = talloc(
212 			talloc_tos(), struct CHALLENGE_MESSAGE);
213@@ -525,13 +624,6 @@ noccache:
214 		}
215 	}
216 
217-	data_blob_free(&server_domain_blob);
218-
219-	DEBUG(3, ("Got challenge flags:\n"));
220-	debug_ntlmssp_flags(chal_flags);
221-
222-	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
223-
224 	if (ntlmssp_state->unicode) {
225 		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
226 			chal_parse_string = "CdUdbddB";
227@@ -769,6 +861,7 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
228 	ntlmssp_state->unicode = True;
229 
230 	ntlmssp_state->use_ntlmv2 = use_ntlmv2;
231+	ntlmssp_state->allow_lm_key = lp_client_lanman_auth();
232 
233 	ntlmssp_state->expected_state = NTLMSSP_INITIAL;
234 
235@@ -780,6 +873,10 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
236 		NTLMSSP_NEGOTIATE_KEY_EXCH |
237 		NTLMSSP_REQUEST_TARGET;
238 
239+	if (ntlmssp_state->use_ntlmv2) {
240+		ntlmssp_state->allow_lm_key = false;
241+	}
242+
243 	ntlmssp_state->client.netbios_name = talloc_strdup(ntlmssp_state, netbios_name);
244 	if (!ntlmssp_state->client.netbios_name) {
245 		talloc_free(ntlmssp_state);
246--- a/libcli/auth/ntlmssp.h
247+++ b/libcli/auth/ntlmssp.h
248@@ -83,6 +83,7 @@ struct ntlmssp_state
249 	DATA_BLOB nt_resp;
250 	DATA_BLOB session_key;
251 
252+	uint32_t required_flags;
253 	uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
254 
255 	/**
256