/src/wireshark/epan/dissectors/packet-ntlmssp.c
Line | Count | Source |
1 | | /* packet-ntlmssp.c |
2 | | * Add-on for better NTLM v1/v2 handling |
3 | | * Copyright 2009, 2012 Matthieu Patou <mat@matws.net> |
4 | | * Routines for NTLM Secure Service Provider |
5 | | * Devin Heitmueller <dheitmueller@netilla.com> |
6 | | * Copyright 2003, Tim Potter <tpot@samba.org> |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | 0 | #define WS_LOG_DOMAIN "packet-ntlmssp" |
16 | | #include "config.h" |
17 | | #include <wireshark.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include <epan/packet.h> |
21 | | #include <epan/exceptions.h> |
22 | | #include <epan/asn1.h> |
23 | | #include <epan/prefs.h> |
24 | | #include <epan/tap.h> |
25 | | #include <epan/expert.h> |
26 | | #include <epan/show_exception.h> |
27 | | #include <epan/proto_data.h> |
28 | | #include <epan/tfs.h> |
29 | | #include <epan/read_keytab_file.h> |
30 | | |
31 | | #include <wsutil/array.h> |
32 | | #include <wsutil/wsgcrypt.h> |
33 | | #include <wsutil/crc32.h> |
34 | | #include <wsutil/str_util.h> |
35 | | |
36 | | #include "packet-windows-common.h" |
37 | | #include "packet-kerberos.h" |
38 | | #include "packet-dcerpc.h" |
39 | | #include "packet-gssapi.h" |
40 | | |
41 | | |
42 | | #include "packet-ntlmssp.h" |
43 | | |
44 | | /* |
45 | | * See |
46 | | * |
47 | | * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/ |
48 | | * |
49 | | * for Microsoft's MS-NLMP, NT LAN Manager (NTLM) Authentication Protocol |
50 | | * Specification. |
51 | | * |
52 | | * See also |
53 | | * |
54 | | * http://davenport.sourceforge.net/ntlm.html |
55 | | * |
56 | | * which indicates that, in practice, some fields specified by MS-NLMP |
57 | | * may be absent; this has been seen in some captures. |
58 | | */ |
59 | | |
60 | | void proto_register_ntlmssp(void); |
61 | | void proto_reg_handoff_ntlmssp(void); |
62 | | |
63 | | static int ntlmssp_tap; |
64 | | |
65 | 392 | #define CLIENT_SIGN_TEXT "session key to client-to-server signing key magic constant" |
66 | 392 | #define CLIENT_SEAL_TEXT "session key to client-to-server sealing key magic constant" |
67 | 392 | #define SERVER_SIGN_TEXT "session key to server-to-client signing key magic constant" |
68 | 392 | #define SERVER_SEAL_TEXT "session key to server-to-client sealing key magic constant" |
69 | | |
70 | | static const value_string ntlmssp_message_types[] = { |
71 | | { NTLMSSP_NEGOTIATE, "NTLMSSP_NEGOTIATE" }, |
72 | | { NTLMSSP_CHALLENGE, "NTLMSSP_CHALLENGE" }, |
73 | | { NTLMSSP_AUTH, "NTLMSSP_AUTH" }, |
74 | | { NTLMSSP_UNKNOWN, "NTLMSSP_UNKNOWN" }, |
75 | | { 0, NULL } |
76 | | }; |
77 | | |
78 | | #define NTLMSSP_EK_IS_NT4HASH(ek) \ |
79 | | (ek->fd_num == -1 && ek->keytype == 23 && ek->keylength == NTLMSSP_KEY_LEN) |
80 | | |
81 | | static const unsigned char gbl_zeros[24] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; |
82 | | static GHashTable* hash_packet; |
83 | | |
84 | | /* |
85 | | * NTLMSSP negotiation flags |
86 | | * Taken from Samba |
87 | | * |
88 | | * See also the davenport.sourceforge.net document cited above, |
89 | | * although that document says that: |
90 | | * |
91 | | * 0x00010000 is "Target Type Domain"; |
92 | | * 0x00020000 is "Target Type Server" |
93 | | * 0x00040000 is "Target Type Share"; |
94 | | * |
95 | | * and that 0x00100000, 0x00200000, and 0x00400000 are |
96 | | * "Request Init Response", "Request Accept Response", and |
97 | | * "Request Non-NT Session Key", rather than those values shifted |
98 | | * right one having those interpretations. |
99 | | * |
100 | | * UPDATE: Further information obtained from [MS-NLMP] 2.2.2.5, added in comments |
101 | | * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832 |
102 | | */ |
103 | 6.47k | #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 // A |
104 | 14 | #define NTLMSSP_NEGOTIATE_OEM 0x00000002 // B |
105 | 14 | #define NTLMSSP_REQUEST_TARGET 0x00000004 // C |
106 | 14 | #define NTLMSSP_UNUSED_00000008 0x00000008 // r10 |
107 | 14 | #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 // D |
108 | 14 | #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 // E |
109 | 14 | #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 // F |
110 | 1.13k | #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 // G, "requests LAN Manager (LM) session key computation", aka NTLMv1 |
111 | 14 | #define NTLMSSP_UNUSED_00000100 0x00000100 // r9 |
112 | 18 | #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 // H, "requests usage of the NTLM v1 session security protocol" |
113 | 14 | #define NTLMSSP_UNUSED_00000400 0x00000400 // r8 |
114 | 14 | #define NTLMSSP_NEGOTIATE_ANONYMOUS 0x00000800 // J |
115 | 14 | #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 // K |
116 | 14 | #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 // L |
117 | 14 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000 // r7 |
118 | 14 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 // M |
119 | 14 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 // N |
120 | 14 | #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 // O |
121 | 14 | #define NTLMSSP_UNUSED_00040000 0x00040000 // r6 |
122 | 2.45k | #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 // P, "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" |
123 | 14 | #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 // Q |
124 | 14 | #define NTLMSSP_UNUSED_00200000 0x00200000 // r5 |
125 | 90 | #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 // R, "requests the usage of the LMOWF" |
126 | 14 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 // S |
127 | 14 | #define NTLMSSP_UNUSED_01000000 0x01000000 // r4 |
128 | 2.02k | #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 // T |
129 | 14 | #define NTLMSSP_UNUSED_04000000 0x04000000 // r3 |
130 | 14 | #define NTLMSSP_UNUSED_08000000 0x08000000 // r2 |
131 | 14 | #define NTLMSSP_UNUSED_10000000 0x10000000 // r1 |
132 | 210 | #define NTLMSSP_NEGOTIATE_128 0x20000000 // U |
133 | 213 | #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 // V |
134 | 208 | #define NTLMSSP_NEGOTIATE_56 0x80000000 // W |
135 | | |
136 | | static int proto_ntlmssp; |
137 | | static int hf_ntlmssp_auth; |
138 | | static int hf_ntlmssp_message_type; |
139 | | static int hf_ntlmssp_negotiate_flags; |
140 | | static int hf_ntlmssp_negotiate_flags_01; |
141 | | static int hf_ntlmssp_negotiate_flags_02; |
142 | | static int hf_ntlmssp_negotiate_flags_04; |
143 | | static int hf_ntlmssp_negotiate_flags_08; |
144 | | static int hf_ntlmssp_negotiate_flags_10; |
145 | | static int hf_ntlmssp_negotiate_flags_20; |
146 | | static int hf_ntlmssp_negotiate_flags_40; |
147 | | static int hf_ntlmssp_negotiate_flags_80; |
148 | | static int hf_ntlmssp_negotiate_flags_100; |
149 | | static int hf_ntlmssp_negotiate_flags_200; |
150 | | static int hf_ntlmssp_negotiate_flags_400; |
151 | | static int hf_ntlmssp_negotiate_flags_800; |
152 | | static int hf_ntlmssp_negotiate_flags_1000; |
153 | | static int hf_ntlmssp_negotiate_flags_2000; |
154 | | static int hf_ntlmssp_negotiate_flags_4000; |
155 | | static int hf_ntlmssp_negotiate_flags_8000; |
156 | | static int hf_ntlmssp_negotiate_flags_10000; |
157 | | static int hf_ntlmssp_negotiate_flags_20000; |
158 | | static int hf_ntlmssp_negotiate_flags_40000; |
159 | | static int hf_ntlmssp_negotiate_flags_80000; |
160 | | static int hf_ntlmssp_negotiate_flags_100000; |
161 | | static int hf_ntlmssp_negotiate_flags_200000; |
162 | | static int hf_ntlmssp_negotiate_flags_400000; |
163 | | static int hf_ntlmssp_negotiate_flags_800000; |
164 | | static int hf_ntlmssp_negotiate_flags_1000000; |
165 | | static int hf_ntlmssp_negotiate_flags_2000000; |
166 | | static int hf_ntlmssp_negotiate_flags_4000000; |
167 | | static int hf_ntlmssp_negotiate_flags_8000000; |
168 | | static int hf_ntlmssp_negotiate_flags_10000000; |
169 | | static int hf_ntlmssp_negotiate_flags_20000000; |
170 | | static int hf_ntlmssp_negotiate_flags_40000000; |
171 | | static int hf_ntlmssp_negotiate_flags_80000000; |
172 | | /* static int hf_ntlmssp_negotiate_workstation_strlen; */ |
173 | | /* static int hf_ntlmssp_negotiate_workstation_maxlen; */ |
174 | | /* static int hf_ntlmssp_negotiate_workstation_buffer; */ |
175 | | static int hf_ntlmssp_negotiate_workstation; |
176 | | /* static int hf_ntlmssp_negotiate_domain_strlen; */ |
177 | | /* static int hf_ntlmssp_negotiate_domain_maxlen; */ |
178 | | /* static int hf_ntlmssp_negotiate_domain_buffer; */ |
179 | | static int hf_ntlmssp_negotiate_domain; |
180 | | static int hf_ntlmssp_ntlm_server_challenge; |
181 | | static int hf_ntlmssp_ntlm_client_challenge; |
182 | | static int hf_ntlmssp_reserved; |
183 | | static int hf_ntlmssp_challenge_target_name; |
184 | | static int hf_ntlmssp_auth_username; |
185 | | static int hf_ntlmssp_auth_domain; |
186 | | static int hf_ntlmssp_auth_hostname; |
187 | | static int hf_ntlmssp_auth_lmresponse; |
188 | | static int hf_ntlmssp_auth_ntresponse; |
189 | | static int hf_ntlmssp_auth_sesskey; |
190 | | static int hf_ntlmssp_string_len; |
191 | | static int hf_ntlmssp_string_maxlen; |
192 | | static int hf_ntlmssp_string_offset; |
193 | | static int hf_ntlmssp_blob_len; |
194 | | static int hf_ntlmssp_blob_maxlen; |
195 | | static int hf_ntlmssp_blob_offset; |
196 | | static int hf_ntlmssp_version; |
197 | | static int hf_ntlmssp_version_major; |
198 | | static int hf_ntlmssp_version_minor; |
199 | | static int hf_ntlmssp_version_build_number; |
200 | | static int hf_ntlmssp_version_ntlm_current_revision; |
201 | | |
202 | | static int hf_ntlmssp_challenge_target_info; |
203 | | static int hf_ntlmssp_challenge_target_info_len; |
204 | | static int hf_ntlmssp_challenge_target_info_maxlen; |
205 | | static int hf_ntlmssp_challenge_target_info_offset; |
206 | | |
207 | | static int hf_ntlmssp_challenge_target_info_item_type; |
208 | | static int hf_ntlmssp_challenge_target_info_item_len; |
209 | | |
210 | | static int hf_ntlmssp_challenge_target_info_end; |
211 | | static int hf_ntlmssp_challenge_target_info_nb_computer_name; |
212 | | static int hf_ntlmssp_challenge_target_info_nb_domain_name; |
213 | | static int hf_ntlmssp_challenge_target_info_dns_computer_name; |
214 | | static int hf_ntlmssp_challenge_target_info_dns_domain_name; |
215 | | static int hf_ntlmssp_challenge_target_info_dns_tree_name; |
216 | | static int hf_ntlmssp_challenge_target_info_flags; |
217 | | static int hf_ntlmssp_challenge_target_info_timestamp; |
218 | | static int hf_ntlmssp_challenge_target_info_restrictions; |
219 | | static int hf_ntlmssp_challenge_target_info_target_name; |
220 | | static int hf_ntlmssp_challenge_target_info_channel_bindings; |
221 | | |
222 | | static int hf_ntlmssp_ntlmv2_response_item_type; |
223 | | static int hf_ntlmssp_ntlmv2_response_item_len; |
224 | | |
225 | | static int hf_ntlmssp_ntlmv2_response_end; |
226 | | static int hf_ntlmssp_ntlmv2_response_nb_computer_name; |
227 | | static int hf_ntlmssp_ntlmv2_response_nb_domain_name; |
228 | | static int hf_ntlmssp_ntlmv2_response_dns_computer_name; |
229 | | static int hf_ntlmssp_ntlmv2_response_dns_domain_name; |
230 | | static int hf_ntlmssp_ntlmv2_response_dns_tree_name; |
231 | | static int hf_ntlmssp_ntlmv2_response_flags; |
232 | | static int hf_ntlmssp_ntlmv2_response_timestamp; |
233 | | static int hf_ntlmssp_ntlmv2_response_restrictions; |
234 | | static int hf_ntlmssp_ntlmv2_response_target_name; |
235 | | static int hf_ntlmssp_ntlmv2_response_channel_bindings; |
236 | | |
237 | | static int hf_ntlmssp_message_integrity_code; |
238 | | static int hf_ntlmssp_verf; |
239 | | static int hf_ntlmssp_verf_vers; |
240 | | static int hf_ntlmssp_verf_body; |
241 | | static int hf_ntlmssp_verf_randompad; |
242 | | static int hf_ntlmssp_verf_hmacmd5; |
243 | | static int hf_ntlmssp_verf_crc32; |
244 | | static int hf_ntlmssp_verf_sequence; |
245 | | /* static int hf_ntlmssp_decrypted_payload; */ |
246 | | |
247 | | static int hf_ntlmssp_ntlmv2_response; |
248 | | static int hf_ntlmssp_ntlmv2_response_ntproofstr; |
249 | | static int hf_ntlmssp_ntlmv2_response_rversion; |
250 | | static int hf_ntlmssp_ntlmv2_response_hirversion; |
251 | | static int hf_ntlmssp_ntlmv2_response_z; |
252 | | static int hf_ntlmssp_ntlmv2_response_pad; |
253 | | static int hf_ntlmssp_ntlmv2_response_time; |
254 | | static int hf_ntlmssp_ntlmv2_response_chal; |
255 | | |
256 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL; |
257 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Version; |
258 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Flags; |
259 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_LM_PRESENT; |
260 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_NT_PRESENT; |
261 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_REMOVED; |
262 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_CREDKEY_PRESENT; |
263 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_SHA_PRESENT; |
264 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKey; |
265 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKeyType; |
266 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCredsSize; |
267 | | static int hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCreds; |
268 | | |
269 | | static int ett_ntlmssp; |
270 | | static int ett_ntlmssp_negotiate_flags; |
271 | | static int ett_ntlmssp_string; |
272 | | static int ett_ntlmssp_blob; |
273 | | static int ett_ntlmssp_version; |
274 | | static int ett_ntlmssp_challenge_target_info; |
275 | | static int ett_ntlmssp_challenge_target_info_item; |
276 | | static int ett_ntlmssp_ntlmv2_response; |
277 | | static int ett_ntlmssp_ntlmv2_response_item; |
278 | | static int ett_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL; |
279 | | |
280 | | static expert_field ei_ntlmssp_v2_key_too_long; |
281 | | static expert_field ei_ntlmssp_blob_len_too_long; |
282 | | static expert_field ei_ntlmssp_target_info_attr; |
283 | | static expert_field ei_ntlmssp_target_info_invalid; |
284 | | static expert_field ei_ntlmssp_message_type; |
285 | | static expert_field ei_ntlmssp_auth_nthash; |
286 | | static expert_field ei_ntlmssp_sessionbasekey; |
287 | | static expert_field ei_ntlmssp_sessionkey; |
288 | | |
289 | | static dissector_handle_t ntlmssp_handle, ntlmssp_wrap_handle; |
290 | | |
291 | | /* Configuration variables */ |
292 | | static const char *ntlmssp_option_nt_password; |
293 | | |
294 | 5.09k | #define NTLMSSP_CONV_INFO_KEY 0 |
295 | | /* Used in the conversation function */ |
296 | | typedef struct _ntlmssp_info { |
297 | | uint32_t flags; |
298 | | bool saw_challenge; |
299 | | gcry_cipher_hd_t rc4_handle_client; |
300 | | gcry_cipher_hd_t rc4_handle_server; |
301 | | uint8_t sign_key_client[NTLMSSP_KEY_LEN]; |
302 | | uint8_t sign_key_server[NTLMSSP_KEY_LEN]; |
303 | | uint32_t server_dest_port; |
304 | | unsigned char server_challenge[8]; |
305 | | bool rc4_state_initialized; |
306 | | ntlmssp_blob ntlm_response; |
307 | | ntlmssp_blob lm_response; |
308 | | } ntlmssp_info; |
309 | | |
310 | 69 | #define NTLMSSP_PACKET_INFO_KEY 1 |
311 | | /* If this struct exists in the payload_decrypt, then we have already |
312 | | decrypted it once */ |
313 | | typedef struct _ntlmssp_packet_info { |
314 | | uint8_t *decrypted_payload; |
315 | | uint8_t payload_len; |
316 | | uint8_t verifier[NTLMSSP_KEY_LEN]; |
317 | | bool payload_decrypted; |
318 | | bool verifier_decrypted; |
319 | | int verifier_offset; |
320 | | uint32_t verifier_block_length; |
321 | | } ntlmssp_packet_info; |
322 | | |
323 | | static int |
324 | | dissect_ntlmssp_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_); |
325 | | |
326 | | /* |
327 | | * GSlist of decrypted payloads. |
328 | | */ |
329 | | static GSList *decrypted_payloads; |
330 | | |
331 | | #if 0 |
332 | | static int |
333 | | LEBE_Convert(int value) |
334 | | { |
335 | | char a, b, c, d; |
336 | | /* Get each byte */ |
337 | | a = value&0x000000FF; |
338 | | b = (value&0x0000FF00) >> 8; |
339 | | c = (value&0x00FF0000) >> 16; |
340 | | d = (value&0xFF000000) >> 24; |
341 | | return (a << 24) | (b << 16) | (c << 8) | d; |
342 | | } |
343 | | #endif |
344 | | |
345 | | static bool |
346 | | ntlmssp_sessions_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_, void *user_data _U_) |
347 | 0 | { |
348 | 0 | ntlmssp_info * conv_ntlmssp_info = (ntlmssp_info *) user_data; |
349 | 0 | if (conv_ntlmssp_info->rc4_state_initialized) { |
350 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_client); |
351 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_server); |
352 | 0 | } |
353 | | /* unregister this callback */ |
354 | 0 | return false; |
355 | 0 | } |
356 | | |
357 | | /* |
358 | | Perform a DES encryption with a 16-byte key and 8-byte data item. |
359 | | It's in fact 3 subsequent call to crypt_des_ecb with a 7-byte key. |
360 | | Missing bytes for the key are replaced by 0; |
361 | | Returns output in response, which is expected to be 24 bytes. |
362 | | Returns true on success, false on failure (unlikely). |
363 | | */ |
364 | | static bool |
365 | | crypt_des_ecb_long(uint8_t *response, |
366 | | const uint8_t *key, |
367 | | const uint8_t *data) |
368 | 0 | { |
369 | 0 | uint8_t pw21[21] = { 0 }; /* 21 bytes place for the needed key */ |
370 | |
|
371 | 0 | memcpy(pw21, key, 16); |
372 | |
|
373 | 0 | memset(response, 0, 24); |
374 | 0 | if (crypt_des_ecb(response, data, pw21)) |
375 | 0 | return false; |
376 | 0 | if (crypt_des_ecb(response + 8, data, pw21 + 7)) |
377 | 0 | return false; |
378 | 0 | if (crypt_des_ecb(response + 16, data, pw21 + 14)) |
379 | 0 | return false; |
380 | | |
381 | 0 | return true; |
382 | 0 | } |
383 | | |
384 | | /* |
385 | | Generate a challenge response, given an eight byte challenge and |
386 | | either the NT or the Lan Manager password hash (16 bytes). |
387 | | Returns output in response, which is expected to be 24 bytes. |
388 | | Return true on success, false on failure (unlikely). |
389 | | */ |
390 | | static bool |
391 | | ntlmssp_generate_challenge_response(uint8_t *response, |
392 | | const uint8_t *passhash, |
393 | | const uint8_t *challenge) |
394 | 461 | { |
395 | 461 | uint8_t pw21[21]; /* Password hash padded to 21 bytes */ |
396 | | |
397 | 461 | memset(pw21, 0x0, sizeof(pw21)); |
398 | 461 | memcpy(pw21, passhash, 16); |
399 | | |
400 | 461 | memset(response, 0, 24); |
401 | | |
402 | 461 | if (crypt_des_ecb(response, challenge, pw21)) |
403 | 461 | return false; |
404 | 0 | if (crypt_des_ecb(response + 8, challenge, pw21 + 7)) |
405 | 0 | return false; |
406 | 0 | if (crypt_des_ecb(response + 16, challenge, pw21 + 14)) |
407 | 0 | return false; |
408 | | |
409 | 0 | return true; |
410 | 0 | } |
411 | | |
412 | | |
413 | | /* Ultra simple ANSI to unicode converter, will only work for ascii password...*/ |
414 | | static void |
415 | | ansi_to_unicode(const char* ansi, char* unicode) |
416 | 499 | { |
417 | 499 | size_t input_len; |
418 | 499 | size_t i; |
419 | | |
420 | 499 | input_len = strlen(ansi); |
421 | 499 | if (unicode != NULL) { |
422 | 681 | for (i = 0; i < (input_len); i++) { |
423 | 182 | unicode[i * 2] = ansi[i]; |
424 | 182 | unicode[i * 2 + 1] = 0; |
425 | 182 | } |
426 | 499 | unicode[2 * input_len] = '\0'; |
427 | 499 | } |
428 | 499 | } |
429 | | |
430 | | /* This function generate the Key Exchange Key (KXKEY) |
431 | | * Depending on the flags this key will either be used to encrypt the exported session key |
432 | | * or will be used directly as exported session key. |
433 | | * Exported session key is the key that will be used for sealing and signing communication |
434 | | * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/d86303b5-b29e-4fb9-b119-77579c761370 |
435 | | */ |
436 | | |
437 | | static void |
438 | | get_keyexchange_key(unsigned char keyexchangekey[NTLMSSP_KEY_LEN], const unsigned char sessionbasekey[NTLMSSP_KEY_LEN], const unsigned char lm_challenge_response[24], int flags) |
439 | 196 | { |
440 | 196 | uint8_t basekey[NTLMSSP_KEY_LEN]; |
441 | 196 | uint8_t zeros[24] = { 0 }; |
442 | | |
443 | 196 | memset(keyexchangekey, 0, NTLMSSP_KEY_LEN); |
444 | 196 | memset(basekey, 0, NTLMSSP_KEY_LEN); |
445 | | /* sessionbasekey is either derived from lm_hash or from nt_hash depending on the key type negotiated */ |
446 | 196 | memcpy(basekey, sessionbasekey, 8); |
447 | 196 | memset(basekey+8, 0xBD, 8); |
448 | 196 | if (flags&NTLMSSP_NEGOTIATE_LM_KEY) { |
449 | | /*data, key*/ |
450 | 120 | crypt_des_ecb(keyexchangekey, lm_challenge_response, basekey); |
451 | 120 | crypt_des_ecb(keyexchangekey+8, lm_challenge_response, basekey+7); |
452 | 120 | } |
453 | 76 | else { |
454 | 76 | if (flags&NTLMSSP_REQUEST_NON_NT_SESSION_KEY) { |
455 | | /*People from samba tends to use the same function in this case than in the previous one but with 0 data |
456 | | * it's not clear that it produce the good result |
457 | | * memcpy(keyexchangekey, lm_hash, 8); |
458 | | * Let's trust samba implementation it mights seem weird but they are more often right than the spec! |
459 | | */ |
460 | 76 | crypt_des_ecb(keyexchangekey, zeros, basekey); |
461 | 76 | crypt_des_ecb(keyexchangekey+8, zeros, basekey+7); |
462 | 76 | } |
463 | 0 | else { |
464 | | /* it is stated page 65 of NTLM SSP spec: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/d86303b5-b29e-4fb9-b119-77579c761370 |
465 | | * that sessionbasekey should be encrypted with hmac_md5 using the concat of both challenge when it's NTLM v1 + extended session security but it turns out to be wrong! |
466 | | */ |
467 | 0 | memcpy(keyexchangekey, sessionbasekey, NTLMSSP_KEY_LEN); |
468 | 0 | } |
469 | 76 | } |
470 | 196 | } |
471 | | |
472 | | uint32_t |
473 | | get_md4pass_list(wmem_allocator_t *pool, md4_pass** p_pass_list) |
474 | 19 | { |
475 | | #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS) |
476 | | uint32_t nb_pass = 0; |
477 | | const enc_key_t *ek; |
478 | | const char* password = ntlmssp_option_nt_password; |
479 | | unsigned char nt_hash[NTLMSSP_KEY_LEN]; |
480 | | char password_unicode[256]; |
481 | | md4_pass* pass_list; |
482 | | int i; |
483 | | |
484 | | *p_pass_list = NULL; |
485 | | read_keytab_file_from_preferences(); |
486 | | |
487 | | for (ek=keytab_get_enc_key_list(); ek; ek=ek->next) { |
488 | | if (NTLMSSP_EK_IS_NT4HASH(ek)) { |
489 | | nb_pass++; |
490 | | } |
491 | | } |
492 | | memset(password_unicode, 0, sizeof(password_unicode)); |
493 | | memset(nt_hash, 0, NTLMSSP_KEY_LEN); |
494 | | /* Compute the NT hash of the provided password, even if empty */ |
495 | | if (strlen(password) < 129) { |
496 | | int password_len; |
497 | | nb_pass++; |
498 | | password_len = (int)strlen(password); |
499 | | ansi_to_unicode(password, password_unicode); |
500 | | gcry_md_hash_buffer(GCRY_MD_MD4, nt_hash, password_unicode, password_len*2); |
501 | | } |
502 | | if (nb_pass == 0) { |
503 | | /* Unable to calculate the session key without a valid password (128 chars or less) ......*/ |
504 | | return 0; |
505 | | } |
506 | | i = 0; |
507 | | *p_pass_list = (md4_pass *)wmem_alloc0(pool, nb_pass*sizeof(md4_pass)); |
508 | | pass_list = *p_pass_list; |
509 | | |
510 | | if (memcmp(nt_hash, gbl_zeros, NTLMSSP_KEY_LEN) != 0) { |
511 | | memcpy(pass_list[i].md4, nt_hash, NTLMSSP_KEY_LEN); |
512 | | snprintf(pass_list[i].key_origin, NTLMSSP_MAX_ORIG_LEN, |
513 | | "<Global NT Password>"); |
514 | | i = 1; |
515 | | } |
516 | | for (ek=keytab_get_enc_key_list(); ek; ek=ek->next) { |
517 | | if (NTLMSSP_EK_IS_NT4HASH(ek)) { |
518 | | memcpy(pass_list[i].md4, ek->keyvalue, NTLMSSP_KEY_LEN); |
519 | | memcpy(pass_list[i].key_origin, ek->key_origin, |
520 | | MIN(sizeof(pass_list[i].key_origin),sizeof(ek->key_origin))); |
521 | | i++; |
522 | | } |
523 | | } |
524 | | return nb_pass; |
525 | | #else /* !(defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)) */ |
526 | 19 | (void) pool; |
527 | 19 | *p_pass_list = NULL; |
528 | 19 | return 0; |
529 | 19 | #endif /* !(defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)) */ |
530 | 19 | } |
531 | | |
532 | | /* Create an NTLMSSP version 2 key |
533 | | * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/5e550938-91d4-459f-b67d-75d70009e3f3 |
534 | | */ |
535 | | static void |
536 | | create_ntlmssp_v2_key(const uint8_t *serverchallenge, const uint8_t *clientchallenge, |
537 | | uint8_t *sessionkey , const uint8_t *encryptedsessionkey , int flags , |
538 | | const ntlmssp_blob *ntlm_response, const ntlmssp_blob *lm_response _U_, ntlmssp_header_t *ntlmssph, |
539 | | packet_info *pinfo, proto_tree *ntlmssp_tree) |
540 | 19 | { |
541 | | /* static const would be nicer, but -Werror=vla does not like it */ |
542 | 38 | #define DOMAIN_NAME_BUF_SIZE 512 |
543 | 57 | #define USER_BUF_SIZE 256 |
544 | 19 | #define BUF_SIZE (DOMAIN_NAME_BUF_SIZE + USER_BUF_SIZE) |
545 | 19 | char domain_name_unicode[DOMAIN_NAME_BUF_SIZE]; |
546 | 19 | char user_uppercase[USER_BUF_SIZE]; |
547 | 19 | char buf[BUF_SIZE]; |
548 | | /*uint8_t md4[NTLMSSP_KEY_LEN];*/ |
549 | 19 | unsigned char nt_hash[NTLMSSP_KEY_LEN]; |
550 | 19 | unsigned char nt_proof[NTLMSSP_KEY_LEN]; |
551 | 19 | unsigned char ntowfv2[NTLMSSP_KEY_LEN]; |
552 | 19 | uint8_t sessionbasekey[NTLMSSP_KEY_LEN]; |
553 | 19 | uint8_t keyexchangekey[NTLMSSP_KEY_LEN]; |
554 | 19 | uint8_t lm_challenge_response[24]; |
555 | 19 | uint32_t i; |
556 | 19 | uint32_t j; |
557 | 19 | gcry_cipher_hd_t rc4_handle; |
558 | 19 | size_t user_len; |
559 | 19 | size_t domain_len; |
560 | 19 | md4_pass *pass_list = NULL; |
561 | 19 | const md4_pass *used_md4 = NULL; |
562 | 19 | uint32_t nb_pass = 0; |
563 | 19 | bool found = false; |
564 | | |
565 | | /* We are going to try password encrypted in keytab as well, it's an idea of Stefan Metzmacher <metze@samba.org> |
566 | | * The idea is to be able to test all the key of domain in once and to be able to decode the NTLM dialogs */ |
567 | | |
568 | 19 | memset(sessionkey, 0, NTLMSSP_KEY_LEN); |
569 | 19 | nb_pass = get_md4pass_list(pinfo->pool, &pass_list); |
570 | 19 | i = 0; |
571 | 19 | memset(user_uppercase, 0, USER_BUF_SIZE); |
572 | 19 | user_len = strlen(ntlmssph->acct_name); |
573 | 19 | if (user_len < USER_BUF_SIZE / 2) { |
574 | 19 | memset(buf, 0, BUF_SIZE); |
575 | 19 | ansi_to_unicode(ntlmssph->acct_name, buf); |
576 | 383 | for (j = 0; j < (2*user_len); j++) { |
577 | 364 | if (buf[j] != '\0') { |
578 | 182 | user_uppercase[j] = g_ascii_toupper(buf[j]); |
579 | 182 | } |
580 | 364 | } |
581 | 19 | } |
582 | 0 | else { |
583 | | /* Unable to calculate the session not enough space in buffer, note this is unlikely to happen but ......*/ |
584 | 0 | return; |
585 | 0 | } |
586 | 19 | domain_len = strlen(ntlmssph->domain_name); |
587 | 19 | if (domain_len < DOMAIN_NAME_BUF_SIZE / 2) { |
588 | 19 | ansi_to_unicode(ntlmssph->domain_name, domain_name_unicode); |
589 | 19 | } |
590 | 0 | else { |
591 | | /* Unable to calculate the session not enough space in buffer, note this is unlikely to happen but ......*/ |
592 | 0 | return; |
593 | 0 | } |
594 | 19 | while (i < nb_pass) { |
595 | 0 | ws_debug("Turn %d", i); |
596 | 0 | used_md4 = &pass_list[i]; |
597 | 0 | memcpy(nt_hash, pass_list[i].md4, NTLMSSP_KEY_LEN); |
598 | 0 | ws_log_buffer(nt_hash, NTLMSSP_KEY_LEN, "Current NT hash"); |
599 | 0 | i++; |
600 | | /* NTOWFv2 computation */ |
601 | 0 | memset(buf, 0, BUF_SIZE); |
602 | 0 | memcpy(buf, user_uppercase, user_len*2); |
603 | 0 | memcpy(buf+user_len*2, domain_name_unicode, domain_len*2); |
604 | 0 | if (ws_hmac_buffer(GCRY_MD_MD5, ntowfv2, buf, domain_len*2+user_len*2, nt_hash, NTLMSSP_KEY_LEN)) { |
605 | 0 | return; |
606 | 0 | } |
607 | 0 | ws_log_buffer(ntowfv2, NTLMSSP_KEY_LEN, "NTOWFv2"); |
608 | | |
609 | | /* LM response */ |
610 | 0 | memset(buf, 0, BUF_SIZE); |
611 | 0 | memcpy(buf, serverchallenge, 8); |
612 | 0 | memcpy(buf+8, clientchallenge, 8); |
613 | 0 | if (ws_hmac_buffer(GCRY_MD_MD5, lm_challenge_response, buf, NTLMSSP_KEY_LEN, ntowfv2, NTLMSSP_KEY_LEN)) { |
614 | 0 | return; |
615 | 0 | } |
616 | 0 | memcpy(lm_challenge_response+NTLMSSP_KEY_LEN, clientchallenge, 8); |
617 | 0 | ws_log_buffer(lm_challenge_response, 24, "LM Response"); |
618 | | |
619 | | /* NT proof = First NTLMSSP_KEY_LEN bytes of NT response */ |
620 | 0 | memset(buf, 0, BUF_SIZE); |
621 | 0 | memcpy(buf, serverchallenge, 8); |
622 | 0 | memcpy(buf+8, ntlm_response->contents+NTLMSSP_KEY_LEN, MIN(BUF_SIZE - 8, ntlm_response->length-NTLMSSP_KEY_LEN)); |
623 | 0 | if (ws_hmac_buffer(GCRY_MD_MD5, nt_proof, buf, ntlm_response->length-8, ntowfv2, NTLMSSP_KEY_LEN)) { |
624 | 0 | return; |
625 | 0 | } |
626 | 0 | ws_log_buffer(nt_proof, NTLMSSP_KEY_LEN, "NT proof"); |
627 | 0 | if (!memcmp(nt_proof, ntlm_response->contents, NTLMSSP_KEY_LEN)) { |
628 | 0 | found = true; |
629 | 0 | break; |
630 | 0 | } |
631 | 0 | } |
632 | 19 | if (!found) { |
633 | 19 | return; |
634 | 19 | } |
635 | | |
636 | 0 | if (ws_hmac_buffer(GCRY_MD_MD5, sessionbasekey, nt_proof, NTLMSSP_KEY_LEN, ntowfv2, NTLMSSP_KEY_LEN)) { |
637 | 0 | return; |
638 | 0 | } |
639 | | |
640 | 0 | get_keyexchange_key(keyexchangekey, sessionbasekey, lm_challenge_response, flags); |
641 | | /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ |
642 | 0 | if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH) |
643 | 0 | { |
644 | 0 | memcpy(sessionkey, encryptedsessionkey, NTLMSSP_KEY_LEN); |
645 | 0 | if (!gcry_cipher_open(&rc4_handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
646 | 0 | if (!gcry_cipher_setkey(rc4_handle, keyexchangekey, NTLMSSP_KEY_LEN)) { |
647 | 0 | gcry_cipher_decrypt(rc4_handle, sessionkey, NTLMSSP_KEY_LEN, NULL, 0); |
648 | 0 | } |
649 | 0 | gcry_cipher_close(rc4_handle); |
650 | 0 | } |
651 | 0 | } |
652 | 0 | else |
653 | 0 | { |
654 | 0 | memcpy(sessionkey, keyexchangekey, NTLMSSP_KEY_LEN); |
655 | 0 | } |
656 | |
|
657 | 0 | memcpy(ntlmssph->session_key, sessionkey, NTLMSSP_KEY_LEN); |
658 | |
|
659 | 0 | if (used_md4 == NULL) { |
660 | 0 | return; |
661 | 0 | } |
662 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
663 | 0 | &ei_ntlmssp_auth_nthash, |
664 | 0 | "NTLMv2 authenticated using %s (%02x%02x%02x%02x...)", |
665 | 0 | used_md4->key_origin, |
666 | 0 | used_md4->md4[0] & 0xFF, used_md4->md4[1] & 0xFF, |
667 | 0 | used_md4->md4[2] & 0xFF, used_md4->md4[3] & 0xFF); |
668 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
669 | 0 | &ei_ntlmssp_sessionbasekey, |
670 | 0 | "NTLMv2 BaseSessionKey (" |
671 | 0 | "%02x%02x%02x%02x" |
672 | 0 | "%02x%02x%02x%02x" |
673 | 0 | "%02x%02x%02x%02x" |
674 | 0 | "%02x%02x%02x%02x" |
675 | 0 | ")", |
676 | 0 | sessionbasekey[0] & 0xFF, sessionbasekey[1] & 0xFF, |
677 | 0 | sessionbasekey[2] & 0xFF, sessionbasekey[3] & 0xFF, |
678 | 0 | sessionbasekey[4] & 0xFF, sessionbasekey[5] & 0xFF, |
679 | 0 | sessionbasekey[6] & 0xFF, sessionbasekey[7] & 0xFF, |
680 | 0 | sessionbasekey[8] & 0xFF, sessionbasekey[9] & 0xFF, |
681 | 0 | sessionbasekey[10] & 0xFF, sessionbasekey[11] & 0xFF, |
682 | 0 | sessionbasekey[12] & 0xFF, sessionbasekey[13] & 0xFF, |
683 | 0 | sessionbasekey[14] & 0xFF, sessionbasekey[15] & 0xFF); |
684 | 0 | if (memcmp(sessionbasekey, sessionkey, NTLMSSP_KEY_LEN) == 0) { |
685 | 0 | return; |
686 | 0 | } |
687 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
688 | 0 | &ei_ntlmssp_sessionkey, |
689 | 0 | "NTLMSSP SessionKey (" |
690 | 0 | "%02x%02x%02x%02x" |
691 | 0 | "%02x%02x%02x%02x" |
692 | 0 | "%02x%02x%02x%02x" |
693 | 0 | "%02x%02x%02x%02x" |
694 | 0 | ")", |
695 | 0 | sessionkey[0] & 0xFF, sessionkey[1] & 0xFF, |
696 | 0 | sessionkey[2] & 0xFF, sessionkey[3] & 0xFF, |
697 | 0 | sessionkey[4] & 0xFF, sessionkey[5] & 0xFF, |
698 | 0 | sessionkey[6] & 0xFF, sessionkey[7] & 0xFF, |
699 | 0 | sessionkey[8] & 0xFF, sessionkey[9] & 0xFF, |
700 | 0 | sessionkey[10] & 0xFF, sessionkey[11] & 0xFF, |
701 | 0 | sessionkey[12] & 0xFF, sessionkey[13] & 0xFF, |
702 | 0 | sessionkey[14] & 0xFF, sessionkey[15] & 0xFF); |
703 | 0 | } |
704 | | |
705 | | /* Create an NTLMSSP version 1 key |
706 | | * That is more complicated logic and methods and user challenge as well. |
707 | | * password points to the ANSI password to encrypt, challenge points to |
708 | | * the 8 octet challenge string |
709 | | * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/464551a8-9fc4-428e-b3d3-bc5bfb2e73a5 |
710 | | */ |
711 | | static void |
712 | | create_ntlmssp_v1_key(const uint8_t *serverchallenge, const uint8_t *clientchallenge, |
713 | | uint8_t *sessionkey, const uint8_t *encryptedsessionkey, int flags, |
714 | | const uint8_t *ref_nt_challenge_response, const uint8_t *ref_lm_challenge_response, |
715 | | ntlmssp_header_t *ntlmssph, |
716 | | packet_info *pinfo, proto_tree *ntlmssp_tree) |
717 | 461 | { |
718 | 461 | const char *password = ntlmssp_option_nt_password; |
719 | 461 | unsigned char lm_password_upper[NTLMSSP_KEY_LEN]; |
720 | 461 | unsigned char lm_hash[NTLMSSP_KEY_LEN]; |
721 | 461 | unsigned char nt_hash[NTLMSSP_KEY_LEN]; |
722 | 461 | unsigned char challenges_hash_first8[8]; |
723 | 461 | unsigned char challenges[NTLMSSP_KEY_LEN]; |
724 | 461 | uint8_t md4[NTLMSSP_KEY_LEN]; |
725 | 461 | uint8_t nb_pass = 0; |
726 | 461 | uint8_t sessionbasekey[NTLMSSP_KEY_LEN]; |
727 | 461 | uint8_t keyexchangekey[NTLMSSP_KEY_LEN]; |
728 | 461 | uint8_t lm_challenge_response[24]; |
729 | 461 | uint8_t nt_challenge_response[24]; |
730 | 461 | gcry_cipher_hd_t rc4_handle; |
731 | 461 | gcry_md_hd_t md5_handle; |
732 | 461 | char password_unicode[256]; |
733 | 461 | size_t password_len; |
734 | 461 | unsigned int i; |
735 | 461 | bool found = false; |
736 | 461 | md4_pass *pass_list = NULL; |
737 | 461 | const md4_pass *used_md4 = NULL; |
738 | | |
739 | | // "A Boolean setting that SHOULD<35> control using the NTLM response for the LM response to the server challenge when NTLMv1 authentication is used. The default value of this state variable is true." |
740 | | // "<35> Section 3.1.1.1: Windows NT Server 4.0 SP3 does not support providing NTLM instead of LM responses." |
741 | | // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f711d059-3983-4b9d-afbb-ff2f8c97ffbf |
742 | 461 | static const bool NoLMResponseNTLMv1 = true; |
743 | | |
744 | 461 | static const unsigned char lmhash_key[] = |
745 | 461 | {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; // "KGS!@#$%" |
746 | | |
747 | 461 | memset(sessionkey, 0, NTLMSSP_KEY_LEN); |
748 | | /* Create a NT hash of the input password, even if empty */ |
749 | | // NTOWFv1 as defined in https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/464551a8-9fc4-428e-b3d3-bc5bfb2e73a5 |
750 | 461 | password_len = strlen(password); |
751 | | /*Do not forget to free password*/ |
752 | 461 | ansi_to_unicode(password, password_unicode); |
753 | 461 | gcry_md_hash_buffer(GCRY_MD_MD4, nt_hash, password_unicode, password_len*2); |
754 | | |
755 | 461 | if ((flags & NTLMSSP_NEGOTIATE_LM_KEY && !(flags & NoLMResponseNTLMv1)) || !(flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) || !(flags & NTLMSSP_NEGOTIATE_NTLM)) { |
756 | | /* Create a LM hash of the input password, even if empty */ |
757 | | // LMOWFv1 as defined in https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/464551a8-9fc4-428e-b3d3-bc5bfb2e73a5 |
758 | | /* Truncate password if too long */ |
759 | 461 | if (password_len > NTLMSSP_KEY_LEN) |
760 | 0 | password_len = NTLMSSP_KEY_LEN; |
761 | | |
762 | 461 | memset(lm_password_upper, 0, sizeof(lm_password_upper)); |
763 | 461 | for (i = 0; i < password_len; i++) { |
764 | 0 | lm_password_upper[i] = g_ascii_toupper(password[i]); |
765 | 0 | } |
766 | | |
767 | 461 | crypt_des_ecb(lm_hash, lmhash_key, lm_password_upper); |
768 | 461 | crypt_des_ecb(lm_hash+8, lmhash_key, lm_password_upper+7); |
769 | 461 | ntlmssp_generate_challenge_response(lm_challenge_response, |
770 | 461 | lm_hash, serverchallenge); |
771 | 461 | memcpy(sessionbasekey, lm_hash, NTLMSSP_KEY_LEN); |
772 | 461 | } |
773 | 0 | else { |
774 | |
|
775 | 0 | memset(lm_challenge_response, 0, 24); |
776 | 0 | if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) { |
777 | 0 | nb_pass = get_md4pass_list(pinfo->pool, &pass_list); |
778 | 0 | i = 0; |
779 | 0 | while (i < nb_pass) { |
780 | | /*ws_debug("Turn %d", i);*/ |
781 | 0 | used_md4 = &pass_list[i]; |
782 | 0 | memcpy(nt_hash, pass_list[i].md4, NTLMSSP_KEY_LEN); |
783 | | /*ws_log_buffer(nt_hash, NTLMSSP_KEY_LEN, "Current NT hash");*/ |
784 | 0 | i++; |
785 | 0 | if(clientchallenge){ |
786 | 0 | memcpy(lm_challenge_response, clientchallenge, 8); |
787 | 0 | } |
788 | 0 | if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) { |
789 | 0 | break; |
790 | 0 | } |
791 | 0 | gcry_md_write(md5_handle, serverchallenge, 8); |
792 | 0 | gcry_md_write(md5_handle, clientchallenge, 8); |
793 | 0 | memcpy(challenges_hash_first8, gcry_md_read(md5_handle, 0), 8); |
794 | 0 | gcry_md_close(md5_handle); |
795 | 0 | crypt_des_ecb_long(nt_challenge_response, nt_hash, challenges_hash_first8); |
796 | 0 | if (ref_nt_challenge_response && !memcmp(ref_nt_challenge_response, nt_challenge_response, 24)) { |
797 | 0 | found = true; |
798 | 0 | break; |
799 | 0 | } |
800 | 0 | } |
801 | 0 | } |
802 | 0 | else { |
803 | 0 | crypt_des_ecb_long(nt_challenge_response, nt_hash, serverchallenge); |
804 | 0 | if (NoLMResponseNTLMv1) { |
805 | 0 | memcpy(lm_challenge_response, nt_challenge_response, 24); |
806 | 0 | } |
807 | 0 | else { |
808 | 0 | crypt_des_ecb_long(lm_challenge_response, lm_hash, serverchallenge); |
809 | 0 | } |
810 | 0 | if (ref_nt_challenge_response && |
811 | 0 | !memcmp(ref_nt_challenge_response, nt_challenge_response, 24) && |
812 | 0 | ref_lm_challenge_response && |
813 | 0 | !memcmp(ref_lm_challenge_response, lm_challenge_response, 24)) |
814 | 0 | { |
815 | 0 | found = true; |
816 | 0 | } |
817 | 0 | } |
818 | | /* So it's clearly not like this that's put into NTLMSSP doc but after some digging into samba code I'm quite confident |
819 | | * that sessionbasekey should be based md4(nt_hash) only in the case of some NT auth |
820 | | * Otherwise it should be lm_hash ...*/ |
821 | 0 | gcry_md_hash_buffer(GCRY_MD_MD4, md4, nt_hash, NTLMSSP_KEY_LEN); |
822 | 0 | if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) { |
823 | 0 | memcpy(challenges, serverchallenge, 8); |
824 | 0 | if(clientchallenge){ |
825 | 0 | memcpy(challenges+8, clientchallenge, 8); |
826 | 0 | } |
827 | 0 | if (ws_hmac_buffer(GCRY_MD_MD5, sessionbasekey, challenges, NTLMSSP_KEY_LEN, md4, NTLMSSP_KEY_LEN)) { |
828 | 0 | return; |
829 | 0 | } |
830 | 0 | } |
831 | 0 | else { |
832 | 0 | memcpy(sessionbasekey, md4, NTLMSSP_KEY_LEN); |
833 | 0 | } |
834 | 0 | } |
835 | | |
836 | 461 | if (!found) { |
837 | 461 | return; |
838 | 461 | } |
839 | | |
840 | 0 | get_keyexchange_key(keyexchangekey, sessionbasekey, lm_challenge_response, flags); |
841 | | /*ws_log_buffer(nt_challenge_response, 24, "NT challenge response"); |
842 | | ws_log_buffer(lm_challenge_response, 24, "LM challenge response");*/ |
843 | | /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ |
844 | 0 | if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH) |
845 | 0 | { |
846 | 0 | if(encryptedsessionkey){ |
847 | 0 | memcpy(sessionkey, encryptedsessionkey, NTLMSSP_KEY_LEN); |
848 | 0 | } |
849 | 0 | if (!gcry_cipher_open(&rc4_handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
850 | 0 | if (!gcry_cipher_setkey(rc4_handle, keyexchangekey, NTLMSSP_KEY_LEN)) { |
851 | 0 | gcry_cipher_decrypt(rc4_handle, sessionkey, NTLMSSP_KEY_LEN, NULL, 0); |
852 | 0 | } |
853 | 0 | gcry_cipher_close(rc4_handle); |
854 | 0 | } |
855 | 0 | } |
856 | 0 | else |
857 | 0 | { |
858 | 0 | memcpy(sessionkey, keyexchangekey, NTLMSSP_KEY_LEN); |
859 | 0 | } |
860 | 0 | memcpy(ntlmssph->session_key, sessionkey, NTLMSSP_KEY_LEN); |
861 | |
|
862 | 0 | if (used_md4 == NULL) { |
863 | 0 | return; |
864 | 0 | } |
865 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
866 | 0 | &ei_ntlmssp_auth_nthash, |
867 | 0 | "NTLMv1 authenticated using %s (%02x%02x%02x%02x...)", |
868 | 0 | used_md4->key_origin, |
869 | 0 | used_md4->md4[0] & 0xFF, used_md4->md4[1] & 0xFF, |
870 | 0 | used_md4->md4[2] & 0xFF, used_md4->md4[3] & 0xFF); |
871 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
872 | 0 | &ei_ntlmssp_sessionbasekey, |
873 | 0 | "NTLMv1 BaseSessionKey (" |
874 | 0 | "%02x%02x%02x%02x" |
875 | 0 | "%02x%02x%02x%02x" |
876 | 0 | "%02x%02x%02x%02x" |
877 | 0 | "%02x%02x%02x%02x" |
878 | 0 | ")", |
879 | 0 | sessionbasekey[0] & 0xFF, sessionbasekey[1] & 0xFF, |
880 | 0 | sessionbasekey[2] & 0xFF, sessionbasekey[3] & 0xFF, |
881 | 0 | sessionbasekey[4] & 0xFF, sessionbasekey[5] & 0xFF, |
882 | 0 | sessionbasekey[6] & 0xFF, sessionbasekey[7] & 0xFF, |
883 | 0 | sessionbasekey[8] & 0xFF, sessionbasekey[9] & 0xFF, |
884 | 0 | sessionbasekey[10] & 0xFF, sessionbasekey[11] & 0xFF, |
885 | 0 | sessionbasekey[12] & 0xFF, sessionbasekey[13] & 0xFF, |
886 | 0 | sessionbasekey[14] & 0xFF, sessionbasekey[15] & 0xFF); |
887 | 0 | if (memcmp(sessionbasekey, sessionkey, NTLMSSP_KEY_LEN) == 0) { |
888 | 0 | return; |
889 | 0 | } |
890 | 0 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
891 | 0 | &ei_ntlmssp_sessionkey, |
892 | 0 | "NTLMSSP SessionKey (" |
893 | 0 | "%02x%02x%02x%02x" |
894 | 0 | "%02x%02x%02x%02x" |
895 | 0 | "%02x%02x%02x%02x" |
896 | 0 | "%02x%02x%02x%02x" |
897 | 0 | ")", |
898 | 0 | sessionkey[0] & 0xFF, sessionkey[1] & 0xFF, |
899 | 0 | sessionkey[2] & 0xFF, sessionkey[3] & 0xFF, |
900 | 0 | sessionkey[4] & 0xFF, sessionkey[5] & 0xFF, |
901 | 0 | sessionkey[6] & 0xFF, sessionkey[7] & 0xFF, |
902 | 0 | sessionkey[8] & 0xFF, sessionkey[9] & 0xFF, |
903 | 0 | sessionkey[10] & 0xFF, sessionkey[11] & 0xFF, |
904 | 0 | sessionkey[12] & 0xFF, sessionkey[13] & 0xFF, |
905 | 0 | sessionkey[14] & 0xFF, sessionkey[15] & 0xFF); |
906 | 0 | } |
907 | | |
908 | | /* |
909 | | * Create an NTLMSSP anonymous key |
910 | | */ |
911 | | static void |
912 | | create_ntlmssp_anon_key(uint8_t *sessionkey, const uint8_t *encryptedsessionkey, int flags, |
913 | | ntlmssp_header_t *ntlmssph, |
914 | | packet_info *pinfo, proto_tree *ntlmssp_tree) |
915 | 196 | { |
916 | 196 | uint8_t lm_challenge_response[24] = { 0, }; |
917 | 196 | uint8_t sessionbasekey[NTLMSSP_KEY_LEN] = { 0, }; |
918 | 196 | uint8_t keyexchangekey[NTLMSSP_KEY_LEN] = { 0, }; |
919 | 196 | gcry_cipher_hd_t rc4_handle; |
920 | | |
921 | 196 | memset(sessionkey, 0, NTLMSSP_KEY_LEN); |
922 | | |
923 | 196 | get_keyexchange_key(keyexchangekey, sessionbasekey, lm_challenge_response, flags); |
924 | 196 | if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH) |
925 | 178 | { |
926 | 178 | if(encryptedsessionkey){ |
927 | 178 | memcpy(sessionkey, encryptedsessionkey, NTLMSSP_KEY_LEN); |
928 | 178 | } |
929 | 178 | if (!gcry_cipher_open(&rc4_handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
930 | 178 | if (!gcry_cipher_setkey(rc4_handle, keyexchangekey, NTLMSSP_KEY_LEN)) { |
931 | 178 | gcry_cipher_decrypt(rc4_handle, sessionkey, NTLMSSP_KEY_LEN, NULL, 0); |
932 | 178 | } |
933 | 178 | gcry_cipher_close(rc4_handle); |
934 | 178 | } |
935 | 178 | } |
936 | 18 | else |
937 | 18 | { |
938 | 18 | memcpy(sessionkey, keyexchangekey, NTLMSSP_KEY_LEN); |
939 | 18 | } |
940 | 196 | memcpy(ntlmssph->session_key, sessionkey, NTLMSSP_KEY_LEN); |
941 | | |
942 | 196 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
943 | 196 | &ei_ntlmssp_auth_nthash, |
944 | 196 | "NTLM authenticated using ANONYMOUS ZERO NTHASH"); |
945 | 196 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
946 | 196 | &ei_ntlmssp_sessionbasekey, |
947 | 196 | "NTLM Anonymous BaseSessionKey (" |
948 | 196 | "%02x%02x%02x%02x" |
949 | 196 | "%02x%02x%02x%02x" |
950 | 196 | "%02x%02x%02x%02x" |
951 | 196 | "%02x%02x%02x%02x" |
952 | 196 | ")", |
953 | 196 | sessionbasekey[0] & 0xFF, sessionbasekey[1] & 0xFF, |
954 | 196 | sessionbasekey[2] & 0xFF, sessionbasekey[3] & 0xFF, |
955 | 196 | sessionbasekey[4] & 0xFF, sessionbasekey[5] & 0xFF, |
956 | 196 | sessionbasekey[6] & 0xFF, sessionbasekey[7] & 0xFF, |
957 | 196 | sessionbasekey[8] & 0xFF, sessionbasekey[9] & 0xFF, |
958 | 196 | sessionbasekey[10] & 0xFF, sessionbasekey[11] & 0xFF, |
959 | 196 | sessionbasekey[12] & 0xFF, sessionbasekey[13] & 0xFF, |
960 | 196 | sessionbasekey[14] & 0xFF, sessionbasekey[15] & 0xFF); |
961 | 196 | if (memcmp(sessionbasekey, sessionkey, NTLMSSP_KEY_LEN) == 0) { |
962 | 0 | return; |
963 | 0 | } |
964 | 196 | expert_add_info_format(pinfo, proto_tree_get_parent(ntlmssp_tree), |
965 | 196 | &ei_ntlmssp_sessionkey, |
966 | 196 | "NTLMSSP SessionKey Anonymous (" |
967 | 196 | "%02x%02x%02x%02x" |
968 | 196 | "%02x%02x%02x%02x" |
969 | 196 | "%02x%02x%02x%02x" |
970 | 196 | "%02x%02x%02x%02x" |
971 | 196 | ")", |
972 | 196 | sessionkey[0] & 0xFF, sessionkey[1] & 0xFF, |
973 | 196 | sessionkey[2] & 0xFF, sessionkey[3] & 0xFF, |
974 | 196 | sessionkey[4] & 0xFF, sessionkey[5] & 0xFF, |
975 | 196 | sessionkey[6] & 0xFF, sessionkey[7] & 0xFF, |
976 | 196 | sessionkey[8] & 0xFF, sessionkey[9] & 0xFF, |
977 | 196 | sessionkey[10] & 0xFF, sessionkey[11] & 0xFF, |
978 | 196 | sessionkey[12] & 0xFF, sessionkey[13] & 0xFF, |
979 | 196 | sessionkey[14] & 0xFF, sessionkey[15] & 0xFF); |
980 | 196 | } |
981 | | |
982 | | void |
983 | | ntlmssp_create_session_key(packet_info *pinfo, |
984 | | proto_tree *tree, |
985 | | ntlmssp_header_t *ntlmssph, |
986 | | int flags, |
987 | | const uint8_t *server_challenge, |
988 | | const uint8_t *encryptedsessionkey, |
989 | | const ntlmssp_blob *ntlm_response, |
990 | | const ntlmssp_blob *lm_response) |
991 | 279 | { |
992 | 279 | uint8_t client_challenge[8] = {0, }; |
993 | 279 | uint8_t sessionkey[NTLMSSP_KEY_LEN] = {0, }; |
994 | | |
995 | 279 | if (ntlm_response->length > 24) |
996 | 19 | { |
997 | | /* |
998 | | * [MS-NLMP] 2.2.2.8 NTLM2 V2 Response: NTLMv2_RESPONSE has |
999 | | * the 2.2.2.7 "NTLM v2: NTLMv2_CLIENT_CHALLENGE" at offset 16. |
1000 | | * Within that ChallengeFromClient is at offset 16, that means |
1001 | | * it's at offset 32 in total. |
1002 | | * |
1003 | | * Note that value is only used for the LM_response of NTLMv2. |
1004 | | */ |
1005 | 19 | if (ntlm_response->length >= 40) { |
1006 | 5 | memcpy(client_challenge, |
1007 | 5 | ntlm_response->contents+32, 8); |
1008 | 5 | } |
1009 | 19 | create_ntlmssp_v2_key(server_challenge, |
1010 | 19 | client_challenge, |
1011 | 19 | sessionkey, |
1012 | 19 | encryptedsessionkey, |
1013 | 19 | flags, |
1014 | 19 | ntlm_response, |
1015 | 19 | lm_response, |
1016 | 19 | ntlmssph, |
1017 | 19 | pinfo, |
1018 | 19 | tree); |
1019 | 19 | } |
1020 | 260 | else if (ntlm_response->length == 24 && lm_response->length == 24) |
1021 | 32 | { |
1022 | 32 | memcpy(client_challenge, lm_response->contents, 8); |
1023 | | |
1024 | 32 | create_ntlmssp_v1_key(server_challenge, |
1025 | 32 | client_challenge, |
1026 | 32 | sessionkey, |
1027 | 32 | encryptedsessionkey, |
1028 | 32 | flags, |
1029 | 32 | ntlm_response->contents, |
1030 | 32 | lm_response->contents, |
1031 | 32 | ntlmssph, |
1032 | 32 | pinfo, |
1033 | 32 | tree); |
1034 | 32 | } |
1035 | 228 | else if (ntlm_response->length == 0 && lm_response->length <= 1) |
1036 | 196 | { |
1037 | 196 | create_ntlmssp_anon_key(sessionkey, |
1038 | 196 | encryptedsessionkey, |
1039 | 196 | flags, |
1040 | 196 | ntlmssph, |
1041 | 196 | pinfo, |
1042 | 196 | tree); |
1043 | 196 | } |
1044 | 279 | } |
1045 | | |
1046 | | static void |
1047 | | get_signing_key(uint8_t *sign_key_server, uint8_t* sign_key_client, const uint8_t key[NTLMSSP_KEY_LEN], int keylen) |
1048 | 196 | { |
1049 | 196 | gcry_md_hd_t md5_handle; |
1050 | | |
1051 | 196 | memset(sign_key_client, 0, NTLMSSP_KEY_LEN); |
1052 | 196 | memset(sign_key_server, 0, NTLMSSP_KEY_LEN); |
1053 | 196 | if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) { |
1054 | 0 | return; |
1055 | 0 | } |
1056 | 196 | gcry_md_write(md5_handle, key, keylen); |
1057 | 196 | gcry_md_write(md5_handle, CLIENT_SIGN_TEXT, strlen(CLIENT_SIGN_TEXT)+1); // +1 to get the final null-byte |
1058 | 196 | memcpy(sign_key_client, gcry_md_read(md5_handle, 0), NTLMSSP_KEY_LEN); |
1059 | 196 | gcry_md_reset(md5_handle); |
1060 | 196 | gcry_md_write(md5_handle, key, keylen); |
1061 | 196 | gcry_md_write(md5_handle, SERVER_SIGN_TEXT, strlen(SERVER_SIGN_TEXT)+1); // +1 to get the final null-byte |
1062 | 196 | memcpy(sign_key_server, gcry_md_read(md5_handle, 0), NTLMSSP_KEY_LEN); |
1063 | 196 | gcry_md_close(md5_handle); |
1064 | 196 | } |
1065 | | |
1066 | | /* We return either a 128 or 64 bit key |
1067 | | */ |
1068 | | static void |
1069 | | get_sealing_rc4key(const uint8_t exportedsessionkey[NTLMSSP_KEY_LEN] , const int flags , int *keylen , |
1070 | | uint8_t *clientsealkey , uint8_t *serversealkey) |
1071 | 196 | { |
1072 | 196 | gcry_md_hd_t md5_handle; |
1073 | | |
1074 | 196 | memset(clientsealkey, 0, NTLMSSP_KEY_LEN); |
1075 | 196 | memset(serversealkey, 0, NTLMSSP_KEY_LEN); |
1076 | 196 | memcpy(clientsealkey, exportedsessionkey, NTLMSSP_KEY_LEN); |
1077 | 196 | if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) |
1078 | 196 | { |
1079 | 196 | if (flags & NTLMSSP_NEGOTIATE_128) |
1080 | 2 | { |
1081 | | /* The exportedsessionkey has already the good length just update the length*/ |
1082 | 2 | *keylen = 16; |
1083 | 2 | } |
1084 | 194 | else |
1085 | 194 | { |
1086 | 194 | if (flags & NTLMSSP_NEGOTIATE_56) |
1087 | 63 | { |
1088 | 63 | memset(clientsealkey+7, 0, 9); |
1089 | 63 | *keylen = 7; |
1090 | 63 | } |
1091 | 131 | else |
1092 | 131 | { |
1093 | 131 | memset(clientsealkey+5, 0, 11); |
1094 | 131 | *keylen = 5; |
1095 | 131 | } |
1096 | 194 | } |
1097 | 196 | memcpy(serversealkey, clientsealkey, NTLMSSP_KEY_LEN); |
1098 | 196 | if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) { |
1099 | 0 | return; |
1100 | 0 | } |
1101 | 196 | gcry_md_write(md5_handle, clientsealkey, *keylen); |
1102 | 196 | gcry_md_write(md5_handle, CLIENT_SEAL_TEXT, strlen(CLIENT_SEAL_TEXT)+1); // +1 to get the final null-byte |
1103 | 196 | memcpy(clientsealkey, gcry_md_read(md5_handle, 0), NTLMSSP_KEY_LEN); |
1104 | 196 | gcry_md_reset(md5_handle); |
1105 | 196 | gcry_md_write(md5_handle, serversealkey, *keylen); |
1106 | 196 | gcry_md_write(md5_handle, SERVER_SEAL_TEXT, strlen(SERVER_SEAL_TEXT)+1); // +1 to get the final null-byte |
1107 | 196 | memcpy(serversealkey, gcry_md_read(md5_handle, 0), NTLMSSP_KEY_LEN); |
1108 | 196 | gcry_md_close(md5_handle); |
1109 | 196 | } |
1110 | 0 | else |
1111 | 0 | { |
1112 | 0 | if (flags & NTLMSSP_NEGOTIATE_128) |
1113 | 0 | { |
1114 | | /* The exportedsessionkey has already the good length just update the length*/ |
1115 | 0 | *keylen = 16; |
1116 | 0 | } |
1117 | 0 | else |
1118 | 0 | { |
1119 | 0 | *keylen = 8; |
1120 | 0 | if (flags & NTLMSSP_NEGOTIATE_56) |
1121 | 0 | { |
1122 | 0 | memset(clientsealkey+7, 0, 9); |
1123 | 0 | } |
1124 | 0 | else |
1125 | 0 | { |
1126 | 0 | memset(clientsealkey+5, 0, 11); |
1127 | 0 | clientsealkey[5]=0xe5; |
1128 | 0 | clientsealkey[6]=0x38; |
1129 | 0 | clientsealkey[7]=0xb0; |
1130 | 0 | } |
1131 | 0 | } |
1132 | 0 | memcpy(serversealkey, clientsealkey,*keylen); |
1133 | 0 | } |
1134 | 196 | } |
1135 | | /* Create an NTLMSSP version 1 key. |
1136 | | * password points to the ANSI password to encrypt, challenge points to |
1137 | | * the 8 octet challenge string, key128 will do a 128 bit key if set to 1, |
1138 | | * otherwise it will do a 40 bit key. The result is stored in |
1139 | | * sspkey (expected to be NTLMSSP_KEY_LEN octets) |
1140 | | */ |
1141 | | /* dissect a string - header area contains: |
1142 | | two byte len |
1143 | | two byte maxlen |
1144 | | four byte offset of string in data area |
1145 | | The function returns the offset at the end of the string header, |
1146 | | but the 'end' parameter returns the offset of the end of the string itself |
1147 | | The 'start' parameter returns the offset of the beginning of the string |
1148 | | If there's no string, just use the offset of the end of the tvb as start/end. |
1149 | | */ |
1150 | | static int |
1151 | | dissect_ntlmssp_string (tvbuff_t *tvb, wmem_allocator_t* allocator, int offset, |
1152 | | proto_tree *ntlmssp_tree, |
1153 | | bool unicode_strings, |
1154 | | int string_hf, int *start, int *end, |
1155 | | const char **stringp) |
1156 | 11.7k | { |
1157 | 11.7k | proto_tree *tree = NULL; |
1158 | 11.7k | proto_item *tf = NULL; |
1159 | 11.7k | uint16_t string_length = tvb_get_letohs(tvb, offset); |
1160 | 11.7k | uint16_t string_maxlen = tvb_get_letohs(tvb, offset+2); |
1161 | 11.7k | uint32_t string_offset = tvb_get_letohl(tvb, offset+4); |
1162 | | |
1163 | 11.7k | if (string_offset > (unsigned)(unicode_strings ? INT_MAX - 1 : INT_MAX)) { |
1164 | 321 | THROW(ReportedBoundsError); |
1165 | 321 | } |
1166 | | |
1167 | 11.7k | *start = ((int)string_offset > offset+8 ? (int)string_offset : (int)tvb_reported_length(tvb)); |
1168 | 11.7k | if (0 == string_length) { |
1169 | 6.79k | *end = *start; |
1170 | 6.79k | if (ntlmssp_tree) |
1171 | 6.79k | proto_tree_add_string(ntlmssp_tree, string_hf, tvb, |
1172 | 6.79k | offset, 8, "NULL"); |
1173 | 6.79k | if (stringp != NULL) |
1174 | 4.51k | *stringp = ""; |
1175 | 6.79k | return offset+8; |
1176 | 6.79k | } |
1177 | | |
1178 | 4.90k | if (unicode_strings) { |
1179 | | /* UTF-16 string; must be 2-byte aligned */ |
1180 | 2.14k | if ((string_offset & 1) != 0) |
1181 | 1.27k | string_offset++; |
1182 | 2.14k | } |
1183 | 4.90k | tf = proto_tree_add_item_ret_string(ntlmssp_tree, string_hf, tvb, |
1184 | 4.90k | string_offset, string_length, |
1185 | 4.90k | unicode_strings ? ENC_UTF_16|ENC_LITTLE_ENDIAN : ENC_ASCII|ENC_NA, |
1186 | 4.90k | allocator, (const uint8_t**)stringp); |
1187 | 4.90k | tree = proto_item_add_subtree(tf, ett_ntlmssp_string); |
1188 | 4.90k | proto_tree_add_uint(tree, hf_ntlmssp_string_len, |
1189 | 4.90k | tvb, offset, 2, string_length); |
1190 | 4.90k | offset += 2; |
1191 | 4.90k | proto_tree_add_uint(tree, hf_ntlmssp_string_maxlen, |
1192 | 4.90k | tvb, offset, 2, string_maxlen); |
1193 | 4.90k | offset += 2; |
1194 | 4.90k | proto_tree_add_uint(tree, hf_ntlmssp_string_offset, |
1195 | 4.90k | tvb, offset, 4, string_offset); |
1196 | 4.90k | offset += 4; |
1197 | | |
1198 | 4.90k | *end = string_offset + string_length; |
1199 | 4.90k | return offset; |
1200 | 11.7k | } |
1201 | | |
1202 | | /* dissect a generic blob - header area contains: |
1203 | | two byte len |
1204 | | two byte maxlen |
1205 | | four byte offset of blob in data area |
1206 | | The function returns the offset at the end of the blob header, |
1207 | | but the 'end' parameter returns the offset of the end of the blob itself |
1208 | | */ |
1209 | | static int |
1210 | | dissect_ntlmssp_blob (tvbuff_t *tvb, packet_info *pinfo, |
1211 | | proto_tree *ntlmssp_tree, int offset, |
1212 | | int blob_hf, int *end, ntlmssp_blob *result) |
1213 | 9.92k | { |
1214 | 9.92k | proto_item *tf = NULL; |
1215 | 9.92k | proto_tree *tree = NULL; |
1216 | 9.92k | uint16_t blob_length = tvb_get_letohs(tvb, offset); |
1217 | 9.92k | uint16_t blob_maxlen = tvb_get_letohs(tvb, offset+2); |
1218 | 9.92k | uint32_t blob_offset = tvb_get_letohl(tvb, offset+4); |
1219 | | |
1220 | 9.92k | if (blob_offset > (unsigned)INT_MAX) { |
1221 | 212 | THROW(ReportedBoundsError); |
1222 | 212 | } |
1223 | | |
1224 | 9.92k | if (0 == blob_length) { |
1225 | 5.42k | *end = (blob_offset > ((unsigned)offset)+8 ? blob_offset : ((unsigned)offset)+8); |
1226 | 5.42k | proto_tree_add_bytes_format_value(ntlmssp_tree, blob_hf, tvb, offset, 8, NULL, "Empty"); |
1227 | 5.42k | result->length = 0; |
1228 | 5.42k | result->contents = NULL; |
1229 | 5.42k | return offset+8; |
1230 | 5.42k | } |
1231 | | |
1232 | 4.49k | if (ntlmssp_tree) { |
1233 | 4.18k | tf = proto_tree_add_item (ntlmssp_tree, blob_hf, tvb, |
1234 | 4.18k | blob_offset, blob_length, ENC_NA); |
1235 | 4.18k | tree = proto_item_add_subtree(tf, ett_ntlmssp_blob); |
1236 | 4.18k | } |
1237 | 4.49k | proto_tree_add_uint(tree, hf_ntlmssp_blob_len, |
1238 | 4.49k | tvb, offset, 2, blob_length); |
1239 | 4.49k | offset += 2; |
1240 | 4.49k | proto_tree_add_uint(tree, hf_ntlmssp_blob_maxlen, |
1241 | 4.49k | tvb, offset, 2, blob_maxlen); |
1242 | 4.49k | offset += 2; |
1243 | 4.49k | proto_tree_add_uint(tree, hf_ntlmssp_blob_offset, |
1244 | 4.49k | tvb, offset, 4, blob_offset); |
1245 | 4.49k | offset += 4; |
1246 | | |
1247 | 4.49k | *end = blob_offset + blob_length; |
1248 | | |
1249 | 4.49k | if (blob_length < NTLMSSP_BLOB_MAX_SIZE) { |
1250 | 3.99k | result->length = blob_length; |
1251 | 3.99k | result->contents = (uint8_t *)tvb_memdup(wmem_file_scope(), tvb, blob_offset, blob_length); |
1252 | 3.99k | } else { |
1253 | 505 | expert_add_info_format(pinfo, tf, &ei_ntlmssp_v2_key_too_long, |
1254 | 505 | "NTLM v2 key is %d bytes long, too big for our %d buffer", blob_length, NTLMSSP_BLOB_MAX_SIZE); |
1255 | 505 | result->length = 0; |
1256 | 505 | result->contents = NULL; |
1257 | 505 | } |
1258 | | |
1259 | | /* |
1260 | | * XXX - for LmChallengeResponse (hf_ntlmssp_auth_lmresponse), should |
1261 | | * we have a field for both Response (2.2.2.3 "LM_RESPONSE" and |
1262 | | * 2.2.2.4 "LMv2_RESPONSE" in [MS-NLMP]) in addition to ClientChallenge |
1263 | | * (only in 2.2.2.4 "LMv2_RESPONSE")? |
1264 | | * |
1265 | | * XXX - should we also dissect the fields of an NtChallengeResponse |
1266 | | * (hf_ntlmssp_auth_ntresponse)? |
1267 | | * |
1268 | | * XXX - should we warn if the blob is too *small*? |
1269 | | */ |
1270 | 4.49k | if (blob_hf == hf_ntlmssp_auth_lmresponse) { |
1271 | | /* |
1272 | | * LMChallengeResponse. It's either 2.2.2.3 "LM_RESPONSE" or |
1273 | | * 2.2.2.4 "LMv2_RESPONSE", in [MS-NLMP]. |
1274 | | * |
1275 | | * XXX - should we have a field for Response as well as |
1276 | | * ClientChallenge? |
1277 | | */ |
1278 | 1.15k | if (tvb_memeql(tvb, blob_offset+8, (const uint8_t*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", NTLMSSP_KEY_LEN) == 0) { |
1279 | | /* |
1280 | | * LMv2_RESPONSE. |
1281 | | * |
1282 | | * XXX - according to 2.2.2.4 "LMv2_RESPONSE", the ClientChallenge |
1283 | | * is at an offset of 16 from the beginning of the blob; it's not |
1284 | | * at the beginning of the blob. |
1285 | | */ |
1286 | 210 | proto_tree_add_item (ntlmssp_tree, |
1287 | 210 | hf_ntlmssp_ntlm_client_challenge, |
1288 | 210 | tvb, blob_offset, 8, ENC_NA); |
1289 | 210 | } |
1290 | 3.34k | } else if (blob_hf == hf_ntlmssp_auth_ntresponse) { |
1291 | | /* |
1292 | | * NTChallengeResponse. It's either 2.2.2.6 "NTLM v1 Response: |
1293 | | * NTLM_RESPONSE" or 2.2.2.8 "NTLM v2 Response: NTLMv2_RESPONSE" |
1294 | | * in [MS-NLMP]. |
1295 | | */ |
1296 | 1.36k | if (blob_length > 24) { |
1297 | | /* |
1298 | | * > 24 bytes, so it's "NTLM v2 Response: NTLMv2_RESPONSE". |
1299 | | * An NTLMv2_RESPONSE has 16 bytes of Response followed |
1300 | | * by an NTLMv2_CLIENT_CHALLENGE; an NTLMv2_CLIENT_CHALLENGE |
1301 | | * is at least 32 bytes, so an NTLMv2_RESPONSE is at least |
1302 | | * 48 bytes long. |
1303 | | */ |
1304 | 991 | dissect_ntlmv2_response(tvb, pinfo, tree, blob_offset, blob_length); |
1305 | 991 | } |
1306 | 1.36k | } |
1307 | | |
1308 | 4.49k | return offset; |
1309 | 9.92k | } |
1310 | | |
1311 | | static int * const ntlmssp_negotiate_flags[] = { |
1312 | | &hf_ntlmssp_negotiate_flags_80000000, |
1313 | | &hf_ntlmssp_negotiate_flags_40000000, |
1314 | | &hf_ntlmssp_negotiate_flags_20000000, |
1315 | | &hf_ntlmssp_negotiate_flags_10000000, |
1316 | | &hf_ntlmssp_negotiate_flags_8000000, |
1317 | | &hf_ntlmssp_negotiate_flags_4000000, |
1318 | | &hf_ntlmssp_negotiate_flags_2000000, |
1319 | | &hf_ntlmssp_negotiate_flags_1000000, |
1320 | | &hf_ntlmssp_negotiate_flags_800000, |
1321 | | &hf_ntlmssp_negotiate_flags_400000, |
1322 | | &hf_ntlmssp_negotiate_flags_200000, |
1323 | | &hf_ntlmssp_negotiate_flags_100000, |
1324 | | &hf_ntlmssp_negotiate_flags_80000, |
1325 | | &hf_ntlmssp_negotiate_flags_40000, |
1326 | | &hf_ntlmssp_negotiate_flags_20000, |
1327 | | &hf_ntlmssp_negotiate_flags_10000, |
1328 | | &hf_ntlmssp_negotiate_flags_8000, |
1329 | | &hf_ntlmssp_negotiate_flags_4000, |
1330 | | &hf_ntlmssp_negotiate_flags_2000, |
1331 | | &hf_ntlmssp_negotiate_flags_1000, |
1332 | | &hf_ntlmssp_negotiate_flags_800, |
1333 | | &hf_ntlmssp_negotiate_flags_400, |
1334 | | &hf_ntlmssp_negotiate_flags_200, |
1335 | | &hf_ntlmssp_negotiate_flags_100, |
1336 | | &hf_ntlmssp_negotiate_flags_80, |
1337 | | &hf_ntlmssp_negotiate_flags_40, |
1338 | | &hf_ntlmssp_negotiate_flags_20, |
1339 | | &hf_ntlmssp_negotiate_flags_10, |
1340 | | &hf_ntlmssp_negotiate_flags_08, |
1341 | | &hf_ntlmssp_negotiate_flags_04, |
1342 | | &hf_ntlmssp_negotiate_flags_02, |
1343 | | &hf_ntlmssp_negotiate_flags_01, |
1344 | | NULL |
1345 | | }; |
1346 | | |
1347 | | /* Dissect "version" */ |
1348 | | |
1349 | | /* From MS-NLMP: |
1350 | | 0 Major Version Number 1 byte |
1351 | | 1 Minor Version Number 1 byte |
1352 | | 2 Build Number short(LE) |
1353 | | 3 (Reserved) 3 bytes |
1354 | | 4 NTLM Current Revision 1 byte |
1355 | | */ |
1356 | | |
1357 | | static int |
1358 | | dissect_ntlmssp_version(tvbuff_t *tvb, int offset, |
1359 | | proto_tree *ntlmssp_tree) |
1360 | 996 | { |
1361 | 996 | if (ntlmssp_tree) { |
1362 | 996 | proto_item *tf; |
1363 | 996 | proto_tree *version_tree; |
1364 | 996 | tf = proto_tree_add_none_format(ntlmssp_tree, hf_ntlmssp_version, tvb, offset, 8, |
1365 | 996 | "Version %u.%u (Build %u); NTLM Current Revision %u", |
1366 | 996 | tvb_get_uint8(tvb, offset), |
1367 | 996 | tvb_get_uint8(tvb, offset+1), |
1368 | 996 | tvb_get_letohs(tvb, offset+2), |
1369 | 996 | tvb_get_uint8(tvb, offset+7)); |
1370 | 996 | version_tree = proto_item_add_subtree (tf, ett_ntlmssp_version); |
1371 | 996 | proto_tree_add_item(version_tree, hf_ntlmssp_version_major , tvb, offset , 1, ENC_LITTLE_ENDIAN); |
1372 | 996 | proto_tree_add_item(version_tree, hf_ntlmssp_version_minor , tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
1373 | 996 | proto_tree_add_item(version_tree, hf_ntlmssp_version_build_number , tvb, offset+2, 2, ENC_LITTLE_ENDIAN); |
1374 | 996 | proto_tree_add_item(version_tree, hf_ntlmssp_version_ntlm_current_revision, tvb, offset+7, 1, ENC_LITTLE_ENDIAN); |
1375 | 996 | } |
1376 | 996 | return offset+8; |
1377 | 996 | } |
1378 | | |
1379 | | /* Dissect a NTLM response. This is documented at |
1380 | | http://ubiqx.org/cifs/SMB.html#SMB.8, para 2.8.5.3 */ |
1381 | | |
1382 | | /* Attribute types */ |
1383 | | /* |
1384 | | * XXX - the davenport.sourceforge.net document cited above says that a |
1385 | | * type of 5 has been seen, "apparently containing the 'parent' DNS |
1386 | | * domain for servers in subdomains". |
1387 | | * XXX: MS-NLMP info is newer than Davenport info; |
1388 | | * The attribute type list and the attribute names below are |
1389 | | * based upon MS-NLMP. |
1390 | | */ |
1391 | | |
1392 | 11.3k | #define NTLM_TARGET_INFO_END 0x0000 |
1393 | 466 | #define NTLM_TARGET_INFO_NB_COMPUTER_NAME 0x0001 |
1394 | 853 | #define NTLM_TARGET_INFO_NB_DOMAIN_NAME 0x0002 |
1395 | 1.22k | #define NTLM_TARGET_INFO_DNS_COMPUTER_NAME 0x0003 |
1396 | 1.64k | #define NTLM_TARGET_INFO_DNS_DOMAIN_NAME 0x0004 |
1397 | 2.46k | #define NTLM_TARGET_INFO_DNS_TREE_NAME 0x0005 |
1398 | 80 | #define NTLM_TARGET_INFO_FLAGS 0x0006 |
1399 | 515 | #define NTLM_TARGET_INFO_TIMESTAMP 0x0007 |
1400 | 302 | #define NTLM_TARGET_INFO_RESTRICTIONS 0x0008 |
1401 | 2.76k | #define NTLM_TARGET_INFO_TARGET_NAME 0x0009 |
1402 | 431 | #define NTLM_TARGET_INFO_CHANNEL_BINDINGS 0x000A |
1403 | | |
1404 | | static const value_string ntlm_name_types[] = { |
1405 | | { NTLM_TARGET_INFO_END, "End of list" }, |
1406 | | { NTLM_TARGET_INFO_NB_COMPUTER_NAME, "NetBIOS computer name" }, |
1407 | | { NTLM_TARGET_INFO_NB_DOMAIN_NAME, "NetBIOS domain name" }, |
1408 | | { NTLM_TARGET_INFO_DNS_COMPUTER_NAME, "DNS computer name" }, |
1409 | | { NTLM_TARGET_INFO_DNS_DOMAIN_NAME, "DNS domain name" }, |
1410 | | { NTLM_TARGET_INFO_DNS_TREE_NAME, "DNS tree name" }, |
1411 | | { NTLM_TARGET_INFO_FLAGS, "Flags" }, |
1412 | | { NTLM_TARGET_INFO_TIMESTAMP, "Timestamp" }, |
1413 | | { NTLM_TARGET_INFO_RESTRICTIONS, "Restrictions" }, |
1414 | | { NTLM_TARGET_INFO_TARGET_NAME, "Target Name"}, |
1415 | | { NTLM_TARGET_INFO_CHANNEL_BINDINGS, "Channel Bindings"}, |
1416 | | { 0, NULL } |
1417 | | }; |
1418 | | static value_string_ext ntlm_name_types_ext = VALUE_STRING_EXT_INIT(ntlm_name_types); |
1419 | | |
1420 | | /* The following *must* match the order of the list of attribute types */ |
1421 | | /* Assumption: values in the list are a sequence starting with 0 and */ |
1422 | | /* with no gaps allowing a direct access of the array by attribute type */ |
1423 | | static int *ntlmssp_hf_challenge_target_info_hf_ptr_array[] = { |
1424 | | &hf_ntlmssp_challenge_target_info_end, |
1425 | | &hf_ntlmssp_challenge_target_info_nb_computer_name, |
1426 | | &hf_ntlmssp_challenge_target_info_nb_domain_name, |
1427 | | &hf_ntlmssp_challenge_target_info_dns_computer_name, |
1428 | | &hf_ntlmssp_challenge_target_info_dns_domain_name, |
1429 | | &hf_ntlmssp_challenge_target_info_dns_tree_name, |
1430 | | &hf_ntlmssp_challenge_target_info_flags, |
1431 | | &hf_ntlmssp_challenge_target_info_timestamp, |
1432 | | &hf_ntlmssp_challenge_target_info_restrictions, |
1433 | | &hf_ntlmssp_challenge_target_info_target_name, |
1434 | | &hf_ntlmssp_challenge_target_info_channel_bindings |
1435 | | }; |
1436 | | |
1437 | | static int *ntlmssp_hf_ntlmv2_response_hf_ptr_array[] = { |
1438 | | &hf_ntlmssp_ntlmv2_response_end, |
1439 | | &hf_ntlmssp_ntlmv2_response_nb_computer_name, |
1440 | | &hf_ntlmssp_ntlmv2_response_nb_domain_name, |
1441 | | &hf_ntlmssp_ntlmv2_response_dns_computer_name, |
1442 | | &hf_ntlmssp_ntlmv2_response_dns_domain_name, |
1443 | | &hf_ntlmssp_ntlmv2_response_dns_tree_name, |
1444 | | &hf_ntlmssp_ntlmv2_response_flags, |
1445 | | &hf_ntlmssp_ntlmv2_response_timestamp, |
1446 | | &hf_ntlmssp_ntlmv2_response_restrictions, |
1447 | | &hf_ntlmssp_ntlmv2_response_target_name, |
1448 | | &hf_ntlmssp_ntlmv2_response_channel_bindings |
1449 | | }; |
1450 | | |
1451 | | typedef struct _tif { |
1452 | | int *ett; |
1453 | | int *hf_item_type; |
1454 | | int *hf_item_length; |
1455 | | int **hf_attr_array_p; |
1456 | | } tif_t; |
1457 | | |
1458 | | static tif_t ntlmssp_challenge_target_info_tif = { |
1459 | | &ett_ntlmssp_challenge_target_info_item, |
1460 | | &hf_ntlmssp_challenge_target_info_item_type, |
1461 | | &hf_ntlmssp_challenge_target_info_item_len, |
1462 | | ntlmssp_hf_challenge_target_info_hf_ptr_array |
1463 | | }; |
1464 | | |
1465 | | static tif_t ntlmssp_ntlmv2_response_tif = { |
1466 | | &ett_ntlmssp_ntlmv2_response_item, |
1467 | | &hf_ntlmssp_ntlmv2_response_item_type, |
1468 | | &hf_ntlmssp_ntlmv2_response_item_len, |
1469 | | ntlmssp_hf_ntlmv2_response_hf_ptr_array |
1470 | | }; |
1471 | | |
1472 | | /** See [MS-NLMP] 2.2.2.1 */ |
1473 | | static int |
1474 | | dissect_ntlmssp_target_info_list(tvbuff_t *_tvb, packet_info *pinfo, proto_tree *tree, |
1475 | | uint32_t target_info_offset, uint16_t target_info_length, |
1476 | | tif_t *tif_p) |
1477 | 2.17k | { |
1478 | 2.17k | tvbuff_t *tvb = tvb_new_subset_length(_tvb, target_info_offset, target_info_length); |
1479 | 2.17k | uint32_t item_offset = 0; |
1480 | 2.17k | uint16_t item_type = ~0; |
1481 | | |
1482 | | /* Now enumerate through the individual items in the list */ |
1483 | | |
1484 | 12.2k | while (tvb_bytes_exist(tvb, item_offset, 4) && (item_type != NTLM_TARGET_INFO_END)) { |
1485 | 11.0k | proto_item *target_info_tf; |
1486 | 11.0k | proto_tree *target_info_tree; |
1487 | 11.0k | uint32_t content_offset; |
1488 | 11.0k | uint16_t content_length; |
1489 | 11.0k | uint32_t type_offset; |
1490 | 11.0k | uint32_t len_offset; |
1491 | 11.0k | uint32_t item_length; |
1492 | 11.0k | const uint8_t *text = NULL; |
1493 | | |
1494 | 11.0k | int **hf_array_p = tif_p->hf_attr_array_p; |
1495 | | |
1496 | | /* Content type */ |
1497 | 11.0k | type_offset = item_offset; |
1498 | 11.0k | item_type = tvb_get_letohs(tvb, type_offset); |
1499 | | |
1500 | | /* Content length */ |
1501 | 11.0k | len_offset = type_offset + 2; |
1502 | 11.0k | content_length = tvb_get_letohs(tvb, len_offset); |
1503 | | |
1504 | | /* Content value */ |
1505 | 11.0k | content_offset = len_offset + 2; |
1506 | 11.0k | item_length = content_length + 4; |
1507 | | |
1508 | 11.0k | if (!tvb_bytes_exist(tvb, item_offset, item_length)) { |
1509 | | /* Mark the current item and all the rest as invalid */ |
1510 | 869 | proto_tree_add_expert(tree, pinfo, &ei_ntlmssp_target_info_invalid, |
1511 | 869 | tvb, item_offset, target_info_length - item_offset); |
1512 | 869 | return target_info_offset + target_info_length; |
1513 | 869 | } |
1514 | | |
1515 | 10.1k | target_info_tree = proto_tree_add_subtree_format(tree, tvb, item_offset, item_length, *tif_p->ett, &target_info_tf, |
1516 | 10.1k | "Attribute: %s", val_to_str_ext(pinfo->pool, item_type, &ntlm_name_types_ext, "Unknown (%d)")); |
1517 | | |
1518 | 10.1k | proto_tree_add_item (target_info_tree, *tif_p->hf_item_type, tvb, type_offset, 2, ENC_LITTLE_ENDIAN); |
1519 | 10.1k | proto_tree_add_item (target_info_tree, *tif_p->hf_item_length, tvb, len_offset, 2, ENC_LITTLE_ENDIAN); |
1520 | | |
1521 | 10.1k | if (content_length > 0) { |
1522 | 8.15k | switch (item_type) { |
1523 | 466 | case NTLM_TARGET_INFO_NB_COMPUTER_NAME: |
1524 | 853 | case NTLM_TARGET_INFO_NB_DOMAIN_NAME: |
1525 | 1.22k | case NTLM_TARGET_INFO_DNS_COMPUTER_NAME: |
1526 | 1.64k | case NTLM_TARGET_INFO_DNS_DOMAIN_NAME: |
1527 | 2.46k | case NTLM_TARGET_INFO_DNS_TREE_NAME: |
1528 | 2.76k | case NTLM_TARGET_INFO_TARGET_NAME: |
1529 | 2.76k | proto_tree_add_item_ret_string(target_info_tree, *hf_array_p[item_type], tvb, content_offset, content_length, ENC_UTF_16|ENC_LITTLE_ENDIAN, pinfo->pool, &text); |
1530 | 2.76k | proto_item_append_text(target_info_tf, ": %s", text); |
1531 | 2.76k | break; |
1532 | | |
1533 | 80 | case NTLM_TARGET_INFO_FLAGS: |
1534 | 80 | proto_tree_add_item(target_info_tree, *hf_array_p[item_type], tvb, content_offset, content_length, ENC_LITTLE_ENDIAN); |
1535 | 80 | break; |
1536 | | |
1537 | 515 | case NTLM_TARGET_INFO_TIMESTAMP: |
1538 | 515 | dissect_nttime(tvb, target_info_tree, content_offset, *hf_array_p[item_type], ENC_LITTLE_ENDIAN); |
1539 | 515 | break; |
1540 | | |
1541 | 302 | case NTLM_TARGET_INFO_RESTRICTIONS: |
1542 | 431 | case NTLM_TARGET_INFO_CHANNEL_BINDINGS: |
1543 | 431 | proto_tree_add_item(target_info_tree, *hf_array_p[item_type], tvb, content_offset, content_length, ENC_NA); |
1544 | 431 | break; |
1545 | | |
1546 | 4.36k | default: |
1547 | 4.36k | proto_tree_add_expert(target_info_tree, pinfo, &ei_ntlmssp_target_info_attr, |
1548 | 4.36k | tvb, content_offset, content_length); |
1549 | 4.36k | break; |
1550 | 8.15k | } |
1551 | 8.15k | } |
1552 | | |
1553 | 10.0k | item_offset += item_length; |
1554 | 10.0k | } |
1555 | | |
1556 | 1.19k | return target_info_offset + item_offset; |
1557 | 2.17k | } |
1558 | | |
1559 | | /** See [MS-NLMP] 3.3.2 */ |
1560 | | int |
1561 | | dissect_ntlmv2_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int len) |
1562 | 991 | { |
1563 | 991 | proto_item *ntlmv2_item = NULL; |
1564 | 991 | proto_tree *ntlmv2_tree = NULL; |
1565 | 991 | const int orig_offset = offset; |
1566 | | |
1567 | | /* XXX - make sure we don't go past len? */ |
1568 | 991 | if (tree) { |
1569 | 991 | ntlmv2_item = proto_tree_add_item( |
1570 | 991 | tree, hf_ntlmssp_ntlmv2_response, tvb, |
1571 | 991 | offset, len, ENC_NA); |
1572 | 991 | ntlmv2_tree = proto_item_add_subtree( |
1573 | 991 | ntlmv2_item, ett_ntlmssp_ntlmv2_response); |
1574 | 991 | } |
1575 | | |
1576 | 991 | proto_tree_add_item( |
1577 | 991 | ntlmv2_tree, hf_ntlmssp_ntlmv2_response_ntproofstr, tvb, |
1578 | 991 | offset, 16, ENC_NA); |
1579 | 991 | offset += 16; |
1580 | | |
1581 | 991 | proto_tree_add_item(ntlmv2_tree, hf_ntlmssp_ntlmv2_response_rversion, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1582 | 991 | offset += 1; |
1583 | | |
1584 | 991 | proto_tree_add_item(ntlmv2_tree, hf_ntlmssp_ntlmv2_response_hirversion, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1585 | 991 | offset += 1; |
1586 | | |
1587 | 991 | proto_tree_add_item(ntlmv2_tree, hf_ntlmssp_ntlmv2_response_z, tvb, offset, 6, ENC_NA); |
1588 | 991 | offset += 6; |
1589 | | |
1590 | 991 | dissect_nttime( |
1591 | 991 | tvb, ntlmv2_tree, offset, hf_ntlmssp_ntlmv2_response_time, ENC_LITTLE_ENDIAN); |
1592 | 991 | offset += 8; |
1593 | 991 | proto_tree_add_item( |
1594 | 991 | ntlmv2_tree, hf_ntlmssp_ntlmv2_response_chal, tvb, |
1595 | 991 | offset, 8, ENC_NA); |
1596 | 991 | offset += 8; |
1597 | | |
1598 | 991 | proto_tree_add_item(ntlmv2_tree, hf_ntlmssp_ntlmv2_response_z, tvb, offset, 4, ENC_NA); |
1599 | 991 | offset += 4; |
1600 | | |
1601 | 991 | offset = dissect_ntlmssp_target_info_list(tvb, pinfo, ntlmv2_tree, offset, len - (offset - orig_offset), &ntlmssp_ntlmv2_response_tif); |
1602 | | |
1603 | 991 | if ((offset - orig_offset) < len) { |
1604 | 215 | proto_tree_add_item(ntlmv2_tree, hf_ntlmssp_ntlmv2_response_pad, tvb, offset, len - (offset - orig_offset), ENC_NA); |
1605 | 215 | } |
1606 | | |
1607 | 991 | return offset+len; |
1608 | 991 | } |
1609 | | |
1610 | | /* tapping into ntlmssph not yet implemented */ |
1611 | | static int |
1612 | | dissect_ntlmssp_negotiate (tvbuff_t *tvb, packet_info* pinfo, int offset, proto_tree *ntlmssp_tree, ntlmssp_header_t *ntlmssph _U_) |
1613 | 434 | { |
1614 | 434 | uint32_t negotiate_flags; |
1615 | 434 | int data_start; |
1616 | 434 | int data_end; |
1617 | 434 | int item_start; |
1618 | 434 | int item_end; |
1619 | | |
1620 | | /* NTLMSSP Negotiate Flags */ |
1621 | 434 | negotiate_flags = tvb_get_letohl (tvb, offset); |
1622 | 434 | proto_tree_add_bitmask(ntlmssp_tree, tvb, offset, hf_ntlmssp_negotiate_flags, ett_ntlmssp_negotiate_flags, ntlmssp_negotiate_flags, ENC_LITTLE_ENDIAN); |
1623 | 434 | offset += 4; |
1624 | | |
1625 | | /* MS-NLMP 2.2.1.1: DomainName MUST be encoded using the OEM character set. |
1626 | | * WorkstationName MUST be encoded using the OEM character set. |
1627 | | * The Davenport document ("The Type 1 Message") agrees, noting that these |
1628 | | * "are always in OEM format, even if Unicode is supported by the client." |
1629 | | * |
1630 | | * Presumably this is because this is the initial message, so while the |
1631 | | * client is offering Unicode support, it has not been negotiated yet. |
1632 | | * Note the flags are known as NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED |
1633 | | * and NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED. |
1634 | | */ |
1635 | | /* |
1636 | | * XXX - the davenport document says that these might not be |
1637 | | * sent at all, presumably meaning the length of the message |
1638 | | * isn't enough to contain them. |
1639 | | */ |
1640 | 434 | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, false, |
1641 | 434 | hf_ntlmssp_negotiate_domain, |
1642 | 434 | &data_start, &data_end, NULL); |
1643 | | |
1644 | 434 | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, false, |
1645 | 434 | hf_ntlmssp_negotiate_workstation, |
1646 | 434 | &item_start, &item_end, NULL); |
1647 | 434 | data_start = MIN(data_start, item_start); |
1648 | 434 | data_end = MAX(data_end, item_end); |
1649 | | |
1650 | | /* If there are more bytes before the data block dissect a version field |
1651 | | if NTLMSSP_NEGOTIATE_VERSION is set in the flags (see MS-NLMP) */ |
1652 | 434 | if (offset < data_start) { |
1653 | 245 | if (negotiate_flags & NTLMSSP_NEGOTIATE_VERSION) |
1654 | 152 | dissect_ntlmssp_version(tvb, offset, ntlmssp_tree); |
1655 | 245 | } |
1656 | 434 | return data_end; |
1657 | 434 | } |
1658 | | |
1659 | | |
1660 | | static int |
1661 | | dissect_ntlmssp_challenge_target_info_blob (packet_info *pinfo, tvbuff_t *tvb, int offset, |
1662 | | proto_tree *ntlmssp_tree, |
1663 | | int *end) |
1664 | 1.70k | { |
1665 | 1.70k | uint16_t challenge_target_info_length = tvb_get_letohs(tvb, offset); |
1666 | 1.70k | uint16_t challenge_target_info_maxlen = tvb_get_letohs(tvb, offset+2); |
1667 | 1.70k | uint32_t challenge_target_info_offset = tvb_get_letohl(tvb, offset+4); |
1668 | 1.70k | proto_item *tf = NULL; |
1669 | 1.70k | proto_tree *challenge_target_info_tree = NULL; |
1670 | | |
1671 | | /* the target info list is just a blob */ |
1672 | 1.70k | if (0 == challenge_target_info_length) { |
1673 | 87 | *end = (challenge_target_info_offset > ((unsigned)offset)+8 ? challenge_target_info_offset : ((unsigned)offset)+8); |
1674 | 87 | proto_tree_add_none_format(ntlmssp_tree, hf_ntlmssp_challenge_target_info, tvb, offset, 8, |
1675 | 87 | "Target Info List: Empty"); |
1676 | 87 | return offset+8; |
1677 | 87 | } |
1678 | | |
1679 | 1.61k | if (ntlmssp_tree) { |
1680 | 1.56k | tf = proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_challenge_target_info, tvb, |
1681 | 1.56k | challenge_target_info_offset, challenge_target_info_length, ENC_NA); |
1682 | 1.56k | challenge_target_info_tree = proto_item_add_subtree(tf, ett_ntlmssp_challenge_target_info); |
1683 | 1.56k | } |
1684 | 1.61k | proto_tree_add_uint(challenge_target_info_tree, hf_ntlmssp_challenge_target_info_len, |
1685 | 1.61k | tvb, offset, 2, challenge_target_info_length); |
1686 | 1.61k | offset += 2; |
1687 | 1.61k | proto_tree_add_uint(challenge_target_info_tree, hf_ntlmssp_challenge_target_info_maxlen, |
1688 | 1.61k | tvb, offset, 2, challenge_target_info_maxlen); |
1689 | 1.61k | offset += 2; |
1690 | 1.61k | proto_tree_add_uint(challenge_target_info_tree, hf_ntlmssp_challenge_target_info_offset, |
1691 | 1.61k | tvb, offset, 4, challenge_target_info_offset); |
1692 | 1.61k | offset += 4; |
1693 | | |
1694 | 1.61k | dissect_ntlmssp_target_info_list(tvb, pinfo, challenge_target_info_tree, |
1695 | 1.61k | challenge_target_info_offset, challenge_target_info_length, |
1696 | 1.61k | &ntlmssp_challenge_target_info_tif); |
1697 | | |
1698 | 1.61k | *end = challenge_target_info_offset + challenge_target_info_length; |
1699 | 1.61k | return offset; |
1700 | 1.70k | } |
1701 | | |
1702 | | /* tapping into ntlmssph not yet implemented */ |
1703 | | static int |
1704 | | dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset, |
1705 | | proto_tree *ntlmssp_tree, ntlmssp_header_t *ntlmssph _U_) |
1706 | 2.54k | { |
1707 | 2.54k | uint32_t negotiate_flags = 0; |
1708 | 2.54k | int item_start, item_end; |
1709 | 2.54k | int data_start, data_end; /* MIN and MAX seen */ |
1710 | 2.54k | uint8_t clientkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key for client */ |
1711 | 2.54k | uint8_t serverkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key for server*/ |
1712 | 2.54k | ntlmssp_info *conv_ntlmssp_info = NULL; |
1713 | 2.54k | conversation_t *conversation; |
1714 | 2.54k | bool unicode_strings = false; |
1715 | 2.54k | uint8_t tmp[8]; |
1716 | 2.54k | uint8_t sspkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key */ |
1717 | 2.54k | int ssp_key_len; /* Either 8 or 16 (40 bit or 128) */ |
1718 | | |
1719 | | /* |
1720 | | * Use the negotiate flags in this message, if they're present |
1721 | | * in the capture, to determine whether strings are Unicode or |
1722 | | * not. |
1723 | | * |
1724 | | * offset points at TargetNameFields; skip past it. |
1725 | | */ |
1726 | 2.54k | if (tvb_bytes_exist(tvb, offset+8, 4)) { |
1727 | 2.30k | negotiate_flags = tvb_get_letohl (tvb, offset+8); |
1728 | 2.30k | if (negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE) |
1729 | 656 | unicode_strings = true; |
1730 | 2.30k | } |
1731 | | |
1732 | | /* Target name */ |
1733 | | /* |
1734 | | * XXX - the davenport document (and MS-NLMP) calls this "Target Name", |
1735 | | * presumably because non-domain targets are supported. |
1736 | | * XXX - Original name "domain" changed to "target_name" to match MS-NLMP |
1737 | | */ |
1738 | 2.54k | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, unicode_strings, |
1739 | 2.54k | hf_ntlmssp_challenge_target_name, |
1740 | 2.54k | &item_start, &item_end, NULL); |
1741 | 2.54k | data_start = item_start; |
1742 | 2.54k | data_end = item_end; |
1743 | | |
1744 | | /* NTLMSSP Negotiate Flags */ |
1745 | 2.54k | proto_tree_add_bitmask(ntlmssp_tree, tvb, offset, hf_ntlmssp_negotiate_flags, ett_ntlmssp_negotiate_flags, ntlmssp_negotiate_flags, ENC_LITTLE_ENDIAN); |
1746 | 2.54k | offset += 4; |
1747 | | |
1748 | | /* NTLMSSP NT Lan Manager Challenge */ |
1749 | 2.54k | proto_tree_add_item (ntlmssp_tree, |
1750 | 2.54k | hf_ntlmssp_ntlm_server_challenge, |
1751 | 2.54k | tvb, offset, 8, ENC_NA); |
1752 | | |
1753 | | /* |
1754 | | * Store the flags and the RC4 state information with the conversation, |
1755 | | * as they're needed in order to dissect subsequent messages. |
1756 | | */ |
1757 | 2.54k | conversation = find_or_create_conversation(pinfo); |
1758 | | |
1759 | 2.54k | tvb_memcpy(tvb, tmp, offset, 8); /* challenge */ |
1760 | | /* We can face more than one NTLM exchange over the same couple of IP and ports ...*/ |
1761 | 2.54k | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, proto_ntlmssp); |
1762 | | /* XXX: The following code is (re)executed every time a particular frame is dissected |
1763 | | * (in whatever order). Thus it seems to me that "multiple exchanges" might not be |
1764 | | * handled well depending on the order that frames are visited after the initial dissection. |
1765 | | */ |
1766 | 2.54k | if (!conv_ntlmssp_info || memcmp(tmp, conv_ntlmssp_info->server_challenge, 8) != 0) { |
1767 | 559 | conv_ntlmssp_info = wmem_new0(wmem_file_scope(), ntlmssp_info); |
1768 | 559 | wmem_register_callback(wmem_file_scope(), ntlmssp_sessions_destroy_cb, conv_ntlmssp_info); |
1769 | | /* Insert the flags into the conversation */ |
1770 | 559 | conv_ntlmssp_info->flags = negotiate_flags; |
1771 | 559 | conv_ntlmssp_info->saw_challenge = true; |
1772 | | /* Insert the RC4 state information into the conversation */ |
1773 | 559 | tvb_memcpy(tvb, conv_ntlmssp_info->server_challenge, offset, 8); |
1774 | | /* Between the challenge and the user provided password, we can build the |
1775 | | NTLMSSP key and initialize the cipher if we are not in EXTENDED SESSION SECURITY |
1776 | | in this case we need the client challenge as well*/ |
1777 | | /* BTW this is true just if we are in LM Authentication if not the logic is a bit different. |
1778 | | * Right now it's not very clear what is LM Authentication it __seems__ to be when |
1779 | | * NEGOTIATE NT ONLY is not set and NEGOTIATE EXTENDED SESSION SECURITY is not set as well*/ |
1780 | 559 | if (!(conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) |
1781 | 429 | { |
1782 | 429 | conv_ntlmssp_info->rc4_state_initialized = false; |
1783 | | /* XXX - Make sure there is 24 bytes for the key */ |
1784 | 429 | conv_ntlmssp_info->ntlm_response.contents = (uint8_t *)wmem_alloc0(wmem_file_scope(), 24); |
1785 | 429 | conv_ntlmssp_info->lm_response.contents = (uint8_t *)wmem_alloc0(wmem_file_scope(), 24); |
1786 | | |
1787 | 429 | create_ntlmssp_v1_key(conv_ntlmssp_info->server_challenge, |
1788 | 429 | NULL, sspkey, NULL, conv_ntlmssp_info->flags, |
1789 | 429 | conv_ntlmssp_info->ntlm_response.contents, |
1790 | 429 | conv_ntlmssp_info->lm_response.contents, |
1791 | 429 | ntlmssph, pinfo, ntlmssp_tree); |
1792 | 429 | if (memcmp(sspkey, gbl_zeros, NTLMSSP_KEY_LEN) != 0) { |
1793 | 0 | get_sealing_rc4key(sspkey, conv_ntlmssp_info->flags, &ssp_key_len, clientkey, serverkey); |
1794 | 0 | if (!gcry_cipher_open(&conv_ntlmssp_info->rc4_handle_client, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
1795 | 0 | if (gcry_cipher_setkey(conv_ntlmssp_info->rc4_handle_client, sspkey, ssp_key_len)) { |
1796 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_client); |
1797 | 0 | conv_ntlmssp_info->rc4_handle_client = NULL; |
1798 | 0 | } |
1799 | 0 | } |
1800 | 0 | if (!gcry_cipher_open(&conv_ntlmssp_info->rc4_handle_server, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
1801 | 0 | if (gcry_cipher_setkey(conv_ntlmssp_info->rc4_handle_server, sspkey, ssp_key_len)) { |
1802 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_server); |
1803 | 0 | conv_ntlmssp_info->rc4_handle_server = NULL; |
1804 | 0 | } |
1805 | 0 | } |
1806 | 0 | if (conv_ntlmssp_info->rc4_handle_client && conv_ntlmssp_info->rc4_handle_server) { |
1807 | 0 | conv_ntlmssp_info->server_dest_port = pinfo->destport; |
1808 | 0 | conv_ntlmssp_info->rc4_state_initialized = true; |
1809 | 0 | } |
1810 | 0 | } |
1811 | 429 | } |
1812 | 559 | conversation_add_proto_data(conversation, proto_ntlmssp, conv_ntlmssp_info); |
1813 | 559 | } |
1814 | 2.54k | offset += 8; |
1815 | | |
1816 | | /* If no more bytes (ie: no "reserved", ...) before start of data block, then return */ |
1817 | | /* XXX: According to Davenport "This form is seen in older Win9x-based systems" */ |
1818 | | /* Also: I've seen a capture with an HTTP CONNECT proxy-authentication */ |
1819 | | /* message wherein the challenge from the proxy has this form. */ |
1820 | 2.54k | if (offset >= data_start) { |
1821 | 136 | return data_end; |
1822 | 136 | } |
1823 | | |
1824 | | /* Reserved (function not completely known) */ |
1825 | | /* |
1826 | | * XXX - SSP key? The davenport document says |
1827 | | * |
1828 | | * The context field is typically populated when Negotiate Local |
1829 | | * Call is set. It contains an SSPI context handle, which allows |
1830 | | * the client to "short-circuit" authentication and effectively |
1831 | | * circumvent responding to the challenge. Physically, the context |
1832 | | * is two long values. This is covered in greater detail later, |
1833 | | * in the "Local Authentication" section. |
1834 | | * |
1835 | | * It also says that that information may be omitted. |
1836 | | */ |
1837 | 2.40k | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_reserved, |
1838 | 2.40k | tvb, offset, 8, ENC_NA); |
1839 | 2.40k | offset += 8; |
1840 | | |
1841 | | /* |
1842 | | * The presence or absence of this field is not obviously correlated |
1843 | | * with any flags in the previous NEGOTIATE message or in this |
1844 | | * message (other than the "Workstation Supplied" and "Domain |
1845 | | * Supplied" flags in the NEGOTIATE message, at least in the capture |
1846 | | * I've seen - but those also correlate with the presence of workstation |
1847 | | * and domain name fields, so it doesn't seem to make sense that they |
1848 | | * actually *indicate* whether the subsequent CHALLENGE has an |
1849 | | * address list). |
1850 | | */ |
1851 | 2.40k | if (offset < data_start) { |
1852 | 1.70k | offset = dissect_ntlmssp_challenge_target_info_blob(pinfo, tvb, offset, ntlmssp_tree, &item_end); |
1853 | | /* XXX: This code assumes that the address list in the data block */ |
1854 | | /* is always after the target name. Is this OK ? */ |
1855 | 1.70k | data_end = MAX(data_end, item_end); |
1856 | 1.70k | } |
1857 | | |
1858 | | /* If there are more bytes before the data block dissect a version field |
1859 | | if NTLMSSP_NEGOTIATE_VERSION is set in the flags (see MS-NLMP) */ |
1860 | 2.40k | if (offset < data_start) { |
1861 | 668 | if (negotiate_flags & NTLMSSP_NEGOTIATE_VERSION) |
1862 | 472 | offset = dissect_ntlmssp_version(tvb, offset, ntlmssp_tree); |
1863 | 668 | } |
1864 | | |
1865 | 2.40k | return MAX(offset, data_end); |
1866 | 2.54k | } |
1867 | | |
1868 | | static int |
1869 | | dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, |
1870 | | proto_tree *ntlmssp_tree, ntlmssp_header_t *ntlmssph) |
1871 | 4.19k | { |
1872 | 4.19k | int item_start, item_end; |
1873 | 4.19k | int data_start, data_end = 0; |
1874 | 4.19k | bool have_negotiate_flags = false; |
1875 | 4.19k | uint32_t negotiate_flags; |
1876 | 4.19k | uint8_t sspkey[NTLMSSP_KEY_LEN]; /* exported session key */ |
1877 | 4.19k | uint8_t clientkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key for client */ |
1878 | 4.19k | uint8_t serverkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key for server*/ |
1879 | 4.19k | uint8_t encryptedsessionkey[NTLMSSP_KEY_LEN] = {0}; |
1880 | 4.19k | ntlmssp_blob sessionblob; |
1881 | 4.19k | bool unicode_strings = false; |
1882 | 4.19k | ntlmssp_info *conv_ntlmssp_info; |
1883 | 4.19k | conversation_t *conversation; |
1884 | 4.19k | int ssp_key_len; |
1885 | | |
1886 | 4.19k | conv_ntlmssp_info = (ntlmssp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_CONV_INFO_KEY); |
1887 | 4.19k | if (conv_ntlmssp_info == NULL) { |
1888 | | /* |
1889 | | * There isn't any. Is there any from this conversation? If so, |
1890 | | * it means this is the first time we've dissected this frame, so |
1891 | | * we should give it flag info. |
1892 | | */ |
1893 | | /* XXX: Create conv_ntlmssp_info & etc if no previous CHALLENGE seen */ |
1894 | | /* so we'll have a place to store flags. */ |
1895 | | /* This is a bit brute-force but looks like it will be OK. */ |
1896 | 898 | conversation = find_or_create_conversation(pinfo); |
1897 | 898 | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, proto_ntlmssp); |
1898 | 898 | if (conv_ntlmssp_info == NULL) { |
1899 | 1 | conv_ntlmssp_info = wmem_new0(wmem_file_scope(), ntlmssp_info); |
1900 | 1 | wmem_register_callback(wmem_file_scope(), ntlmssp_sessions_destroy_cb, conv_ntlmssp_info); |
1901 | 1 | conversation_add_proto_data(conversation, proto_ntlmssp, conv_ntlmssp_info); |
1902 | 1 | } |
1903 | | /* XXX: The *conv_ntlmssp_info struct attached to the frame is the |
1904 | | same as the one attached to the conversation. That is: *both* point to |
1905 | | the exact same struct in memory. Is this what is indended ? */ |
1906 | 898 | p_add_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_CONV_INFO_KEY, conv_ntlmssp_info); |
1907 | 898 | } |
1908 | | |
1909 | | /* |
1910 | | * Get flag info from the original negotiate message, if any. |
1911 | | * This is because the flag information is sometimes missing from |
1912 | | * the AUTHENTICATE message, so we can't figure out whether |
1913 | | * strings are Unicode or not by looking at *our* flags. |
1914 | | * |
1915 | | * MS-NLMP says: |
1916 | | * |
1917 | | * In 2.2.1.1 NEGOTIATE_MESSAGE: |
1918 | | * |
1919 | | * NegotiateFlags (4 bytes): A NEGOTIATE structure that contains a set |
1920 | | * of flags, as defined in section 2.2.2.5. The client sets flags to |
1921 | | * indicate options it supports. |
1922 | | * |
1923 | | * In 2.2.1.2 CHALLENGE_MESSAGE: |
1924 | | * |
1925 | | * NegotiateFlags (4 bytes): A NEGOTIATE structure that contains a set |
1926 | | * of flags, as defined by section 2.2.2.5. The server sets flags to |
1927 | | * indicate options it supports or, if there has been a NEGOTIATE_MESSAGE |
1928 | | * (section 2.2.1.1), the choices it has made from the options offered |
1929 | | * by the client. |
1930 | | * |
1931 | | * In 2.2.1.3 AUTHENTICATE_MESSAGE: |
1932 | | * |
1933 | | * NegotiateFlags (4 bytes): In connectionless mode, a NEGOTIATE |
1934 | | * structure that contains a set of flags (section 2.2.2.5) and |
1935 | | * represents the conclusion of negotiation--the choices the client |
1936 | | * has made from the options the server offered in the CHALLENGE_MESSAGE. |
1937 | | * In connection-oriented mode, a NEGOTIATE structure that contains the |
1938 | | * set of bit flags (section 2.2.2.5) negotiated in the previous messages. |
1939 | | * |
1940 | | * As 1.3.1 NTLM Authentication Call Flow indicates, in connectionless |
1941 | | * mode, there's no NEGOTIATE_MESSAGE, just a CHALLENGE_MESSAGE and |
1942 | | * an AUTHENTICATE_MESSAGE. |
1943 | | * |
1944 | | * So, for connectionless mode, with no NEGOTIATE_MESSAGE, the flags |
1945 | | * that are the result of negotiation are in the AUTHENTICATE_MESSAGE; |
1946 | | * only at the time the AUTHENTICATE_MESSAGE is sent does the client |
1947 | | * know what the server is offering, so, at that point, it can indicate |
1948 | | * to the server which of those it supports, with the final result |
1949 | | * specifying the capabilities offered by the server that are also |
1950 | | * supported by the client. |
1951 | | * |
1952 | | * For connection-oriented mode, at the time of the CHALLENGE_MESSAGE, |
1953 | | * the server knows what capabilities the client supports, as those |
1954 | | * we specified in the NEGOTIATE_MESSAGE, so it returns the set of |
1955 | | * capabilities, from the set that the client supports, that it also |
1956 | | * supports, so the CHALLENGE_MESSAGE contains the final result. The |
1957 | | * AUTHENTICATE_MESSAGE "contains the set of bit flags ... negotiated |
1958 | | * in the previous messages", so it should contain the same set of |
1959 | | * bit flags that were in the CHALLENGE_MESSAGE. |
1960 | | * |
1961 | | * So we use the flags in this message, the AUTHENTICATE_MESSAGE, if |
1962 | | * they're present; if this is connectionless mode, the flags in the |
1963 | | * CHALLENGE_MESSAGE aren't sufficient, as they don't indicate what |
1964 | | * the client supports, and if this is connection-oriented mode, the |
1965 | | * flags here should match what's in the CHALLENGE_MESSAGE. |
1966 | | * |
1967 | | * The flags might be missing from this message; the message could |
1968 | | * have been cut short by the snapshot length, and even if it's not, |
1969 | | * some older protocol implementations omit it. If they're missing, |
1970 | | * we fall back on what's in the CHALLENGE_MESSAGE. |
1971 | | * |
1972 | | * XXX: I've seen a capture which does an HTTP CONNECT which: |
1973 | | * - has the NEGOTIATE & CHALLENGE messages in one TCP connection; |
1974 | | * - has the AUTHENTICATE message in a second TCP connection; |
1975 | | * (The authentication apparently succeeded). |
1976 | | * For that case, in order to get the flags from the CHALLENGE_MESSAGE, |
1977 | | * we'd somehow have to manage NTLMSSP exchanges that cross TCP |
1978 | | * connection boundaries. |
1979 | | * |
1980 | | * offset points at LmChallengeResponseFields; skip past |
1981 | | * LmChallengeResponseFields, NtChallengeResponseFields, |
1982 | | * DomainNameFields, UserNameFields, WorkstationFields, |
1983 | | * and EncryptedRandomSessionKeyFields. |
1984 | | */ |
1985 | 4.19k | if (tvb_bytes_exist(tvb, offset+8+8+8+8+8+8, 4)) { |
1986 | | /* |
1987 | | * See where the Lan Manager response's blob begins; |
1988 | | * the data area starts at, or before, that location. |
1989 | | */ |
1990 | 2.49k | data_start = tvb_get_letohl(tvb, offset+4); |
1991 | | |
1992 | | /* |
1993 | | * See where the NTLM response's blob begins; the data area |
1994 | | * starts at, or before, that location. |
1995 | | */ |
1996 | 2.49k | item_start = tvb_get_letohl(tvb, offset+8+4); |
1997 | 2.49k | data_start = MIN(data_start, item_start); |
1998 | | |
1999 | | /* |
2000 | | * See where the domain name's blob begins; the data area |
2001 | | * starts at, or before, that location. |
2002 | | */ |
2003 | 2.49k | item_start = tvb_get_letohl(tvb, offset+8+8+4); |
2004 | 2.49k | data_start = MIN(data_start, item_start); |
2005 | | |
2006 | | /* |
2007 | | * See where the user name's blob begins; the data area |
2008 | | * starts at, or before, that location. |
2009 | | */ |
2010 | 2.49k | item_start = tvb_get_letohl(tvb, offset+8+8+8+4); |
2011 | 2.49k | data_start = MIN(data_start, item_start); |
2012 | | |
2013 | | /* |
2014 | | * See where the host name's blob begins; the data area |
2015 | | * starts at, or before, that location. |
2016 | | */ |
2017 | 2.49k | item_start = tvb_get_letohl(tvb, offset+8+8+8+8+4); |
2018 | 2.49k | data_start = MIN(data_start, item_start); |
2019 | | |
2020 | | /* |
2021 | | * See if we have a session key and flags. |
2022 | | */ |
2023 | 2.49k | if (offset+8+8+8+8+8 < data_start) { |
2024 | | /* |
2025 | | * We have a session key and flags. |
2026 | | */ |
2027 | 873 | negotiate_flags = tvb_get_letohl (tvb, offset+8+8+8+8+8+8); |
2028 | 873 | have_negotiate_flags = true; |
2029 | 873 | if (negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE) |
2030 | 445 | unicode_strings = true; |
2031 | 873 | } |
2032 | 2.49k | } |
2033 | 4.19k | if (!have_negotiate_flags) { |
2034 | | /* |
2035 | | * The flags from this message aren't present; if we have the |
2036 | | * flags from the CHALLENGE message, use them. |
2037 | | */ |
2038 | 3.32k | if (conv_ntlmssp_info != NULL && conv_ntlmssp_info->saw_challenge) { |
2039 | 3.28k | if (conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_UNICODE) |
2040 | 914 | unicode_strings = true; |
2041 | 3.28k | } |
2042 | 3.32k | } |
2043 | | |
2044 | | /* |
2045 | | * Sometimes the session key and flags are missing. |
2046 | | * Sometimes the session key is present but the flags are missing. |
2047 | | * XXX Who stay so ? Reading spec I would rather say the opposite: flags are |
2048 | | * always present, session information are always there as well but sometime |
2049 | | * session information could be null (in case of no session) |
2050 | | * Sometimes they're both present. |
2051 | | * |
2052 | | * This does not correlate with any flags in the previous CHALLENGE |
2053 | | * message, and only correlates with "Negotiate Unicode", "Workstation |
2054 | | * Supplied", and "Domain Supplied" in the NEGOTIATE message - but |
2055 | | * those don't make sense as flags to use to determine this. |
2056 | | * |
2057 | | * So we check all of the descriptors to figure out where the data |
2058 | | * area begins, and if the session key or the flags would be in the |
2059 | | * middle of the data area, we assume the field in question is |
2060 | | * missing. |
2061 | | * |
2062 | | * XXX - Reading Davenport and MS-NLMP: as I see it the possibilities are: |
2063 | | * a. No session-key; no flags; no version ("Win9x") |
2064 | | * b. Session-key & flags. |
2065 | | * c. Session-key, flags & version. |
2066 | | * In cases b and c the session key may be "null". |
2067 | | * |
2068 | | */ |
2069 | | |
2070 | | /* Lan Manager response */ |
2071 | 4.19k | data_start = tvb_get_letohl(tvb, offset+4); |
2072 | 4.19k | offset = dissect_ntlmssp_blob(tvb, pinfo, ntlmssp_tree, offset, |
2073 | 4.19k | hf_ntlmssp_auth_lmresponse, |
2074 | 4.19k | &item_end, |
2075 | 4.19k | conv_ntlmssp_info == NULL ? NULL : |
2076 | 4.19k | &conv_ntlmssp_info->lm_response); |
2077 | 4.19k | data_end = MAX(data_end, item_end); |
2078 | | |
2079 | | /* NTLM response */ |
2080 | 4.19k | item_start = tvb_get_letohl(tvb, offset+4); |
2081 | 4.19k | offset = dissect_ntlmssp_blob(tvb, pinfo, ntlmssp_tree, offset, |
2082 | 4.19k | hf_ntlmssp_auth_ntresponse, |
2083 | 4.19k | &item_end, |
2084 | 4.19k | conv_ntlmssp_info == NULL ? NULL : |
2085 | 4.19k | &conv_ntlmssp_info->ntlm_response); |
2086 | 4.19k | data_start = MIN(data_start, item_start); |
2087 | 4.19k | data_end = MAX(data_end, item_end); |
2088 | | |
2089 | | /* domain name */ |
2090 | 4.19k | item_start = tvb_get_letohl(tvb, offset+4); |
2091 | 4.19k | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, |
2092 | 4.19k | unicode_strings, |
2093 | 4.19k | hf_ntlmssp_auth_domain, |
2094 | 4.19k | &item_start, &item_end, &(ntlmssph->domain_name)); |
2095 | | /*ntlmssph->domain_name_len = item_end-item_start;*/ |
2096 | 4.19k | data_start = MIN(data_start, item_start); |
2097 | 4.19k | data_end = MAX(data_end, item_end); |
2098 | | |
2099 | | /* user name */ |
2100 | 4.19k | item_start = tvb_get_letohl(tvb, offset+4); |
2101 | 4.19k | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, |
2102 | 4.19k | unicode_strings, |
2103 | 4.19k | hf_ntlmssp_auth_username, |
2104 | 4.19k | &item_start, &item_end, &(ntlmssph->acct_name)); |
2105 | | /*ntlmssph->acct_name_len = item_end-item_start;*/ |
2106 | 4.19k | data_start = MIN(data_start, item_start); |
2107 | 4.19k | data_end = MAX(data_end, item_end); |
2108 | | |
2109 | 4.19k | if (!ntlmssph->domain_name[0] && !ntlmssph->acct_name[0]) |
2110 | 1.09k | col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "User: anonymous"); |
2111 | 3.09k | else |
2112 | 3.09k | col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "User: %s\\%s", |
2113 | 3.09k | ntlmssph->domain_name, ntlmssph->acct_name); |
2114 | | |
2115 | | /* hostname */ |
2116 | 4.19k | item_start = tvb_get_letohl(tvb, offset+4); |
2117 | 4.19k | offset = dissect_ntlmssp_string(tvb, pinfo->pool, offset, ntlmssp_tree, |
2118 | 4.19k | unicode_strings, |
2119 | 4.19k | hf_ntlmssp_auth_hostname, |
2120 | 4.19k | &item_start, &item_end, &(ntlmssph->host_name)); |
2121 | 4.19k | data_start = MIN(data_start, item_start); |
2122 | 4.19k | data_end = MAX(data_end, item_end); |
2123 | | |
2124 | 4.19k | sessionblob.length = 0; |
2125 | 4.19k | if (offset < data_start) { |
2126 | | /* Session Key */ |
2127 | 1.99k | offset = dissect_ntlmssp_blob(tvb, pinfo, ntlmssp_tree, offset, |
2128 | 1.99k | hf_ntlmssp_auth_sesskey, |
2129 | 1.99k | &item_end, &sessionblob); |
2130 | 1.99k | data_end = MAX(data_end, item_end); |
2131 | 1.99k | } |
2132 | | |
2133 | 4.19k | if (offset < data_start) { |
2134 | | /* NTLMSSP Negotiate Flags */ |
2135 | 1.63k | negotiate_flags = tvb_get_letohl (tvb, offset); |
2136 | 1.63k | proto_tree_add_bitmask(ntlmssp_tree, tvb, offset, hf_ntlmssp_negotiate_flags, ett_ntlmssp_negotiate_flags, ntlmssp_negotiate_flags, ENC_LITTLE_ENDIAN); |
2137 | 1.63k | offset += 4; |
2138 | | |
2139 | | /* If no previous flags seen (ie: no previous CHALLENGE) use flags |
2140 | | from the AUTHENTICATE message). |
2141 | | Assumption: (flags == 0) means flags not previously seen */ |
2142 | 1.63k | if ((conv_ntlmssp_info != NULL) && (conv_ntlmssp_info->flags == 0)) { |
2143 | 5 | conv_ntlmssp_info->flags = negotiate_flags; |
2144 | 5 | } |
2145 | 1.63k | } else |
2146 | 2.56k | negotiate_flags = 0; |
2147 | | |
2148 | | /* If there are more bytes before the data block dissect a version field |
2149 | | if NTLMSSP_NEGOTIATE_VERSION is set in the flags (see MS-NLMP) */ |
2150 | 4.19k | if (offset < data_start) { |
2151 | 1.10k | if (negotiate_flags & NTLMSSP_NEGOTIATE_VERSION) { |
2152 | 372 | offset = dissect_ntlmssp_version(tvb, offset, ntlmssp_tree); |
2153 | 730 | } else { |
2154 | 730 | proto_tree_add_item(ntlmssp_tree, hf_ntlmssp_ntlmv2_response_z, tvb, offset, 8, ENC_NA); |
2155 | 730 | offset += 8; |
2156 | 730 | } |
2157 | 1.10k | } |
2158 | | |
2159 | | /* If there are still more bytes before the data block dissect an MIC (message integrity_code) field */ |
2160 | | /* (See MS-NLMP) */ |
2161 | 4.19k | if (offset < data_start) { |
2162 | 155 | proto_tree_add_item(ntlmssp_tree, hf_ntlmssp_message_integrity_code, tvb, offset, 16, ENC_NA); |
2163 | 155 | offset += 16; |
2164 | 155 | } |
2165 | | |
2166 | 4.19k | if (sessionblob.length > NTLMSSP_KEY_LEN) { |
2167 | 136 | expert_add_info_format(pinfo, NULL, &ei_ntlmssp_blob_len_too_long, "Session blob length too long: %u", sessionblob.length); |
2168 | 4.05k | } else if (sessionblob.length != 0) { |
2169 | | /* XXX - Is it a problem if sessionblob.length < NTLMSSP_KEY_LEN ? */ |
2170 | 1.29k | memcpy(encryptedsessionkey, sessionblob.contents, sessionblob.length); |
2171 | | /* Try to attach to an existing conversation if not then it's useless to try to do so |
2172 | | * because we are missing important information (ie. server challenge) |
2173 | | */ |
2174 | 1.29k | if (conv_ntlmssp_info) { |
2175 | | /* If we are in EXTENDED SESSION SECURITY then we can now initialize cipher */ |
2176 | 1.29k | if ((conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) |
2177 | 279 | { |
2178 | 279 | if (conv_ntlmssp_info->rc4_state_initialized) { |
2179 | | /* XXX - Do we really need to reinitialize the cipher contexts? */ |
2180 | 182 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_server); |
2181 | 182 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_client); |
2182 | 182 | } |
2183 | 279 | conv_ntlmssp_info->rc4_state_initialized = false; |
2184 | 279 | ntlmssp_create_session_key(pinfo, |
2185 | 279 | ntlmssp_tree, |
2186 | 279 | ntlmssph, |
2187 | 279 | conv_ntlmssp_info->flags, |
2188 | 279 | conv_ntlmssp_info->server_challenge, |
2189 | 279 | encryptedsessionkey, |
2190 | 279 | &conv_ntlmssp_info->ntlm_response, |
2191 | 279 | &conv_ntlmssp_info->lm_response); |
2192 | | /* ssp is the exported session key */ |
2193 | 279 | memcpy(sspkey, ntlmssph->session_key, NTLMSSP_KEY_LEN); |
2194 | 279 | if (memcmp(sspkey, gbl_zeros, NTLMSSP_KEY_LEN) != 0) { |
2195 | 196 | get_sealing_rc4key(sspkey, conv_ntlmssp_info->flags, &ssp_key_len, clientkey, serverkey); |
2196 | 196 | get_signing_key((uint8_t*)&conv_ntlmssp_info->sign_key_server, (uint8_t*)&conv_ntlmssp_info->sign_key_client, sspkey, ssp_key_len); |
2197 | 196 | if (!gcry_cipher_open (&conv_ntlmssp_info->rc4_handle_server, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
2198 | 196 | if (gcry_cipher_setkey(conv_ntlmssp_info->rc4_handle_server, serverkey, ssp_key_len)) { |
2199 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_server); |
2200 | 0 | conv_ntlmssp_info->rc4_handle_server = NULL; |
2201 | 0 | } |
2202 | 196 | } |
2203 | 196 | if (!gcry_cipher_open (&conv_ntlmssp_info->rc4_handle_client, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
2204 | 196 | if (gcry_cipher_setkey(conv_ntlmssp_info->rc4_handle_client, clientkey, ssp_key_len)) { |
2205 | 0 | gcry_cipher_close(conv_ntlmssp_info->rc4_handle_client); |
2206 | 0 | conv_ntlmssp_info->rc4_handle_client = NULL; |
2207 | 0 | } |
2208 | 196 | } |
2209 | 196 | if (conv_ntlmssp_info->rc4_handle_server && conv_ntlmssp_info->rc4_handle_client) { |
2210 | 196 | conv_ntlmssp_info->server_dest_port = pinfo->destport; |
2211 | 196 | conv_ntlmssp_info->rc4_state_initialized = true; |
2212 | 196 | } |
2213 | 196 | } |
2214 | 279 | } |
2215 | 1.29k | } |
2216 | 1.29k | } |
2217 | 4.19k | return MAX(offset, data_end); |
2218 | 4.19k | } |
2219 | | |
2220 | | static uint8_t* |
2221 | | get_sign_key(packet_info *pinfo, int cryptpeer) |
2222 | 1 | { |
2223 | 1 | conversation_t *conversation; |
2224 | 1 | ntlmssp_info *conv_ntlmssp_info; |
2225 | | |
2226 | 1 | conversation = find_conversation_pinfo(pinfo, 0); |
2227 | 1 | if (conversation == NULL) { |
2228 | | /* We don't have a conversation. In this case, stop processing |
2229 | | because we do not have enough info to decrypt the payload */ |
2230 | 0 | return NULL; |
2231 | 0 | } |
2232 | 1 | else { |
2233 | | /* We have a conversation, check for encryption state */ |
2234 | 1 | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, |
2235 | 1 | proto_ntlmssp); |
2236 | 1 | if (conv_ntlmssp_info == NULL) { |
2237 | | /* No encryption state tied to the conversation. Therefore, we |
2238 | | cannot decrypt the payload */ |
2239 | 0 | return NULL; |
2240 | 0 | } |
2241 | 1 | else { |
2242 | | /* We have the encryption state in the conversation. So return the |
2243 | | crypt state tied to the requested peer |
2244 | | */ |
2245 | 1 | if (cryptpeer == 1) { |
2246 | 1 | return (uint8_t*)&conv_ntlmssp_info->sign_key_client; |
2247 | 1 | } else { |
2248 | 0 | return (uint8_t*)&conv_ntlmssp_info->sign_key_server; |
2249 | 0 | } |
2250 | 1 | } |
2251 | 1 | } |
2252 | 1 | } |
2253 | | |
2254 | | /* |
2255 | | * Get the encryption state tied to this conversation. cryptpeer indicates |
2256 | | * whether to retrieve the client key (1) or the server key (0) |
2257 | | */ |
2258 | | static gcry_cipher_hd_t |
2259 | | get_encrypted_state(packet_info *pinfo, int cryptpeer) |
2260 | 4 | { |
2261 | 4 | conversation_t *conversation; |
2262 | 4 | ntlmssp_info *conv_ntlmssp_info; |
2263 | | |
2264 | 4 | conversation = find_conversation_pinfo(pinfo, 0); |
2265 | 4 | if (conversation == NULL) { |
2266 | | /* We don't have a conversation. In this case, stop processing |
2267 | | because we do not have enough info to decrypt the payload */ |
2268 | 0 | return NULL; |
2269 | 0 | } |
2270 | 4 | else { |
2271 | | /* We have a conversation, check for encryption state */ |
2272 | 4 | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, |
2273 | 4 | proto_ntlmssp); |
2274 | 4 | if (conv_ntlmssp_info == NULL) { |
2275 | | /* No encryption state tied to the conversation. Therefore, we |
2276 | | cannot decrypt the payload */ |
2277 | 0 | return NULL; |
2278 | 0 | } |
2279 | 4 | else { |
2280 | | /* We have the encryption state in the conversation. So return the |
2281 | | crypt state tied to the requested peer |
2282 | | */ |
2283 | 4 | if (cryptpeer == 1) { |
2284 | 2 | return conv_ntlmssp_info->rc4_handle_client; |
2285 | 2 | } else { |
2286 | 2 | return conv_ntlmssp_info->rc4_handle_server; |
2287 | 2 | } |
2288 | 4 | } |
2289 | 4 | } |
2290 | 4 | } |
2291 | | |
2292 | | static tvbuff_t* |
2293 | | decrypt_data_payload(tvbuff_t *tvb, int offset, uint32_t encrypted_block_length, |
2294 | | packet_info *pinfo, proto_tree *tree _U_, void *key); |
2295 | | static void |
2296 | | store_verifier(tvbuff_t *tvb, int offset, uint32_t encrypted_block_length, packet_info *pinfo); |
2297 | | |
2298 | | static void |
2299 | | decrypt_verifier(tvbuff_t *tvb, packet_info *pinfo); |
2300 | | |
2301 | | static int |
2302 | | dissect_ntlmssp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
2303 | 20 | { |
2304 | 20 | volatile int offset = 0; |
2305 | 20 | proto_tree *volatile ntlmssp_tree = NULL; |
2306 | 20 | proto_item *tf = NULL; |
2307 | 20 | uint32_t length; |
2308 | 20 | uint32_t encrypted_block_length; |
2309 | 20 | uint8_t key[NTLMSSP_KEY_LEN]; |
2310 | | /* the magic ntlm is the identifier of a NTLMSSP packet that's 00 00 00 01 */ |
2311 | 20 | uint32_t ntlm_magic_size = 4; |
2312 | 20 | uint32_t ntlm_signature_size = 8; |
2313 | 20 | uint32_t ntlm_seq_size = 4; |
2314 | | |
2315 | 20 | length = tvb_captured_length (tvb); |
2316 | | /* signature + seq + real payload */ |
2317 | 20 | encrypted_block_length = length - ntlm_magic_size; |
2318 | | |
2319 | 20 | if (encrypted_block_length < (ntlm_signature_size + ntlm_seq_size)) { |
2320 | | /* Don't know why this would happen, but if it does, don't even bother |
2321 | | attempting decryption/dissection */ |
2322 | 0 | return offset + length; |
2323 | 0 | } |
2324 | | |
2325 | | /* Setup a new tree for the NTLMSSP payload */ |
2326 | 20 | if (tree) { |
2327 | 20 | tf = proto_tree_add_item (tree, |
2328 | 20 | hf_ntlmssp_verf, |
2329 | 20 | tvb, offset, -1, ENC_NA); |
2330 | | |
2331 | 20 | ntlmssp_tree = proto_item_add_subtree (tf, |
2332 | 20 | ett_ntlmssp); |
2333 | 20 | } |
2334 | | |
2335 | | /* |
2336 | | * Catch the ReportedBoundsError exception; the stuff we've been |
2337 | | * handed doesn't necessarily run to the end of the packet, it's |
2338 | | * an item inside a packet, so if it happens to be malformed (or |
2339 | | * we, or a dissector we call, has a bug), so that an exception |
2340 | | * is thrown, we want to report the error, but return and let |
2341 | | * our caller dissect the rest of the packet. |
2342 | | * |
2343 | | * If it gets a BoundsError, we can stop, as there's nothing more |
2344 | | * in the packet after our blob to see, so we just re-throw the |
2345 | | * exception. |
2346 | | */ |
2347 | 20 | TRY { |
2348 | | /* Version number */ |
2349 | 20 | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_vers, |
2350 | 20 | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
2351 | 20 | offset += 4; |
2352 | | |
2353 | | /* Encrypted body */ |
2354 | 20 | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_body, |
2355 | 20 | tvb, offset, ntlm_signature_size + ntlm_seq_size, ENC_NA); |
2356 | 20 | memset(key, 0, sizeof(key)); |
2357 | 20 | tvb_memcpy(tvb, key, offset, ntlm_signature_size + ntlm_seq_size); |
2358 | | /* Try to decrypt */ |
2359 | 20 | decrypt_data_payload (tvb, offset+(ntlm_signature_size + ntlm_seq_size), encrypted_block_length-(ntlm_signature_size + ntlm_seq_size), pinfo, ntlmssp_tree, key); |
2360 | 20 | store_verifier (tvb, offset, ntlm_signature_size + ntlm_seq_size, pinfo); |
2361 | 20 | decrypt_verifier (tvb, pinfo); |
2362 | | /* let's try to hook ourselves here */ |
2363 | | |
2364 | 20 | offset += 12; |
2365 | 20 | } CATCH_NONFATAL_ERRORS { |
2366 | 0 | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
2367 | 20 | } ENDTRY; |
2368 | | |
2369 | 20 | return offset; |
2370 | 20 | } |
2371 | | |
2372 | | static tvbuff_t* |
2373 | | decrypt_data_payload(tvbuff_t *tvb, int offset, uint32_t encrypted_block_length, |
2374 | | packet_info *pinfo, proto_tree *tree _U_, void *key) |
2375 | 20 | { |
2376 | 20 | tvbuff_t *decr_tvb; /* Used to display decrypted buffer */ |
2377 | 20 | ntlmssp_packet_info *packet_ntlmssp_info; |
2378 | 20 | ntlmssp_packet_info *stored_packet_ntlmssp_info = NULL; |
2379 | | |
2380 | | /* Check to see if we already have state for this packet */ |
2381 | 20 | packet_ntlmssp_info = (ntlmssp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_PACKET_INFO_KEY); |
2382 | 20 | if (packet_ntlmssp_info == NULL) { |
2383 | | /* We don't have any packet state, so create one */ |
2384 | 9 | packet_ntlmssp_info = wmem_new0(wmem_file_scope(), ntlmssp_packet_info); |
2385 | 9 | p_add_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_PACKET_INFO_KEY, packet_ntlmssp_info); |
2386 | 9 | } |
2387 | 20 | if (!packet_ntlmssp_info->payload_decrypted) { |
2388 | 15 | conversation_t *conversation; |
2389 | 15 | ntlmssp_info *conv_ntlmssp_info; |
2390 | | |
2391 | | /* Pull the challenge info from the conversation */ |
2392 | 15 | conversation = find_conversation_pinfo(pinfo, 0); |
2393 | 15 | if (conversation == NULL) { |
2394 | | /* There is no conversation, thus no encryption state */ |
2395 | 0 | return NULL; |
2396 | 0 | } |
2397 | | |
2398 | 15 | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, |
2399 | 15 | proto_ntlmssp); |
2400 | 15 | if (conv_ntlmssp_info == NULL) { |
2401 | | /* There is no NTLMSSP state tied to the conversation */ |
2402 | 0 | return NULL; |
2403 | 0 | } |
2404 | 15 | if (!conv_ntlmssp_info->rc4_state_initialized) { |
2405 | | /* The crypto sybsystem is not initialized. This means that either |
2406 | | the conversation did not include a challenge, or that we do not have the right password */ |
2407 | 14 | return NULL; |
2408 | 14 | } |
2409 | 1 | if (key != NULL) { |
2410 | 1 | stored_packet_ntlmssp_info = (ntlmssp_packet_info *)g_hash_table_lookup(hash_packet, key); |
2411 | 1 | } |
2412 | 1 | if (stored_packet_ntlmssp_info != NULL && stored_packet_ntlmssp_info->payload_decrypted == true) { |
2413 | | /* Mat TBD (stderr, "Found a already decrypted packet\n");*/ |
2414 | 0 | memcpy(packet_ntlmssp_info, stored_packet_ntlmssp_info, sizeof(ntlmssp_packet_info)); |
2415 | | /* Mat TBD ws_log_buffer(packet_ntlmssp_info->decrypted_payload, encrypted_block_length, "Data");*/ |
2416 | 0 | } |
2417 | 1 | else { |
2418 | 1 | gcry_cipher_hd_t rc4_handle; |
2419 | 1 | gcry_cipher_hd_t rc4_handle_peer; |
2420 | | |
2421 | | /* Get the pair of RC4 state structures. One is used for to decrypt the |
2422 | | payload. The other is used to re-encrypt the payload to represent |
2423 | | the peer */ |
2424 | 1 | if (conv_ntlmssp_info->server_dest_port == pinfo->destport) { |
2425 | | /* client */ |
2426 | 1 | rc4_handle = get_encrypted_state(pinfo, 1); |
2427 | 1 | rc4_handle_peer = get_encrypted_state(pinfo, 0); |
2428 | 1 | } else { |
2429 | | /* server */ |
2430 | 0 | rc4_handle = get_encrypted_state(pinfo, 0); |
2431 | 0 | rc4_handle_peer = get_encrypted_state(pinfo, 1); |
2432 | 0 | } |
2433 | | |
2434 | 1 | if (rc4_handle == NULL) { |
2435 | | /* There is no encryption state, so we cannot decrypt */ |
2436 | 0 | return NULL; |
2437 | 0 | } |
2438 | | |
2439 | | /* Store the decrypted contents in the packet state struct |
2440 | | (of course at this point, they aren't decrypted yet) */ |
2441 | 1 | packet_ntlmssp_info->decrypted_payload = (uint8_t *)tvb_memdup(wmem_file_scope(), tvb, offset, |
2442 | 1 | encrypted_block_length); |
2443 | 1 | packet_ntlmssp_info->payload_len = encrypted_block_length; |
2444 | 1 | decrypted_payloads = g_slist_prepend(decrypted_payloads, |
2445 | 1 | packet_ntlmssp_info->decrypted_payload); |
2446 | 1 | if (key != NULL) { |
2447 | 1 | uint8_t *perm_key = g_new(uint8_t, NTLMSSP_KEY_LEN); |
2448 | 1 | memcpy(perm_key, key, NTLMSSP_KEY_LEN); |
2449 | 1 | g_hash_table_insert(hash_packet, perm_key, packet_ntlmssp_info); |
2450 | 1 | } |
2451 | | |
2452 | | /* Do the decryption of the payload */ |
2453 | 1 | gcry_cipher_decrypt(rc4_handle, packet_ntlmssp_info->decrypted_payload, encrypted_block_length, NULL, 0); |
2454 | | |
2455 | | /* decrypt the verifier */ |
2456 | | /*ws_log_buffer(packet_ntlmssp_info->decrypted_payload, encrypted_block_length, "data");*/ |
2457 | | /* We setup a temporary buffer so we can re-encrypt the payload after |
2458 | | decryption. This is to update the opposite peer's RC4 state |
2459 | | it's useful when we have only one key for both conversation |
2460 | | in case of KEY_EXCH we have independent key so this is not needed*/ |
2461 | 1 | if (!(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) { |
2462 | 0 | uint8_t *peer_block; |
2463 | 0 | peer_block = (uint8_t *)wmem_memdup(pinfo->pool, packet_ntlmssp_info->decrypted_payload, encrypted_block_length); |
2464 | 0 | gcry_cipher_decrypt(rc4_handle_peer, peer_block, encrypted_block_length, NULL, 0); |
2465 | 0 | } |
2466 | | |
2467 | 1 | packet_ntlmssp_info->payload_decrypted = true; |
2468 | 1 | } |
2469 | 1 | } |
2470 | | |
2471 | | /* Show the decrypted buffer in a new window */ |
2472 | 6 | decr_tvb = tvb_new_child_real_data(tvb, packet_ntlmssp_info->decrypted_payload, |
2473 | 6 | encrypted_block_length, |
2474 | 6 | encrypted_block_length); |
2475 | | |
2476 | 6 | add_new_data_source(pinfo, decr_tvb, |
2477 | 6 | "Decrypted data"); |
2478 | 6 | return decr_tvb; |
2479 | 20 | } |
2480 | | |
2481 | | static int |
2482 | | dissect_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
2483 | 7.40k | { |
2484 | 7.40k | volatile int offset = 0; |
2485 | 7.40k | proto_tree *volatile ntlmssp_tree = NULL; |
2486 | 7.40k | proto_item *tf, *type_item; |
2487 | 7.40k | ntlmssp_header_t *ntlmssph; |
2488 | | |
2489 | | /* Check if it is a signing signature */ |
2490 | 7.40k | if (tvb_bytes_exist(tvb, offset, 16) && |
2491 | 7.21k | tvb_reported_length_remaining(tvb, offset) == 16 && |
2492 | 96 | tvb_get_uint8(tvb, offset) == 0x01) |
2493 | 0 | { |
2494 | 0 | tvbuff_t *verf_tvb = tvb_new_subset_length(tvb, offset, 16); |
2495 | 0 | offset += dissect_ntlmssp_verf(verf_tvb, pinfo, tree, NULL); |
2496 | 0 | return offset; |
2497 | 0 | } |
2498 | | |
2499 | 7.40k | ntlmssph = wmem_new(pinfo->pool, ntlmssp_header_t); |
2500 | 7.40k | ntlmssph->type = 0; |
2501 | 7.40k | ntlmssph->domain_name = NULL; |
2502 | 7.40k | ntlmssph->acct_name = NULL; |
2503 | 7.40k | ntlmssph->host_name = NULL; |
2504 | 7.40k | memset(ntlmssph->session_key, 0, NTLMSSP_KEY_LEN); |
2505 | | |
2506 | | /* Setup a new tree for the NTLMSSP payload */ |
2507 | 7.40k | tf = proto_tree_add_item (tree, |
2508 | 7.40k | proto_ntlmssp, |
2509 | 7.40k | tvb, offset, -1, ENC_NA); |
2510 | | |
2511 | 7.40k | ntlmssp_tree = proto_item_add_subtree (tf, ett_ntlmssp); |
2512 | | |
2513 | | /* |
2514 | | * Catch the ReportedBoundsError exception; the stuff we've been |
2515 | | * handed doesn't necessarily run to the end of the packet, it's |
2516 | | * an item inside a packet, so if it happens to be malformed (or |
2517 | | * we, or a dissector we call, has a bug), so that an exception |
2518 | | * is thrown, we want to report the error, but return and let |
2519 | | * our caller dissect the rest of the packet. |
2520 | | * |
2521 | | * If it gets a BoundsError, we can stop, as there's nothing more |
2522 | | * in the packet after our blob to see, so we just re-throw the |
2523 | | * exception. |
2524 | | */ |
2525 | 7.40k | TRY { |
2526 | | /* NTLMSSP constant */ |
2527 | 7.40k | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_auth, |
2528 | 7.40k | tvb, offset, 8, ENC_ASCII); |
2529 | 7.40k | offset += 8; |
2530 | | |
2531 | | /* NTLMSSP Message Type */ |
2532 | 7.40k | type_item = proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_message_type, |
2533 | 7.40k | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
2534 | 7.40k | ntlmssph->type = tvb_get_letohl (tvb, offset); |
2535 | 7.40k | offset += 4; |
2536 | | |
2537 | 7.40k | col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", |
2538 | 7.40k | val_to_str_const(ntlmssph->type, |
2539 | 7.40k | ntlmssp_message_types, |
2540 | 7.40k | "Unknown NTLMSSP message type")); |
2541 | | |
2542 | | /* Call the appropriate dissector based on the Message Type */ |
2543 | 7.40k | switch (ntlmssph->type) { |
2544 | | |
2545 | 434 | case NTLMSSP_NEGOTIATE: |
2546 | 434 | dissect_ntlmssp_negotiate (tvb, pinfo, offset, ntlmssp_tree, ntlmssph); |
2547 | 434 | break; |
2548 | | |
2549 | 2.54k | case NTLMSSP_CHALLENGE: |
2550 | 2.54k | dissect_ntlmssp_challenge (tvb, pinfo, offset, ntlmssp_tree, ntlmssph); |
2551 | 2.54k | break; |
2552 | | |
2553 | 4.19k | case NTLMSSP_AUTH: |
2554 | 4.19k | dissect_ntlmssp_auth (tvb, pinfo, offset, ntlmssp_tree, ntlmssph); |
2555 | 4.19k | break; |
2556 | | |
2557 | 174 | default: |
2558 | | /* Unrecognized message type */ |
2559 | 174 | expert_add_info(pinfo, type_item, &ei_ntlmssp_message_type); |
2560 | 174 | break; |
2561 | 7.40k | } |
2562 | 7.40k | } CATCH_NONFATAL_ERRORS { |
2563 | | |
2564 | 4.67k | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
2565 | 4.67k | } ENDTRY; |
2566 | | |
2567 | 2.73k | tap_queue_packet(ntlmssp_tap, pinfo, ntlmssph); |
2568 | 2.73k | return tvb_captured_length(tvb); |
2569 | 7.40k | } |
2570 | | |
2571 | | static void |
2572 | | store_verifier(tvbuff_t *tvb, int offset, uint32_t encrypted_block_length, packet_info *pinfo) |
2573 | 20 | { |
2574 | 20 | ntlmssp_packet_info *packet_ntlmssp_info; |
2575 | | |
2576 | 20 | packet_ntlmssp_info = (ntlmssp_packet_info*)p_get_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_PACKET_INFO_KEY); |
2577 | 20 | if (packet_ntlmssp_info == NULL) { |
2578 | | /* We don't have any packet state, so create one */ |
2579 | 0 | packet_ntlmssp_info = wmem_new0(wmem_file_scope(), ntlmssp_packet_info); |
2580 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_PACKET_INFO_KEY, packet_ntlmssp_info); |
2581 | 0 | } |
2582 | | |
2583 | 20 | if (!packet_ntlmssp_info->verifier_decrypted) { |
2584 | | /* Store all necessary info for later decryption */ |
2585 | 15 | packet_ntlmssp_info->verifier_offset = offset; |
2586 | 15 | packet_ntlmssp_info->verifier_block_length = encrypted_block_length; |
2587 | | /* Setup the buffer to decrypt to */ |
2588 | 15 | tvb_memcpy(tvb, packet_ntlmssp_info->verifier, |
2589 | 15 | offset, MIN(encrypted_block_length, sizeof(packet_ntlmssp_info->verifier))); |
2590 | 15 | } |
2591 | 20 | } |
2592 | | |
2593 | | /* |
2594 | | * See page 45 of "DCE/RPC over SMB" by Luke Kenneth Casson Leighton. |
2595 | | */ |
2596 | | static void |
2597 | | decrypt_verifier(tvbuff_t *tvb, packet_info *pinfo) |
2598 | 20 | { |
2599 | 20 | proto_tree *decr_tree; |
2600 | 20 | conversation_t *conversation; |
2601 | 20 | uint8_t* sign_key; |
2602 | 20 | gcry_cipher_hd_t rc4_handle; |
2603 | 20 | gcry_cipher_hd_t rc4_handle_peer; |
2604 | 20 | tvbuff_t *decr_tvb; /* Used to display decrypted buffer */ |
2605 | 20 | uint8_t *peer_block; |
2606 | 20 | uint8_t *check_buf; |
2607 | 20 | uint8_t calculated_md5[NTLMSSP_KEY_LEN]; |
2608 | 20 | ntlmssp_info *conv_ntlmssp_info; |
2609 | 20 | ntlmssp_packet_info *packet_ntlmssp_info; |
2610 | 20 | int decrypted_offset = 0; |
2611 | 20 | int sequence = 0; |
2612 | | |
2613 | 20 | packet_ntlmssp_info = (ntlmssp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ntlmssp, NTLMSSP_PACKET_INFO_KEY); |
2614 | 20 | if (packet_ntlmssp_info == NULL) { |
2615 | | /* We don't have data for this packet */ |
2616 | 0 | return; |
2617 | 0 | } |
2618 | 20 | conversation = find_conversation_pinfo(pinfo, 0); |
2619 | 20 | if (conversation == NULL) { |
2620 | | /* There is no conversation, thus no encryption state */ |
2621 | 0 | return; |
2622 | 0 | } |
2623 | 20 | conv_ntlmssp_info = (ntlmssp_info *)conversation_get_proto_data(conversation, |
2624 | 20 | proto_ntlmssp); |
2625 | 20 | if (conv_ntlmssp_info == NULL) { |
2626 | | /* There is no NTLMSSP state tied to the conversation */ |
2627 | 0 | return; |
2628 | 0 | } |
2629 | | |
2630 | 20 | if (!packet_ntlmssp_info->verifier_decrypted) { |
2631 | 15 | if (!conv_ntlmssp_info->rc4_state_initialized) { |
2632 | | /* The crypto subsystem is not initialized. This means that either |
2633 | | the conversation did not include a challenge, or we are doing |
2634 | | something other than NTLMSSP v1 */ |
2635 | 14 | return; |
2636 | 14 | } |
2637 | 1 | if (conv_ntlmssp_info->server_dest_port == pinfo->destport) { |
2638 | | /* client talk to server */ |
2639 | 1 | rc4_handle = get_encrypted_state(pinfo, 1); |
2640 | 1 | sign_key = get_sign_key(pinfo, 1); |
2641 | 1 | rc4_handle_peer = get_encrypted_state(pinfo, 0); |
2642 | 1 | } else { |
2643 | 0 | rc4_handle = get_encrypted_state(pinfo, 0); |
2644 | 0 | sign_key = get_sign_key(pinfo, 0); |
2645 | 0 | rc4_handle_peer = get_encrypted_state(pinfo, 1); |
2646 | 0 | } |
2647 | | |
2648 | 1 | if (rc4_handle == NULL || rc4_handle_peer == NULL) { |
2649 | | /* There is no encryption state, so we cannot decrypt */ |
2650 | 0 | return; |
2651 | 0 | } |
2652 | | |
2653 | | /*if (!(NTLMSSP_NEGOTIATE_KEY_EXCH & packet_ntlmssp_info->flags)) {*/ |
2654 | 1 | if (conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) { |
2655 | 1 | if ((NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) { |
2656 | | /* The spec says that if we have a key exchange then we have the signature that is encrypted |
2657 | | * otherwise it's just a hmac_md5(keysign, concat(message, sequence))[0..7] |
2658 | | */ |
2659 | 1 | if (gcry_cipher_decrypt(rc4_handle, packet_ntlmssp_info->verifier, 8, NULL, 0)) { |
2660 | 0 | return; |
2661 | 0 | } |
2662 | 1 | } |
2663 | | /* |
2664 | | * Trying to check the HMAC MD5 of the message against the calculated one works great with LDAP payload but |
2665 | | * don't with DCE/RPC calls. |
2666 | | * TODO Some analysis needs to be done ... |
2667 | | */ |
2668 | 1 | if (sign_key != NULL) { |
2669 | 1 | check_buf = (uint8_t *)wmem_alloc(pinfo->pool, packet_ntlmssp_info->payload_len+4); |
2670 | 1 | tvb_memcpy(tvb, &sequence, packet_ntlmssp_info->verifier_offset+8, 4); |
2671 | 1 | memcpy(check_buf, &sequence, 4); |
2672 | 1 | memcpy(check_buf+4, packet_ntlmssp_info->decrypted_payload, packet_ntlmssp_info->payload_len); |
2673 | 1 | if (ws_hmac_buffer(GCRY_MD_MD5, calculated_md5, check_buf, (int)(packet_ntlmssp_info->payload_len+4), sign_key, NTLMSSP_KEY_LEN)) { |
2674 | 0 | return; |
2675 | 0 | } |
2676 | | /* |
2677 | | ws_log_buffer(packet_ntlmssp_info->verifier, 8, "HMAC from packet"); |
2678 | | ws_log_buffer(calculated_md5, 8, "HMAC"); |
2679 | | */ |
2680 | 1 | } |
2681 | 1 | } |
2682 | 0 | else { |
2683 | | /* The packet has a PAD then a checksum then a sequence and they are encoded in this order so we can decrypt all at once */ |
2684 | | /* Do the actual decryption of the verifier */ |
2685 | 0 | if (gcry_cipher_decrypt(rc4_handle, packet_ntlmssp_info->verifier, packet_ntlmssp_info->verifier_block_length, NULL, 0)) { |
2686 | 0 | return; |
2687 | 0 | } |
2688 | 0 | } |
2689 | | |
2690 | | |
2691 | | /* We setup a temporary buffer so we can re-encrypt the payload after |
2692 | | decryption. This is to update the opposite peer's RC4 state |
2693 | | This is not needed when we just have EXTENDED SESSION SECURITY because the signature is not encrypted |
2694 | | and it's also not needed when we have key exchange because server and client have independent keys */ |
2695 | 1 | if (!(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags) && !(NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY & conv_ntlmssp_info->flags)) { |
2696 | 0 | peer_block = (uint8_t *)wmem_memdup(pinfo->pool, packet_ntlmssp_info->verifier, packet_ntlmssp_info->verifier_block_length); |
2697 | 0 | if (gcry_cipher_decrypt(rc4_handle_peer, peer_block, packet_ntlmssp_info->verifier_block_length, NULL, 0)) { |
2698 | 0 | return; |
2699 | 0 | } |
2700 | 0 | } |
2701 | | |
2702 | | /* Mark the packet as decrypted so that subsequent attempts to dissect |
2703 | | the packet use the already decrypted payload instead of attempting |
2704 | | to decrypt again */ |
2705 | 1 | packet_ntlmssp_info->verifier_decrypted = true; |
2706 | 1 | } |
2707 | | |
2708 | | /* Show the decrypted buffer in a new window */ |
2709 | 6 | decr_tvb = tvb_new_child_real_data(tvb, packet_ntlmssp_info->verifier, |
2710 | 6 | packet_ntlmssp_info->verifier_block_length, |
2711 | 6 | packet_ntlmssp_info->verifier_block_length); |
2712 | 6 | add_new_data_source(pinfo, decr_tvb, |
2713 | 6 | "Decrypted NTLMSSP Verifier"); |
2714 | | |
2715 | | /* Show the decrypted payload in the tree */ |
2716 | 6 | decr_tree = proto_tree_add_subtree_format(NULL, decr_tvb, 0, -1, |
2717 | 6 | ett_ntlmssp, NULL, |
2718 | 6 | "Decrypted Verifier (%d byte%s)", |
2719 | 6 | packet_ntlmssp_info->verifier_block_length, |
2720 | 6 | plurality(packet_ntlmssp_info->verifier_block_length, "", "s")); |
2721 | | |
2722 | 6 | if (( conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) { |
2723 | 6 | proto_tree_add_item (decr_tree, hf_ntlmssp_verf_hmacmd5, |
2724 | 6 | decr_tvb, decrypted_offset, 8, ENC_NA); |
2725 | 6 | decrypted_offset += 8; |
2726 | | |
2727 | | /* Incrementing sequence number of DCE conversation */ |
2728 | 6 | proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence, |
2729 | 6 | decr_tvb, decrypted_offset, 4, ENC_NA); |
2730 | 6 | } |
2731 | 0 | else { |
2732 | | /* RANDOM PAD usually it's 0 */ |
2733 | 0 | proto_tree_add_item (decr_tree, hf_ntlmssp_verf_randompad, |
2734 | 0 | decr_tvb, decrypted_offset, 4, ENC_LITTLE_ENDIAN); |
2735 | 0 | decrypted_offset += 4; |
2736 | | |
2737 | | /* CRC32 of the DCE fragment data */ |
2738 | 0 | proto_tree_add_item (decr_tree, hf_ntlmssp_verf_crc32, |
2739 | 0 | decr_tvb, decrypted_offset, 4, ENC_LITTLE_ENDIAN); |
2740 | 0 | decrypted_offset += 4; |
2741 | | |
2742 | | /* Incrementing sequence number of DCE conversation */ |
2743 | 0 | proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence, |
2744 | 0 | decr_tvb, decrypted_offset, 4, ENC_NA); |
2745 | 0 | } |
2746 | 6 | } |
2747 | | |
2748 | | /* Used when NTLMSSP is done over DCE/RPC because in this case verifier and real payload are not contiguous*/ |
2749 | | static int |
2750 | | dissect_ntlmssp_payload_only(tvbuff_t *tvb, packet_info *pinfo, _U_ proto_tree *tree, void *data) |
2751 | 0 | { |
2752 | 0 | volatile int offset = 0; |
2753 | 0 | proto_tree *volatile ntlmssp_tree = NULL; |
2754 | 0 | uint32_t encrypted_block_length; |
2755 | 0 | tvbuff_t *volatile decr_tvb; |
2756 | 0 | tvbuff_t** ret_decr_tvb = (tvbuff_t**)data; |
2757 | |
|
2758 | 0 | if (ret_decr_tvb) |
2759 | 0 | *ret_decr_tvb = NULL; |
2760 | | /* the magic ntlm is the identifier of a NTLMSSP packet that's 00 00 00 01 |
2761 | | */ |
2762 | 0 | encrypted_block_length = tvb_captured_length (tvb); |
2763 | | /* signature + seq + real payload */ |
2764 | | |
2765 | | /* Setup a new tree for the NTLMSSP payload */ |
2766 | | #if 0 |
2767 | | if (tree) { |
2768 | | tf = proto_tree_add_item (tree, |
2769 | | hf_ntlmssp_verf, |
2770 | | tvb, offset, -1, ENC_NA); |
2771 | | |
2772 | | ntlmssp_tree = proto_item_add_subtree (tf, |
2773 | | ett_ntlmssp); |
2774 | | } |
2775 | | #endif |
2776 | | /* |
2777 | | * Catch the ReportedBoundsError exception; the stuff we've been |
2778 | | * handed doesn't necessarily run to the end of the packet, it's |
2779 | | * an item inside a packet, so if it happens to be malformed (or |
2780 | | * we, or a dissector we call, has a bug), so that an exception |
2781 | | * is thrown, we want to report the error, but return and let |
2782 | | * our caller dissect the rest of the packet. |
2783 | | * |
2784 | | * If it gets a BoundsError, we can stop, as there's nothing more |
2785 | | * in the packet after our blob to see, so we just re-throw the |
2786 | | * exception. |
2787 | | */ |
2788 | 0 | TRY { |
2789 | | /* Version number */ |
2790 | | |
2791 | | /* Try to decrypt */ |
2792 | 0 | decr_tvb = decrypt_data_payload (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree, NULL); |
2793 | 0 | if (ret_decr_tvb) |
2794 | 0 | *ret_decr_tvb = decr_tvb; |
2795 | | /* let's try to hook ourselves here */ |
2796 | |
|
2797 | 0 | } CATCH_NONFATAL_ERRORS { |
2798 | |
|
2799 | 0 | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
2800 | 0 | } ENDTRY; |
2801 | |
|
2802 | 0 | return offset; |
2803 | 0 | } |
2804 | | |
2805 | | /* Used when NTLMSSP is done over DCE/RPC because in this case verifier and real payload are not contiguous |
2806 | | * But in fact this function could be merged with wrap_dissect_ntlmssp_verf because it's only used there |
2807 | | */ |
2808 | | static int |
2809 | | dissect_ntlmssp_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
2810 | 0 | { |
2811 | 0 | volatile int offset = 0; |
2812 | 0 | proto_tree *volatile ntlmssp_tree = NULL; |
2813 | 0 | proto_item *tf = NULL; |
2814 | 0 | uint32_t verifier_length; |
2815 | 0 | uint32_t encrypted_block_length; |
2816 | |
|
2817 | 0 | verifier_length = tvb_captured_length (tvb); |
2818 | 0 | encrypted_block_length = verifier_length - 4; |
2819 | |
|
2820 | 0 | if (encrypted_block_length < 12) { |
2821 | | /* Don't know why this would happen, but if it does, don't even bother |
2822 | | attempting decryption/dissection */ |
2823 | 0 | return offset + verifier_length; |
2824 | 0 | } |
2825 | | |
2826 | | /* Setup a new tree for the NTLMSSP payload */ |
2827 | 0 | if (tree) { |
2828 | 0 | tf = proto_tree_add_item (tree, |
2829 | 0 | hf_ntlmssp_verf, |
2830 | 0 | tvb, offset, -1, ENC_NA); |
2831 | |
|
2832 | 0 | ntlmssp_tree = proto_item_add_subtree (tf, |
2833 | 0 | ett_ntlmssp); |
2834 | 0 | } |
2835 | | |
2836 | | /* |
2837 | | * Catch the ReportedBoundsError exception; the stuff we've been |
2838 | | * handed doesn't necessarily run to the end of the packet, it's |
2839 | | * an item inside a packet, so if it happens to be malformed (or |
2840 | | * we, or a dissector we call, has a bug), so that an exception |
2841 | | * is thrown, we want to report the error, but return and let |
2842 | | * our caller dissect the rest of the packet. |
2843 | | * |
2844 | | * If it gets a BoundsError, we can stop, as there's nothing more |
2845 | | * in the packet after our blob to see, so we just re-throw the |
2846 | | * exception. |
2847 | | */ |
2848 | 0 | TRY { |
2849 | | /* Version number */ |
2850 | 0 | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_vers, |
2851 | 0 | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
2852 | 0 | offset += 4; |
2853 | | |
2854 | | /* Encrypted body */ |
2855 | 0 | proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_body, |
2856 | 0 | tvb, offset, encrypted_block_length, ENC_NA); |
2857 | | |
2858 | | /* Extract and store the verifier for later decryption */ |
2859 | 0 | store_verifier (tvb, offset, encrypted_block_length, pinfo); |
2860 | | /* let's try to hook ourselves here */ |
2861 | |
|
2862 | 0 | offset += 12; |
2863 | 0 | offset += encrypted_block_length; |
2864 | 0 | } CATCH_NONFATAL_ERRORS { |
2865 | |
|
2866 | 0 | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
2867 | 0 | } ENDTRY; |
2868 | |
|
2869 | 0 | return offset; |
2870 | 0 | } |
2871 | | |
2872 | | static tvbuff_t * |
2873 | | wrap_dissect_ntlmssp_payload_only(tvbuff_t *header_tvb _U_, |
2874 | | tvbuff_t *payload_tvb, |
2875 | | tvbuff_t *trailer_tvb _U_, |
2876 | | tvbuff_t *auth_tvb _U_, |
2877 | | packet_info *pinfo, |
2878 | | dcerpc_auth_info *auth_info _U_) |
2879 | 0 | { |
2880 | 0 | tvbuff_t *decrypted_tvb; |
2881 | |
|
2882 | 0 | dissect_ntlmssp_payload_only(payload_tvb, pinfo, NULL, &decrypted_tvb); |
2883 | | /* Now the payload is decrypted, we can then decrypt the verifier which was stored earlier */ |
2884 | 0 | decrypt_verifier(payload_tvb, pinfo); |
2885 | 0 | return decrypted_tvb; |
2886 | 0 | } |
2887 | | |
2888 | | static unsigned |
2889 | | header_hash(const void *pointer) |
2890 | 2 | { |
2891 | 2 | uint32_t crc = ~crc32c_calculate(pointer, NTLMSSP_KEY_LEN, CRC32C_PRELOAD); |
2892 | | /* Mat TBD ws_debug("Val: %u", crc);*/ |
2893 | 2 | return crc; |
2894 | 2 | } |
2895 | | |
2896 | | static gboolean |
2897 | | header_equal(const void *pointer1, const void *pointer2) |
2898 | 0 | { |
2899 | 0 | if (!memcmp(pointer1, pointer2, NTLMSSP_KEY_LEN)) { |
2900 | 0 | return TRUE; |
2901 | 0 | } |
2902 | 0 | else { |
2903 | 0 | return FALSE; |
2904 | 0 | } |
2905 | 0 | } |
2906 | | |
2907 | | static void |
2908 | | ntlmssp_init_protocol(void) |
2909 | 14 | { |
2910 | 14 | hash_packet = g_hash_table_new_full(header_hash, header_equal, g_free, NULL); |
2911 | 14 | } |
2912 | | |
2913 | | static void |
2914 | | ntlmssp_cleanup_protocol(void) |
2915 | 0 | { |
2916 | 0 | if (decrypted_payloads != NULL) { |
2917 | 0 | g_slist_free(decrypted_payloads); |
2918 | 0 | decrypted_payloads = NULL; |
2919 | 0 | } |
2920 | 0 | g_hash_table_destroy(hash_packet); |
2921 | 0 | } |
2922 | | |
2923 | | |
2924 | | |
2925 | | static int |
2926 | | wrap_dissect_ntlmssp(tvbuff_t *tvb, int offset, packet_info *pinfo, |
2927 | | proto_tree *tree, dcerpc_info *di _U_, uint8_t *drep _U_) |
2928 | 0 | { |
2929 | 0 | tvbuff_t *auth_tvb; |
2930 | |
|
2931 | 0 | auth_tvb = tvb_new_subset_remaining(tvb, offset); |
2932 | |
|
2933 | 0 | dissect_ntlmssp(auth_tvb, pinfo, tree, NULL); |
2934 | |
|
2935 | 0 | return tvb_captured_length_remaining(tvb, offset); |
2936 | 0 | } |
2937 | | |
2938 | | static int |
2939 | | wrap_dissect_ntlmssp_verf(tvbuff_t *tvb, int offset, packet_info *pinfo, |
2940 | | proto_tree *tree, dcerpc_info *di _U_, uint8_t *drep _U_) |
2941 | 0 | { |
2942 | 0 | tvbuff_t *auth_tvb; |
2943 | |
|
2944 | 0 | auth_tvb = tvb_new_subset_remaining(tvb, offset); |
2945 | 0 | return dissect_ntlmssp_verf(auth_tvb, pinfo, tree, NULL); |
2946 | 0 | } |
2947 | | |
2948 | | static dcerpc_auth_subdissector_fns ntlmssp_sign_fns = { |
2949 | | wrap_dissect_ntlmssp, /* Bind */ |
2950 | | wrap_dissect_ntlmssp, /* Bind ACK */ |
2951 | | wrap_dissect_ntlmssp, /* AUTH3 */ |
2952 | | wrap_dissect_ntlmssp_verf, /* Request verifier */ |
2953 | | wrap_dissect_ntlmssp_verf, /* Response verifier */ |
2954 | | NULL, /* Request data */ |
2955 | | NULL /* Response data */ |
2956 | | }; |
2957 | | |
2958 | | static dcerpc_auth_subdissector_fns ntlmssp_seal_fns = { |
2959 | | wrap_dissect_ntlmssp, /* Bind */ |
2960 | | wrap_dissect_ntlmssp, /* Bind ACK */ |
2961 | | wrap_dissect_ntlmssp, /* AUTH3 */ |
2962 | | wrap_dissect_ntlmssp_verf, /* Request verifier */ |
2963 | | wrap_dissect_ntlmssp_verf, /* Response verifier */ |
2964 | | wrap_dissect_ntlmssp_payload_only, /* Request data */ |
2965 | | wrap_dissect_ntlmssp_payload_only /* Response data */ |
2966 | | }; |
2967 | | |
2968 | | static const value_string MSV1_0_CRED_VERSION[] = { |
2969 | | { 0x00000000, "MSV1_0_CRED_VERSION" }, |
2970 | | { 0x00000002, "MSV1_0_CRED_VERSION_V2" }, |
2971 | | { 0x00000004, "MSV1_0_CRED_VERSION_V3" }, |
2972 | | { 0xffff0001, "MSV1_0_CRED_VERSION_IUM" }, |
2973 | | { 0xffff0002, "MSV1_0_CRED_VERSION_REMOTE" }, |
2974 | | { 0xfffffffe, "MSV1_0_CRED_VERSION_RESERVED_1" }, |
2975 | | { 0xffffffff, "MSV1_0_CRED_VERSION_INVALID" }, |
2976 | | { 0, NULL } |
2977 | | }; |
2978 | | |
2979 | 14 | #define MSV1_0_CRED_LM_PRESENT 0x00000001 |
2980 | 14 | #define MSV1_0_CRED_NT_PRESENT 0x00000002 |
2981 | 14 | #define MSV1_0_CRED_REMOVED 0x00000004 |
2982 | 14 | #define MSV1_0_CRED_CREDKEY_PRESENT 0x00000008 |
2983 | 14 | #define MSV1_0_CRED_SHA_PRESENT 0x00000010 |
2984 | | |
2985 | | static int* const MSV1_0_CRED_FLAGS_bits[] = { |
2986 | | &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_LM_PRESENT, |
2987 | | &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_NT_PRESENT, |
2988 | | &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_REMOVED, |
2989 | | &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_CREDKEY_PRESENT, |
2990 | | &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_SHA_PRESENT, |
2991 | | NULL |
2992 | | }; |
2993 | | |
2994 | | static const value_string MSV1_0_CREDENTIAL_KEY_TYPE[] = { |
2995 | | { 0, "InvalidCredKey" }, |
2996 | | { 1, "IUMCredKey" }, |
2997 | | { 2, "DomainUserCredKey" }, |
2998 | | { 3, "LocalUserCredKey" }, |
2999 | | { 4, "ExternallySuppliedCredKey" }, |
3000 | | { 0, NULL } |
3001 | | }; |
3002 | | |
3003 | 0 | #define MSV1_0_CREDENTIAL_KEY_LENGTH 20 |
3004 | | |
3005 | | int |
3006 | | dissect_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL(tvbuff_t *tvb, int offset, proto_tree *tree) |
3007 | 0 | { |
3008 | 0 | proto_item *item; |
3009 | 0 | proto_tree *subtree; |
3010 | 0 | uint32_t EncryptedCredsSize; |
3011 | |
|
3012 | 0 | if (tvb_captured_length(tvb) < 36) |
3013 | 0 | return offset; |
3014 | | |
3015 | 0 | item = proto_tree_add_item(tree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL, tvb, |
3016 | 0 | offset, -1, ENC_NA); |
3017 | 0 | subtree = proto_item_add_subtree(item, ett_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL); |
3018 | |
|
3019 | 0 | proto_tree_add_item(subtree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Version, tvb, |
3020 | 0 | offset, 4, ENC_LITTLE_ENDIAN); |
3021 | 0 | offset+=4; |
3022 | |
|
3023 | 0 | proto_tree_add_bitmask(subtree, tvb, offset, |
3024 | 0 | hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Flags, |
3025 | 0 | ett_ntlmssp, MSV1_0_CRED_FLAGS_bits, ENC_LITTLE_ENDIAN); |
3026 | 0 | offset+=4; |
3027 | |
|
3028 | 0 | proto_tree_add_item(subtree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKey, |
3029 | 0 | tvb, offset, MSV1_0_CREDENTIAL_KEY_LENGTH, ENC_NA); |
3030 | 0 | offset+=MSV1_0_CREDENTIAL_KEY_LENGTH; |
3031 | |
|
3032 | 0 | proto_tree_add_item(subtree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKeyType, |
3033 | 0 | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
3034 | 0 | offset+=4; |
3035 | |
|
3036 | 0 | EncryptedCredsSize = tvb_get_letohl(tvb, offset); |
3037 | 0 | proto_tree_add_item(subtree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCredsSize, |
3038 | 0 | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
3039 | 0 | offset+=4; |
3040 | |
|
3041 | 0 | if (EncryptedCredsSize == 0) |
3042 | 0 | return offset; |
3043 | | |
3044 | 0 | if (tvb_captured_length(tvb) < (36 + EncryptedCredsSize)) |
3045 | 0 | return offset; |
3046 | | |
3047 | 0 | proto_tree_add_item(subtree, hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCreds, |
3048 | 0 | tvb, offset, EncryptedCredsSize, ENC_NA); |
3049 | 0 | offset+=EncryptedCredsSize; |
3050 | |
|
3051 | 0 | return offset; |
3052 | 0 | } |
3053 | | |
3054 | | |
3055 | | void |
3056 | | proto_register_ntlmssp(void) |
3057 | 14 | { |
3058 | | |
3059 | 14 | static hf_register_info hf[] = { |
3060 | 14 | { &hf_ntlmssp_auth, |
3061 | 14 | { "NTLMSSP identifier", "ntlmssp.identifier", |
3062 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3063 | 14 | NULL, HFILL } |
3064 | 14 | }, |
3065 | 14 | { &hf_ntlmssp_message_type, |
3066 | 14 | { "NTLM Message Type", "ntlmssp.messagetype", |
3067 | 14 | FT_UINT32, BASE_HEX, VALS(ntlmssp_message_types), 0x0, |
3068 | 14 | NULL, HFILL } |
3069 | 14 | }, |
3070 | 14 | { &hf_ntlmssp_negotiate_flags, |
3071 | 14 | { "Negotiate Flags", "ntlmssp.negotiateflags", |
3072 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
3073 | 14 | NULL, HFILL } |
3074 | 14 | }, |
3075 | 14 | { &hf_ntlmssp_negotiate_flags_01, |
3076 | 14 | { "Negotiate UNICODE", "ntlmssp.negotiateunicode", |
3077 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_UNICODE, |
3078 | 14 | NULL, HFILL } |
3079 | 14 | }, |
3080 | 14 | { &hf_ntlmssp_negotiate_flags_02, |
3081 | 14 | { "Negotiate OEM", "ntlmssp.negotiateoem", |
3082 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_OEM, |
3083 | 14 | NULL, HFILL } |
3084 | 14 | }, |
3085 | 14 | { &hf_ntlmssp_negotiate_flags_04, |
3086 | 14 | { "Request Target", "ntlmssp.requesttarget", |
3087 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_REQUEST_TARGET, |
3088 | 14 | NULL, HFILL } |
3089 | 14 | }, |
3090 | 14 | { &hf_ntlmssp_negotiate_flags_08, |
3091 | 14 | { "Request 0x00000008", "ntlmssp.unused00000008", |
3092 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_00000008, |
3093 | 14 | NULL, HFILL } |
3094 | 14 | }, |
3095 | 14 | { &hf_ntlmssp_negotiate_flags_10, |
3096 | 14 | { "Negotiate Sign", "ntlmssp.negotiatesign", |
3097 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_SIGN, |
3098 | 14 | NULL, HFILL } |
3099 | 14 | }, |
3100 | 14 | { &hf_ntlmssp_negotiate_flags_20, |
3101 | 14 | { "Negotiate Seal", "ntlmssp.negotiateseal", |
3102 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_SEAL, |
3103 | 14 | NULL, HFILL } |
3104 | 14 | }, |
3105 | 14 | { &hf_ntlmssp_negotiate_flags_40, |
3106 | 14 | { "Negotiate Datagram", "ntlmssp.negotiatedatagram", |
3107 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_DATAGRAM, |
3108 | 14 | NULL, HFILL } |
3109 | 14 | }, |
3110 | 14 | { &hf_ntlmssp_negotiate_flags_80, |
3111 | 14 | { "Negotiate Lan Manager Key", "ntlmssp.negotiatelmkey", |
3112 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_LM_KEY, |
3113 | 14 | NULL, HFILL } |
3114 | 14 | }, |
3115 | 14 | { &hf_ntlmssp_negotiate_flags_100, |
3116 | 14 | { "Negotiate 0x00000100", "ntlmssp.unused00000100", |
3117 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_00000100, |
3118 | 14 | NULL, HFILL } |
3119 | 14 | }, |
3120 | 14 | { &hf_ntlmssp_negotiate_flags_200, |
3121 | 14 | { "Negotiate NTLM key", "ntlmssp.negotiatentlm", |
3122 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_NTLM, |
3123 | 14 | NULL, HFILL } |
3124 | 14 | }, |
3125 | 14 | { &hf_ntlmssp_negotiate_flags_400, |
3126 | 14 | { "Negotiate 0x00000400", "ntlmssp.unused00000400", |
3127 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_00000400, |
3128 | 14 | NULL, HFILL } |
3129 | 14 | }, |
3130 | 14 | { &hf_ntlmssp_negotiate_flags_800, |
3131 | 14 | { "Negotiate Anonymous", "ntlmssp.negotiateanonymous", |
3132 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_ANONYMOUS, |
3133 | 14 | NULL, HFILL } |
3134 | 14 | }, |
3135 | 14 | { &hf_ntlmssp_negotiate_flags_1000, |
3136 | 14 | { "Negotiate OEM Domain Supplied", "ntlmssp.negotiateoemdomainsupplied", |
3137 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, |
3138 | 14 | NULL, HFILL } |
3139 | 14 | }, |
3140 | 14 | { &hf_ntlmssp_negotiate_flags_2000, |
3141 | 14 | { "Negotiate OEM Workstation Supplied", "ntlmssp.negotiateoemworkstationsupplied", |
3142 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, |
3143 | 14 | NULL, HFILL } |
3144 | 14 | }, |
3145 | 14 | { &hf_ntlmssp_negotiate_flags_4000, |
3146 | 14 | { "Negotiate Local Call", "ntlmssp.negotiatelocalcall", |
3147 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_LOCAL_CALL, |
3148 | 14 | NULL, HFILL } |
3149 | 14 | }, |
3150 | 14 | { &hf_ntlmssp_negotiate_flags_8000, |
3151 | 14 | { "Negotiate Always Sign", "ntlmssp.negotiatealwayssign", |
3152 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_ALWAYS_SIGN, |
3153 | 14 | NULL, HFILL } |
3154 | 14 | }, |
3155 | 14 | { &hf_ntlmssp_negotiate_flags_10000, |
3156 | 14 | { "Target Type Domain", "ntlmssp.targettypedomain", |
3157 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_TARGET_TYPE_DOMAIN, |
3158 | 14 | NULL, HFILL } |
3159 | 14 | }, |
3160 | 14 | { &hf_ntlmssp_negotiate_flags_20000, |
3161 | 14 | { "Target Type Server", "ntlmssp.targettypeserver", |
3162 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_TARGET_TYPE_SERVER, |
3163 | 14 | NULL, HFILL } |
3164 | 14 | }, |
3165 | 14 | { &hf_ntlmssp_negotiate_flags_40000, |
3166 | 14 | { "Negotiate 0x00040000", "ntlmssp.unused00040000", |
3167 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_00040000, |
3168 | 14 | NULL, HFILL } |
3169 | 14 | }, |
3170 | | |
3171 | | /* Negotiate Flags */ |
3172 | 14 | { &hf_ntlmssp_negotiate_flags_80000, |
3173 | 14 | { "Negotiate Extended Session Security", "ntlmssp.negotiateextendedsessionsecurity", |
3174 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, |
3175 | 14 | NULL, HFILL } |
3176 | 14 | }, |
3177 | 14 | { &hf_ntlmssp_negotiate_flags_100000, |
3178 | 14 | { "Negotiate Identify", "ntlmssp.negotiateidentify", |
3179 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_IDENTIFY, |
3180 | 14 | NULL, HFILL } |
3181 | 14 | }, |
3182 | 14 | { &hf_ntlmssp_negotiate_flags_200000, |
3183 | 14 | { "Negotiate 0x00200000", "ntlmssp.unused00200000", |
3184 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_00200000, |
3185 | 14 | NULL, HFILL } |
3186 | 14 | }, |
3187 | 14 | { &hf_ntlmssp_negotiate_flags_400000, |
3188 | 14 | { "Request Non-NT Session Key", "ntlmssp.requestnonntsessionkey", |
3189 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_REQUEST_NON_NT_SESSION_KEY, |
3190 | 14 | NULL, HFILL } |
3191 | 14 | }, |
3192 | 14 | { &hf_ntlmssp_negotiate_flags_800000, |
3193 | 14 | { "Negotiate Target Info", "ntlmssp.negotiatetargetinfo", |
3194 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_TARGET_INFO, |
3195 | 14 | NULL, HFILL } |
3196 | 14 | }, |
3197 | 14 | { &hf_ntlmssp_negotiate_flags_1000000, |
3198 | 14 | { "Negotiate 0x01000000", "ntlmssp.unused01000000", |
3199 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_01000000, |
3200 | 14 | NULL, HFILL } |
3201 | 14 | }, |
3202 | 14 | { &hf_ntlmssp_negotiate_flags_2000000, |
3203 | 14 | { "Negotiate Version", "ntlmssp.negotiateversion", |
3204 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_VERSION, |
3205 | 14 | NULL, HFILL } |
3206 | 14 | }, |
3207 | 14 | { &hf_ntlmssp_negotiate_flags_4000000, |
3208 | 14 | { "Negotiate 0x04000000", "ntlmssp.unused04000000", |
3209 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_04000000, |
3210 | 14 | NULL, HFILL } |
3211 | 14 | }, |
3212 | 14 | { &hf_ntlmssp_negotiate_flags_8000000, |
3213 | 14 | { "Negotiate 0x08000000", "ntlmssp.unused08000000", |
3214 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_08000000, |
3215 | 14 | NULL, HFILL } |
3216 | 14 | }, |
3217 | 14 | { &hf_ntlmssp_negotiate_flags_10000000, |
3218 | 14 | { "Negotiate 0x10000000", "ntlmssp.unused10000000", |
3219 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_UNUSED_10000000, |
3220 | 14 | NULL, HFILL } |
3221 | 14 | }, |
3222 | 14 | { &hf_ntlmssp_negotiate_flags_20000000, |
3223 | 14 | { "Negotiate 128", "ntlmssp.negotiate128", |
3224 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_128, |
3225 | 14 | "128-bit encryption is supported", HFILL } |
3226 | 14 | }, |
3227 | 14 | { &hf_ntlmssp_negotiate_flags_40000000, |
3228 | 14 | { "Negotiate Key Exchange", "ntlmssp.negotiatekeyexch", |
3229 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_KEY_EXCH, |
3230 | 14 | NULL, HFILL } |
3231 | 14 | }, |
3232 | 14 | { &hf_ntlmssp_negotiate_flags_80000000, |
3233 | 14 | { "Negotiate 56", "ntlmssp.negotiate56", |
3234 | 14 | FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_56, |
3235 | 14 | "56-bit encryption is supported", HFILL } |
3236 | 14 | }, |
3237 | | #if 0 |
3238 | | { &hf_ntlmssp_negotiate_workstation_strlen, |
3239 | | { "Calling workstation name length", "ntlmssp.negotiate.callingworkstation.strlen", |
3240 | | FT_UINT16, BASE_DEC, NULL, 0x0, |
3241 | | NULL, HFILL } |
3242 | | }, |
3243 | | #endif |
3244 | | #if 0 |
3245 | | { &hf_ntlmssp_negotiate_workstation_maxlen, |
3246 | | { "Calling workstation name max length", "ntlmssp.negotiate.callingworkstation.maxlen", |
3247 | | FT_UINT16, BASE_DEC, NULL, 0x0, |
3248 | | NULL, HFILL } |
3249 | | }, |
3250 | | #endif |
3251 | | #if 0 |
3252 | | { &hf_ntlmssp_negotiate_workstation_buffer, |
3253 | | { "Calling workstation name buffer", "ntlmssp.negotiate.callingworkstation.buffer", |
3254 | | FT_UINT32, BASE_HEX, NULL, 0x0, |
3255 | | NULL, HFILL } |
3256 | | }, |
3257 | | #endif |
3258 | 14 | { &hf_ntlmssp_negotiate_workstation, |
3259 | 14 | { "Calling workstation name", "ntlmssp.negotiate.callingworkstation", |
3260 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3261 | 14 | NULL, HFILL } |
3262 | 14 | }, |
3263 | | #if 0 |
3264 | | { &hf_ntlmssp_negotiate_domain_strlen, |
3265 | | { "Calling workstation domain length", "ntlmssp.negotiate.domain.strlen", |
3266 | | FT_UINT16, BASE_DEC, NULL, 0x0, |
3267 | | NULL, HFILL } |
3268 | | }, |
3269 | | #endif |
3270 | | #if 0 |
3271 | | { &hf_ntlmssp_negotiate_domain_maxlen, |
3272 | | { "Calling workstation domain max length", "ntlmssp.negotiate.domain.maxlen", |
3273 | | FT_UINT16, BASE_DEC, NULL, 0x0, |
3274 | | NULL, HFILL } |
3275 | | }, |
3276 | | #endif |
3277 | | #if 0 |
3278 | | { &hf_ntlmssp_negotiate_domain_buffer, |
3279 | | { "Calling workstation domain buffer", "ntlmssp.negotiate.domain.buffer", |
3280 | | FT_UINT32, BASE_HEX, NULL, 0x0, |
3281 | | NULL, HFILL } |
3282 | | }, |
3283 | | #endif |
3284 | 14 | { &hf_ntlmssp_negotiate_domain, |
3285 | 14 | { "Calling workstation domain", "ntlmssp.negotiate.domain", |
3286 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3287 | 14 | NULL, HFILL } |
3288 | 14 | }, |
3289 | 14 | { &hf_ntlmssp_ntlm_client_challenge, |
3290 | 14 | { "LMv2 Client Challenge", "ntlmssp.ntlmclientchallenge", |
3291 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3292 | 14 | "The 8-byte LMv2 challenge message generated by the client", HFILL } |
3293 | 14 | }, |
3294 | 14 | { &hf_ntlmssp_ntlm_server_challenge, |
3295 | 14 | { "NTLM Server Challenge", "ntlmssp.ntlmserverchallenge", |
3296 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3297 | 14 | NULL, HFILL } |
3298 | 14 | }, |
3299 | 14 | { &hf_ntlmssp_reserved, |
3300 | 14 | { "Reserved", "ntlmssp.reserved", |
3301 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3302 | 14 | NULL, HFILL } |
3303 | 14 | }, |
3304 | | |
3305 | 14 | { &hf_ntlmssp_challenge_target_name, |
3306 | 14 | { "Target Name", "ntlmssp.challenge.target_name", |
3307 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3308 | 14 | NULL, HFILL } |
3309 | 14 | }, |
3310 | 14 | { &hf_ntlmssp_auth_domain, |
3311 | 14 | { "Domain name", "ntlmssp.auth.domain", |
3312 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3313 | 14 | NULL, HFILL } |
3314 | 14 | }, |
3315 | 14 | { &hf_ntlmssp_auth_username, |
3316 | 14 | { "User name", "ntlmssp.auth.username", |
3317 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3318 | 14 | NULL, HFILL } |
3319 | 14 | }, |
3320 | 14 | { &hf_ntlmssp_auth_hostname, |
3321 | 14 | { "Host name", "ntlmssp.auth.hostname", |
3322 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3323 | 14 | NULL, HFILL } |
3324 | 14 | }, |
3325 | 14 | { &hf_ntlmssp_auth_lmresponse, |
3326 | 14 | { "Lan Manager Response", "ntlmssp.auth.lmresponse", |
3327 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3328 | 14 | NULL, HFILL } |
3329 | 14 | }, |
3330 | 14 | { &hf_ntlmssp_auth_ntresponse, |
3331 | 14 | { "NTLM Response", "ntlmssp.auth.ntresponse", |
3332 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3333 | 14 | NULL, HFILL } |
3334 | 14 | }, |
3335 | 14 | { &hf_ntlmssp_auth_sesskey, |
3336 | 14 | { "Session Key", "ntlmssp.auth.sesskey", |
3337 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3338 | 14 | NULL, HFILL } |
3339 | 14 | }, |
3340 | 14 | { &hf_ntlmssp_string_len, |
3341 | 14 | { "Length", "ntlmssp.string.length", |
3342 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3343 | 14 | NULL, HFILL} |
3344 | 14 | }, |
3345 | 14 | { &hf_ntlmssp_string_maxlen, |
3346 | 14 | { "Maxlen", "ntlmssp.string.maxlen", |
3347 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3348 | 14 | NULL, HFILL} |
3349 | 14 | }, |
3350 | 14 | { &hf_ntlmssp_string_offset, |
3351 | 14 | { "Offset", "ntlmssp.string.offset", |
3352 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
3353 | 14 | NULL, HFILL} |
3354 | 14 | }, |
3355 | 14 | { &hf_ntlmssp_blob_len, |
3356 | 14 | { "Length", "ntlmssp.blob.length", |
3357 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3358 | 14 | NULL, HFILL} |
3359 | 14 | }, |
3360 | 14 | { &hf_ntlmssp_blob_maxlen, |
3361 | 14 | { "Maxlen", "ntlmssp.blob.maxlen", |
3362 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3363 | 14 | NULL, HFILL} |
3364 | 14 | }, |
3365 | 14 | { &hf_ntlmssp_blob_offset, |
3366 | 14 | { "Offset", "ntlmssp.blob.offset", |
3367 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
3368 | 14 | NULL, HFILL} |
3369 | 14 | }, |
3370 | 14 | { &hf_ntlmssp_version, |
3371 | 14 | { "Version", "ntlmssp.version", |
3372 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
3373 | 14 | NULL, HFILL} |
3374 | 14 | }, |
3375 | 14 | { &hf_ntlmssp_version_major, |
3376 | 14 | { "Major Version", "ntlmssp.version.major", |
3377 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
3378 | 14 | NULL, HFILL} |
3379 | 14 | }, |
3380 | 14 | { &hf_ntlmssp_version_minor, |
3381 | 14 | { "Minor Version", "ntlmssp.version.minor", |
3382 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
3383 | 14 | NULL, HFILL} |
3384 | 14 | }, |
3385 | 14 | { &hf_ntlmssp_version_build_number, |
3386 | 14 | { "Build Number", "ntlmssp.version.build_number", |
3387 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3388 | 14 | NULL, HFILL} |
3389 | 14 | }, |
3390 | 14 | { &hf_ntlmssp_version_ntlm_current_revision, |
3391 | 14 | { "NTLM Current Revision", "ntlmssp.version.ntlm_current_revision", |
3392 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
3393 | 14 | NULL, HFILL} |
3394 | 14 | }, |
3395 | | |
3396 | | /* Target Info */ |
3397 | 14 | { &hf_ntlmssp_challenge_target_info, |
3398 | 14 | { "Target Info", "ntlmssp.challenge.target_info", |
3399 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
3400 | 14 | NULL, HFILL} |
3401 | 14 | }, |
3402 | 14 | { &hf_ntlmssp_challenge_target_info_len, |
3403 | 14 | { "Length", "ntlmssp.challenge.target_info.length", |
3404 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3405 | 14 | NULL, HFILL} |
3406 | 14 | }, |
3407 | 14 | { &hf_ntlmssp_challenge_target_info_maxlen, |
3408 | 14 | { "Maxlen", "ntlmssp.challenge.target_info.maxlen", |
3409 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3410 | 14 | NULL, HFILL} |
3411 | 14 | }, |
3412 | 14 | { &hf_ntlmssp_challenge_target_info_offset, |
3413 | 14 | { "Offset", "ntlmssp.challenge.target_info.offset", |
3414 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
3415 | 14 | NULL, HFILL} |
3416 | 14 | }, |
3417 | | |
3418 | 14 | { &hf_ntlmssp_challenge_target_info_item_type, |
3419 | 14 | { "Target Info Item Type", "ntlmssp.challenge.target_info.item.type", |
3420 | 14 | FT_UINT16, BASE_HEX | BASE_EXT_STRING, &ntlm_name_types_ext, 0x0, |
3421 | 14 | NULL, HFILL } |
3422 | 14 | }, |
3423 | 14 | { &hf_ntlmssp_challenge_target_info_item_len, |
3424 | 14 | { "Target Info Item Length", "ntlmssp.challenge.target_info.item.length", |
3425 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3426 | 14 | NULL, HFILL} |
3427 | 14 | }, |
3428 | | |
3429 | 14 | { &hf_ntlmssp_challenge_target_info_end, |
3430 | 14 | { "List End", "ntlmssp.challenge.target_info.end", |
3431 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
3432 | 14 | NULL, HFILL } |
3433 | 14 | }, |
3434 | 14 | { &hf_ntlmssp_challenge_target_info_nb_computer_name, |
3435 | 14 | { "NetBIOS Computer Name", "ntlmssp.challenge.target_info.nb_computer_name", |
3436 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3437 | 14 | "Server NetBIOS Computer Name", HFILL } |
3438 | 14 | }, |
3439 | 14 | { &hf_ntlmssp_challenge_target_info_nb_domain_name, |
3440 | 14 | { "NetBIOS Domain Name", "ntlmssp.challenge.target_info.nb_domain_name", |
3441 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3442 | 14 | "Server NetBIOS Domain Name", HFILL } |
3443 | 14 | }, |
3444 | 14 | { &hf_ntlmssp_challenge_target_info_dns_computer_name, |
3445 | 14 | { "DNS Computer Name", "ntlmssp.challenge.target_info.dns_computer_name", |
3446 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3447 | 14 | NULL, HFILL } |
3448 | 14 | }, |
3449 | 14 | { &hf_ntlmssp_challenge_target_info_dns_domain_name, |
3450 | 14 | { "DNS Domain Name", "ntlmssp.challenge.target_info.dns_domain_name", |
3451 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3452 | 14 | NULL, HFILL } |
3453 | 14 | }, |
3454 | 14 | { &hf_ntlmssp_challenge_target_info_dns_tree_name, |
3455 | 14 | { "DNS Tree Name", "ntlmssp.challenge.target_info.dns_tree_name", |
3456 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3457 | 14 | NULL, HFILL } |
3458 | 14 | }, |
3459 | 14 | { &hf_ntlmssp_challenge_target_info_flags, |
3460 | 14 | { "Flags", "ntlmssp.challenge.target_info.flags", |
3461 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
3462 | 14 | NULL, HFILL } |
3463 | 14 | }, |
3464 | 14 | { &hf_ntlmssp_challenge_target_info_timestamp, |
3465 | 14 | { "Timestamp", "ntlmssp.challenge.target_info.timestamp", |
3466 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, |
3467 | 14 | NULL, HFILL } |
3468 | 14 | }, |
3469 | 14 | { &hf_ntlmssp_challenge_target_info_restrictions, |
3470 | 14 | { "Restrictions", "ntlmssp.challenge.target_info.restrictions", |
3471 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
3472 | 14 | NULL, HFILL } |
3473 | 14 | }, |
3474 | 14 | { &hf_ntlmssp_challenge_target_info_target_name, |
3475 | 14 | { "Target Name", "ntlmssp.challenge.target_info.target_name", |
3476 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3477 | 14 | NULL, HFILL } |
3478 | 14 | }, |
3479 | 14 | { &hf_ntlmssp_challenge_target_info_channel_bindings, |
3480 | 14 | { "Channel Bindings", "ntlmssp.challenge.target_info.channel_bindings", |
3481 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3482 | 14 | NULL, HFILL } |
3483 | 14 | }, |
3484 | | |
3485 | 14 | { &hf_ntlmssp_ntlmv2_response_item_type, |
3486 | 14 | { "NTLMV2 Response Item Type", "ntlmssp.ntlmv2_response.item.type", |
3487 | 14 | FT_UINT16, BASE_HEX | BASE_EXT_STRING, &ntlm_name_types_ext, 0x0, |
3488 | 14 | NULL, HFILL } |
3489 | 14 | }, |
3490 | 14 | { &hf_ntlmssp_ntlmv2_response_item_len, |
3491 | 14 | { "NTLMV2 Response Item Length", "ntlmssp.ntlmv2_response.item.length", |
3492 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
3493 | 14 | NULL, HFILL} |
3494 | 14 | }, |
3495 | | |
3496 | 14 | { &hf_ntlmssp_ntlmv2_response_end, |
3497 | 14 | { "List End", "ntlmssp.ntlmv2_response.end", |
3498 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
3499 | 14 | NULL, HFILL } |
3500 | 14 | }, |
3501 | 14 | { &hf_ntlmssp_ntlmv2_response_nb_computer_name, |
3502 | 14 | { "NetBIOS Computer Name", "ntlmssp.ntlmv2_response.nb_computer_name", |
3503 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3504 | 14 | "Server NetBIOS Computer Name", HFILL } |
3505 | 14 | }, |
3506 | 14 | { &hf_ntlmssp_ntlmv2_response_nb_domain_name, |
3507 | 14 | { "NetBIOS Domain Name", "ntlmssp.ntlmv2_response.nb_domain_name", |
3508 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3509 | 14 | "Server NetBIOS Domain Name", HFILL } |
3510 | 14 | }, |
3511 | 14 | { &hf_ntlmssp_ntlmv2_response_dns_computer_name, |
3512 | 14 | { "DNS Computer Name", "ntlmssp.ntlmv2_response.dns_computer_name", |
3513 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3514 | 14 | NULL, HFILL } |
3515 | 14 | }, |
3516 | 14 | { &hf_ntlmssp_ntlmv2_response_dns_domain_name, |
3517 | 14 | { "DNS Domain Name", "ntlmssp.ntlmv2_response.dns_domain_name", |
3518 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3519 | 14 | NULL, HFILL } |
3520 | 14 | }, |
3521 | 14 | { &hf_ntlmssp_ntlmv2_response_dns_tree_name, |
3522 | 14 | { "DNS Tree Name", "ntlmssp.ntlmv2_response.dns_tree_name", |
3523 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3524 | 14 | NULL, HFILL } |
3525 | 14 | }, |
3526 | 14 | { &hf_ntlmssp_ntlmv2_response_flags, |
3527 | 14 | { "Flags", "ntlmssp.ntlmv2_response.flags", |
3528 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
3529 | 14 | NULL, HFILL } |
3530 | 14 | }, |
3531 | 14 | { &hf_ntlmssp_ntlmv2_response_timestamp, |
3532 | 14 | { "Timestamp", "ntlmssp.ntlmv2_response.timestamp", |
3533 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, |
3534 | 14 | NULL, HFILL } |
3535 | 14 | }, |
3536 | 14 | { &hf_ntlmssp_ntlmv2_response_restrictions, |
3537 | 14 | { "Restrictions", "ntlmssp.ntlmv2_response.restrictions", |
3538 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
3539 | 14 | NULL, HFILL } |
3540 | 14 | }, |
3541 | 14 | { &hf_ntlmssp_ntlmv2_response_target_name, |
3542 | 14 | { "Target Name", "ntlmssp.ntlmv2_response.target_name", |
3543 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
3544 | 14 | NULL, HFILL } |
3545 | 14 | }, |
3546 | 14 | { &hf_ntlmssp_ntlmv2_response_channel_bindings, |
3547 | 14 | { "Channel Bindings", "ntlmssp.ntlmv2_response.channel_bindings", |
3548 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3549 | 14 | NULL, HFILL } |
3550 | 14 | }, |
3551 | | |
3552 | 14 | { &hf_ntlmssp_message_integrity_code, |
3553 | 14 | { "MIC", "ntlmssp.authenticate.mic", |
3554 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3555 | 14 | "Message Integrity Code", HFILL} |
3556 | 14 | }, |
3557 | 14 | { &hf_ntlmssp_verf, |
3558 | 14 | { "NTLMSSP Verifier", "ntlmssp.verf", |
3559 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
3560 | 14 | NULL, HFILL } |
3561 | 14 | }, |
3562 | 14 | { &hf_ntlmssp_verf_vers, |
3563 | 14 | { "Version Number", "ntlmssp.verf.vers", |
3564 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
3565 | 14 | NULL, HFILL } |
3566 | 14 | }, |
3567 | 14 | { &hf_ntlmssp_verf_body, |
3568 | 14 | { "Verifier Body", "ntlmssp.verf.body", |
3569 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3570 | 14 | NULL, HFILL } |
3571 | 14 | }, |
3572 | | #if 0 |
3573 | | { &hf_ntlmssp_decrypted_payload, |
3574 | | { "NTLM Decrypted Payload", "ntlmssp.decrypted_payload", |
3575 | | FT_BYTES, BASE_NONE, NULL, 0x0, |
3576 | | NULL, HFILL } |
3577 | | }, |
3578 | | #endif |
3579 | 14 | { &hf_ntlmssp_verf_randompad, |
3580 | 14 | { "Random Pad", "ntlmssp.verf.randompad", |
3581 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
3582 | 14 | NULL, HFILL } |
3583 | 14 | }, |
3584 | 14 | { &hf_ntlmssp_verf_crc32, |
3585 | 14 | { "Verifier CRC32", "ntlmssp.verf.crc32", |
3586 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
3587 | 14 | NULL, HFILL } |
3588 | 14 | }, |
3589 | 14 | { &hf_ntlmssp_verf_hmacmd5, |
3590 | 14 | { "HMAC MD5", "ntlmssp.verf.hmacmd5", |
3591 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3592 | 14 | NULL, HFILL } |
3593 | 14 | }, |
3594 | 14 | { &hf_ntlmssp_verf_sequence, |
3595 | 14 | { "Sequence", "ntlmssp.verf.sequence", |
3596 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3597 | 14 | NULL, HFILL } |
3598 | 14 | }, |
3599 | | |
3600 | 14 | { &hf_ntlmssp_ntlmv2_response, |
3601 | 14 | { "NTLMv2 Response", "ntlmssp.ntlmv2_response", |
3602 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3603 | 14 | NULL, HFILL } |
3604 | 14 | }, |
3605 | 14 | { &hf_ntlmssp_ntlmv2_response_ntproofstr, |
3606 | 14 | { "NTProofStr", "ntlmssp.ntlmv2_response.ntproofstr", |
3607 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3608 | 14 | "The HMAC-MD5 of the challenge", HFILL } |
3609 | 14 | }, |
3610 | 14 | { &hf_ntlmssp_ntlmv2_response_rversion, |
3611 | 14 | { "Response Version", "ntlmssp.ntlmv2_response.rversion", |
3612 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
3613 | 14 | "The 1-byte response version, currently set to 1", HFILL } |
3614 | 14 | }, |
3615 | 14 | { &hf_ntlmssp_ntlmv2_response_hirversion, |
3616 | 14 | { "Hi Response Version", "ntlmssp.ntlmv2_response.hirversion", |
3617 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
3618 | 14 | "The 1-byte highest response version understood by the client, currently set to 1", HFILL } |
3619 | 14 | }, |
3620 | 14 | { &hf_ntlmssp_ntlmv2_response_z, |
3621 | 14 | { "Z", "ntlmssp.ntlmv2_response.z", |
3622 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3623 | 14 | "byte array of zero bytes", HFILL } |
3624 | 14 | }, |
3625 | 14 | { &hf_ntlmssp_ntlmv2_response_pad, |
3626 | 14 | { "padding", "ntlmssp.ntlmv2_response.pad", |
3627 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3628 | 14 | NULL, HFILL } |
3629 | 14 | }, |
3630 | 14 | { &hf_ntlmssp_ntlmv2_response_time, |
3631 | 14 | { "Time", "ntlmssp.ntlmv2_response.time", |
3632 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, |
3633 | 14 | "The 8-byte little-endian time in UTC", HFILL } |
3634 | 14 | }, |
3635 | 14 | { &hf_ntlmssp_ntlmv2_response_chal, |
3636 | 14 | { "NTLMv2 Client Challenge", "ntlmssp.ntlmv2_response.chal", |
3637 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
3638 | 14 | "The 8-byte NTLMv2 challenge message generated by the client", HFILL } |
3639 | 14 | }, |
3640 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL, |
3641 | 14 | { "NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL", |
3642 | 14 | FT_NONE, BASE_NONE, NULL, 0, |
3643 | 14 | NULL, HFILL }}, |
3644 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Version, |
3645 | 14 | { "Version", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.Version", |
3646 | 14 | FT_UINT32, BASE_HEX, VALS(MSV1_0_CRED_VERSION), 0, |
3647 | 14 | NULL, HFILL }}, |
3648 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_Flags, |
3649 | 14 | { "Flags", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.Flags", |
3650 | 14 | FT_UINT32, BASE_HEX, NULL, 0, |
3651 | 14 | NULL, HFILL }}, |
3652 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_LM_PRESENT, |
3653 | 14 | { "lm_present", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.LM_PRESENT", |
3654 | 14 | FT_BOOLEAN, 32, NULL, MSV1_0_CRED_LM_PRESENT, |
3655 | 14 | NULL, HFILL }}, |
3656 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_NT_PRESENT, |
3657 | 14 | { "nt_present", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.NT_PRESENT", |
3658 | 14 | FT_BOOLEAN, 32, NULL, MSV1_0_CRED_NT_PRESENT, |
3659 | 14 | NULL, HFILL }}, |
3660 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_REMOVED, |
3661 | 14 | { "removed", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.REMOVED", |
3662 | 14 | FT_BOOLEAN, 32, NULL, MSV1_0_CRED_REMOVED, |
3663 | 14 | NULL, HFILL }}, |
3664 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_CREDKEY_PRESENT, |
3665 | 14 | { "credkey_present", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.CREDKEY_PRESENT", |
3666 | 14 | FT_BOOLEAN, 32, NULL, MSV1_0_CRED_CREDKEY_PRESENT, |
3667 | 14 | NULL, HFILL }}, |
3668 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_FLAG_SHA_PRESENT, |
3669 | 14 | { "sha_present", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.SHA_PRESENT", |
3670 | 14 | FT_BOOLEAN, 32, NULL, MSV1_0_CRED_SHA_PRESENT, |
3671 | 14 | NULL, HFILL }}, |
3672 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKey, |
3673 | 14 | { "CredentialKey", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.CredentialKey", |
3674 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
3675 | 14 | NULL, HFILL }}, |
3676 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_CredentialKeyType, |
3677 | 14 | { "CredentialKeyType", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.CredentialKeyType", |
3678 | 14 | FT_UINT32, BASE_DEC, VALS(MSV1_0_CREDENTIAL_KEY_TYPE), 0, |
3679 | 14 | NULL, HFILL }}, |
3680 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCredsSize, |
3681 | 14 | { "EncryptedCredsSize", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.EncryptedCredsSize", |
3682 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3683 | 14 | NULL, HFILL }}, |
3684 | 14 | { &hf_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL_EncryptedCreds, |
3685 | 14 | { "EncryptedCreds", "ntlmssp.NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL.EncryptedCreds", |
3686 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
3687 | 14 | NULL, HFILL }}, |
3688 | 14 | }; |
3689 | | |
3690 | | |
3691 | 14 | static int *ett[] = { |
3692 | 14 | &ett_ntlmssp, |
3693 | 14 | &ett_ntlmssp_negotiate_flags, |
3694 | 14 | &ett_ntlmssp_string, |
3695 | 14 | &ett_ntlmssp_blob, |
3696 | 14 | &ett_ntlmssp_version, |
3697 | 14 | &ett_ntlmssp_challenge_target_info, |
3698 | 14 | &ett_ntlmssp_challenge_target_info_item, |
3699 | 14 | &ett_ntlmssp_ntlmv2_response, |
3700 | 14 | &ett_ntlmssp_ntlmv2_response_item, |
3701 | 14 | &ett_ntlmssp_NTLM_REMOTE_SUPPLEMENTAL_CREDENTIAL, |
3702 | 14 | }; |
3703 | 14 | static ei_register_info ei[] = { |
3704 | 14 | { &ei_ntlmssp_v2_key_too_long, { "ntlmssp.v2_key_too_long", PI_UNDECODED, PI_WARN, "NTLM v2 key is too long", EXPFILL }}, |
3705 | 14 | { &ei_ntlmssp_blob_len_too_long, { "ntlmssp.blob.length.too_long", PI_UNDECODED, PI_WARN, "Session blob length too long", EXPFILL }}, |
3706 | 14 | { &ei_ntlmssp_target_info_attr, { "ntlmssp.target_info_attr.unknown", PI_UNDECODED, PI_WARN, "Unknown NTLMSSP Target Info Attribute", EXPFILL }}, |
3707 | 14 | { &ei_ntlmssp_target_info_invalid, { "ntlmssp.target_info_attr.invalid", PI_UNDECODED, PI_WARN, "Invalid NTLMSSP Target Info AvPairs", EXPFILL }}, |
3708 | 14 | { &ei_ntlmssp_message_type, { "ntlmssp.messagetype.unknown", PI_PROTOCOL, PI_WARN, "Unrecognized NTLMSSP Message", EXPFILL }}, |
3709 | 14 | { &ei_ntlmssp_auth_nthash, { "ntlmssp.authenticated", PI_SECURITY, PI_CHAT, "Authenticated NTHASH", EXPFILL }}, |
3710 | 14 | { &ei_ntlmssp_sessionbasekey, { "ntlmssp.sessionbasekey", PI_SECURITY, PI_CHAT, "SessionBaseKey", EXPFILL }}, |
3711 | 14 | { &ei_ntlmssp_sessionkey, { "ntlmssp.sessionkey", PI_SECURITY, PI_CHAT, "SessionKey", EXPFILL }}, |
3712 | 14 | }; |
3713 | 14 | module_t *ntlmssp_module; |
3714 | 14 | expert_module_t* expert_ntlmssp; |
3715 | | |
3716 | 14 | proto_ntlmssp = proto_register_protocol ( |
3717 | 14 | "NTLM Secure Service Provider", /* name */ |
3718 | 14 | "NTLMSSP", /* short name */ |
3719 | 14 | "ntlmssp" /* abbrev */ |
3720 | 14 | ); |
3721 | 14 | proto_register_field_array (proto_ntlmssp, hf, array_length (hf)); |
3722 | 14 | proto_register_subtree_array (ett, array_length (ett)); |
3723 | 14 | expert_ntlmssp = expert_register_protocol(proto_ntlmssp); |
3724 | 14 | expert_register_field_array(expert_ntlmssp, ei, array_length(ei)); |
3725 | 14 | register_init_routine(&ntlmssp_init_protocol); |
3726 | 14 | register_cleanup_routine(&ntlmssp_cleanup_protocol); |
3727 | | |
3728 | 14 | ntlmssp_module = prefs_register_protocol(proto_ntlmssp, NULL); |
3729 | | |
3730 | 14 | prefs_register_string_preference(ntlmssp_module, "nt_password", |
3731 | 14 | "NT Password", |
3732 | 14 | "Cleartext NT Password (used to decrypt payloads, supports only ASCII passwords)", |
3733 | 14 | &ntlmssp_option_nt_password); |
3734 | | |
3735 | 14 | ntlmssp_handle = register_dissector("ntlmssp", dissect_ntlmssp, proto_ntlmssp); |
3736 | 14 | ntlmssp_wrap_handle = register_dissector("ntlmssp_payload", dissect_ntlmssp_payload, proto_ntlmssp); |
3737 | 14 | register_dissector("ntlmssp_data_only", dissect_ntlmssp_payload_only, proto_ntlmssp); |
3738 | 14 | register_dissector("ntlmssp_verf", dissect_ntlmssp_verf, proto_ntlmssp); |
3739 | | |
3740 | 14 | ntlmssp_tap = register_tap("ntlmssp"); |
3741 | 14 | } |
3742 | | |
3743 | | void |
3744 | | proto_reg_handoff_ntlmssp(void) |
3745 | 14 | { |
3746 | | /* Register protocol with the GSS-API module */ |
3747 | | |
3748 | 14 | gssapi_init_oid("1.3.6.1.4.1.311.2.2.10", proto_ntlmssp, ett_ntlmssp, |
3749 | 14 | ntlmssp_handle, ntlmssp_wrap_handle, |
3750 | 14 | "NTLMSSP - Microsoft NTLM Security Support Provider"); |
3751 | | |
3752 | | /* Register authenticated pipe dissector */ |
3753 | | |
3754 | | /* |
3755 | | * XXX - the verifiers here seem to have a version of 1 and a body of all |
3756 | | * zeroes. |
3757 | | * |
3758 | | * XXX - DCE_C_AUTHN_LEVEL_CONNECT is, according to the DCE RPC 1.1 |
3759 | | * spec, upgraded to DCE_C_AUTHN_LEVEL_PKT. Should we register |
3760 | | * any other levels here? |
3761 | | */ |
3762 | 14 | register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT, |
3763 | 14 | DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, |
3764 | 14 | &ntlmssp_sign_fns); |
3765 | | |
3766 | 14 | register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT, |
3767 | 14 | DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, |
3768 | 14 | &ntlmssp_sign_fns); |
3769 | | |
3770 | 14 | register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, |
3771 | 14 | DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, |
3772 | 14 | &ntlmssp_sign_fns); |
3773 | | |
3774 | 14 | register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY, |
3775 | 14 | DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, |
3776 | 14 | &ntlmssp_seal_fns); |
3777 | 14 | } |
3778 | | |
3779 | | /* |
3780 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
3781 | | * |
3782 | | * Local variables: |
3783 | | * c-basic-offset: 2 |
3784 | | * tab-width: 8 |
3785 | | * indent-tabs-mode: nil |
3786 | | * End: |
3787 | | * |
3788 | | * vi: set shiftwidth=2 tabstop=8 expandtab: |
3789 | | * :indentSize=2:tabSize=8:noTabs=true: |
3790 | | */ |