1 /* Proxytunnel - (C) 2001-2008 Jos Visser / Mark Janssen */
2 /* Contact: josv@osp.nl / maniac@maniac.nl */
3
4 /*
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* ntlm.c -- Code for handling NTLM authentication */
21 /* NTLM Code from Paul Solomon <psolomon@tpg.com.au> */
22
23 #include "ntlm.h"
24 #include "global.h"
25 #include "base64.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include "proxytunnel.h"
29 #include <ctype.h>
30 #include <sys/time.h>
31 #include <openssl/md4.h>
32 #include <openssl/md5.h>
33
34 #define TYPE1_DATA_SEG 8
35 #define TYPE2_BUF_SIZE 2048
36 #define DOMAIN_BUFLEN 256
37 #define LM2_DIGEST_LEN 24
38
39 int ntlm_challenge = 0;
40 void message( char *s, ... );
41 int unicode = 0;
42
43 unsigned char challenge[8];
44 char domain[DOMAIN_BUFLEN];
45 char workstation[] = "WORKSTATION";
46
47 unsigned char unipasswd[DOMAIN_BUFLEN * 2];
48
49 unsigned char t2_buf[TYPE2_BUF_SIZE];
50
51 unsigned char *pblob = NULL;
52 int bloblen;
53
54 unsigned char *t_info;
55 int t_info_len;
56
57 unsigned long flags;
58
59 unsigned char lm2digest[LM2_DIGEST_LEN];
60
build_type1()61 void build_type1() {
62 ntlm_type1 *type1;
63 int len = sizeof(ntlm_type1) + sizeof(unsigned char) * TYPE1_DATA_SEG;
64
65 type1 = (ntlm_type1 *)malloc(len);
66 if (!type1) {
67 message("Fatal Error in build type1, Malloc failed\n");
68 exit(-1);
69 }
70
71 memset(type1, 0, len);
72 type1->signature[0] = 'N';
73 type1->signature[1] = 'T';
74 type1->signature[2] = 'L';
75 type1->signature[3] = 'M';
76 type1->signature[4] = 'S';
77 type1->signature[5] = 'S';
78 type1->signature[6] = 'P';
79 type1->signature[7] = '\0';
80
81 type1->message_type = NTLM_TYPE_1;
82 type1->flags = NEG_UNICODE | NEG_OEM | REQ_TARGET | NEG_NTLM | NEG_ASIGN | NEG_NTLM2 | NEG_128 | NEG_56 | IE_SETSTHIS;
83
84 base64((unsigned char *)ntlm_type1_buf, (unsigned char *)type1, len);
85
86 free(type1);
87 return;
88 }
89
90
parse_type2(unsigned char * buf)91 int parse_type2(unsigned char *buf) {
92 int len = unbase64(t2_buf, buf, TYPE2_BUF_SIZE);
93 ntlm_type2 *t2 = (ntlm_type2 *)t2_buf;
94 int i;
95
96 if (len <= 0) {
97 message("parse_type2: failed to decode the message\n");
98 return -1;
99 }
100
101 if (strcmp((const char *)t2->signature, "NTLMSSP") != 0) {
102 message("parse_type2: Signature did not match\n");
103 return -1;
104 }
105
106 if( args_info.verbose_flag )
107 message("parse_type2: Signature matched\n");
108
109 if (t2->message_type != NTLM_TYPE_2) {
110 message("parse_type2: Incorrect message type sent\n");
111 return -1;
112 }
113
114 if (t2->target_name.length > 0 && t2->target_name.length < DOMAIN_BUFLEN && (t2->target_name.length + t2->target_name.offset < len)) {
115 int sp = 1;
116 if (t2->flags & NEG_UNICODE)
117 sp = 2;
118 for (i = 0; i < t2->target_name.length / sp; i++)
119 domain[i] = t2_buf[t2->target_name.offset + i * sp];
120 domain[i] = 0;
121 } else {
122 domain[0] = 0;
123 }
124
125 for (i = 0; i < 8; i++)
126 challenge[i] = t2->challenge[i];
127
128 if( args_info.verbose_flag )
129 message("NTLM Got Domain: %s\n", domain);
130
131 if( args_info.domain_given ) {
132 if( ! args_info.quiet_flag )
133 message( "NTLM Overriding domain: %s\n", args_info.domain_arg );
134 for( i = 0; i < strlen(args_info.domain_arg); i++ ) {
135 domain[i] = args_info.domain_arg[i];
136 }
137 domain[i] = 0;
138 }
139
140 if( args_info.verbose_flag ) {
141 message("NTLM Domain: %s\n", domain);
142 message("NTLM Got Challenge: ");
143
144 for (i = 0; i < 8; i++)
145 message("%02X", challenge[i]);
146 message("\n");
147 }
148
149 if (!(t2->flags & NEG_NTLM && t2->flags & NEG_NTLM2)) {
150 message("parse_type2: Sorry, only NTLMv2 is supported at this time\n");
151 return -1;
152 }
153
154 if (t2->flags & NEG_UNICODE)
155 unicode = 1;
156 else
157 unicode = 0;
158
159 t_info = &t2_buf[t2->target_info.offset];
160 t_info_len = t2->target_info.length;
161
162 flags = t2->flags;
163
164 ntlm_challenge = 1;
165
166 build_ntlm2_response();
167
168 return 0;
169 }
170
171
build_type3_response()172 void build_type3_response() {
173 unsigned char *t3;
174 ntlm_type3 *type3;
175 int len;
176 int sp = 1;
177 int i;
178
179 if (unicode)
180 sp = 2;
181
182 len = sizeof(ntlm_type3) + sizeof(unsigned char) * (LM2_DIGEST_LEN + bloblen + (strlen(domain) + strlen(args_info.user_arg) + strlen(workstation)) * sp);
183
184 type3 = (ntlm_type3 *)malloc(len);
185 if (!type3) {
186 message("Fatal Error in build type3, Malloc failed\n");
187 exit(-1);
188 }
189 t3 = (unsigned char *) type3;
190
191 memset(type3, 0, len);
192 type3->signature[0] = 'N';
193 type3->signature[1] = 'T';
194 type3->signature[2] = 'L';
195 type3->signature[3] = 'M';
196 type3->signature[4] = 'S';
197 type3->signature[5] = 'S';
198 type3->signature[6] = 'P';
199 type3->signature[7] = '\0';
200
201 type3->message_type = NTLM_TYPE_3;
202 type3->flags = flags & ~TAR_DOMAIN & ~NEG_TARINFO;
203
204 type3->LM_response.length = LM2_DIGEST_LEN;
205 type3->LM_response.space = LM2_DIGEST_LEN;
206 type3->LM_response.offset = sizeof(ntlm_type3);
207 memcpy(&t3[type3->LM_response.offset], lm2digest, LM2_DIGEST_LEN);
208
209 type3->NTLM_response.length = bloblen;
210 type3->NTLM_response.space = bloblen;
211 type3->NTLM_response.offset = type3->LM_response.offset + type3->LM_response.space;
212 memcpy(&t3[type3->NTLM_response.offset], pblob, bloblen);
213
214 type3->domain.length = strlen(domain) * sp;
215 type3->domain.space = strlen(domain) * sp;
216 type3->domain.offset = type3->NTLM_response.offset + type3->NTLM_response.space;
217 for (i = 0; i < strlen(domain); i++)
218 t3[type3->domain.offset + i * sp] = domain[i];
219
220 type3->user.length = strlen(args_info.user_arg) * sp;
221 type3->user.space = strlen(args_info.user_arg) * sp;
222 type3->user.offset = type3->domain.offset + type3->domain.space;
223 for (i = 0; i < strlen(args_info.user_arg); i++)
224 t3[type3->user.offset + i * sp] = args_info.user_arg[i];
225
226 type3->workstation.length = strlen(workstation) * sp;
227 type3->workstation.space = strlen(workstation) * sp;
228 type3->workstation.offset = type3->user.offset + type3->user.space;
229 for (i = 0; i < strlen(workstation); i++)
230 t3[type3->workstation.offset + i * sp] = workstation[i];
231
232 base64((unsigned char *)ntlm_type3_buf, (unsigned char *)type3, len);
233
234 free(type3);
235 return;
236 }
237
238 /*
239 ** Function: hmac_md5
240 */
241
242 void
hmac_md5(text,text_len,key,key_len,digest)243 hmac_md5(text, text_len, key, key_len, digest)
244 unsigned char* text; /* pointer to data stream */
245 int text_len; /* length of data stream */
246 unsigned char* key; /* pointer to authentication key */
247 int key_len; /* length of authentication key */
248 unsigned char digest[16]; /* caller digest to be filled in */
249 {
250 MD5_CTX context;
251 unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
252 unsigned char k_opad[65]; /* outer padding - key XORd with opad */
253 unsigned char tk[16];
254 int i;
255
256 /* if key is longer than 64 bytes reset it to key=MD5(key) */
257 if (key_len > 64) {
258 MD5_CTX tctx;
259 MD5_Init( &tctx );
260 MD5_Update( &tctx, key, key_len );
261 MD5_Final( tk, &tctx );
262 key = tk;
263 key_len = 16;
264 }
265
266 /*
267 * the HMAC_MD5 transform looks like:
268 *
269 * MD5(K XOR opad, MD5(K XOR ipad, text))
270 *
271 * where K is an n byte key
272 * ipad is the byte 0x36 repeated 64 times
273 * opad is the byte 0x5c repeated 64 times
274 * and text is the data being protected
275 */
276
277 /* start out by storing key in pads */
278 bzero( k_ipad, sizeof k_ipad);
279 bzero( k_opad, sizeof k_opad);
280 bcopy( key, k_ipad, key_len);
281 bcopy( key, k_opad, key_len);
282
283 /* XOR key with ipad and opad values */
284 for (i=0; i<64; i++) {
285 k_ipad[i] ^= 0x36;
286 k_opad[i] ^= 0x5c;
287 }
288
289 /* perform inner MD5 */
290 MD5_Init(&context); /* init context for 1st pass */
291 MD5_Update(&context, k_ipad, 64); /* start with inner pad */
292 MD5_Update(&context, text, text_len); /* then text of datagram */
293 MD5_Final(digest, &context); /* finish up 1st pass */
294
295 /* perform outer MD5 */
296 MD5_Init(&context); /* init context for 2nd pass */
297 MD5_Update(&context, k_opad, 64); /* start with outer pad */
298 MD5_Update(&context, digest, 16); /* then results of 1st hash */
299 MD5_Final(digest, &context); /* finish up 2nd pass */
300 }
301
build_ntlm2_response()302 void build_ntlm2_response() {
303 int i, j;
304 int passlen = 0;
305 MD4_CTX passcontext;
306 unsigned char passdigest[16];
307 unsigned char *userdom;
308 int userdomlen;
309 unsigned char userdomdigest[16];
310 blob *b;
311 struct timeval t;
312 unsigned char responsedigest[16];
313 unsigned char lm2data[16];
314
315 if (pblob != NULL)
316 free(pblob);
317
318 memset(unipasswd, 0, sizeof(unsigned char) * DOMAIN_BUFLEN * 2);
319 for (i = 0; i < strlen(args_info.pass_arg); i++) {
320 if (unicode) {
321 unipasswd[i * 2] = args_info.pass_arg[i];
322 passlen++;
323 passlen++;
324 } else {
325 unipasswd[i] = args_info.pass_arg[i];
326 passlen++;
327 }
328 }
329
330 MD4_Init (&passcontext);
331 MD4_Update (&passcontext, unipasswd, passlen);
332 MD4_Final (passdigest, &passcontext);
333
334 if( args_info.verbose_flag ) {
335 message("NTLM: MD4 of password is: ");
336 for( i = 0; i < 16; i++)
337 message("%02X", passdigest[i]);
338 message("\nDOMAIN: %s\nUSER: %s\n", domain, args_info.user_arg);
339 }
340
341 userdomlen = sizeof(unsigned char) * (strlen(args_info.user_arg) + strlen(domain)) * 2;
342 userdom = (unsigned char *)malloc(userdomlen);
343 memset(userdom, 0, userdomlen);
344 if (!userdom) {
345 message("Fatal Error in build_ntlm2_response, Malloc failed\n");
346 exit(-1);
347 }
348
349 userdomlen = 0;
350 for (i = 0; i < strlen(args_info.user_arg); i++) {
351 if (unicode) {
352 userdom[i * 2] = toupper(args_info.user_arg[i]);
353 userdomlen++;
354 userdomlen++;
355 } else {
356 userdom[i] = toupper(args_info.user_arg[i]);
357 userdomlen++;
358 }
359 }
360
361 for (j = 0; j < strlen(domain); j++) {
362 if (unicode) {
363 userdom[i * 2 + j * 2] = toupper(domain[j]);
364 userdomlen++;
365 userdomlen++;
366 } else {
367 userdom[i + j] = toupper(domain[j]);
368 userdomlen++;
369 }
370 }
371
372 if( args_info.verbose_flag ) {
373 message("userdom is: ");
374 for( i = 0; i < userdomlen; i++)
375 message("%02X", userdom[i]);
376 message("\n");
377 }
378
379 hmac_md5(userdom, userdomlen, passdigest, 16, userdomdigest);
380
381 free(userdom);
382
383 if( args_info.verbose_flag ) {
384 message("HMAC_MD5 of userdom keyed with MD4 pass is: ");
385 for( i = 0; i < 16; i++)
386 message("%02X", userdomdigest[i]);
387 message("\n");
388 }
389
390 if ((sizeof(long long) != 8)) {
391 message("We are in trouble here.. long long support is not here!!\n");
392 exit(-1);
393 }
394
395 bloblen = sizeof(blob) + sizeof(unsigned char) * t_info_len;
396
397 pblob = (unsigned char *)malloc(bloblen);
398 if (!pblob) {
399 message("Fatal Error in build_ntlm2_response, Malloc failed\n");
400 exit(-1);
401 }
402
403 memset(pblob, 0, bloblen);
404
405 b = (blob *)pblob;
406
407 for (i = 0; i < 8; i++)
408 b->digest[8 + i] = challenge[i];
409
410 b->signature = 0x00000101;
411
412 /* This is nasty, also not sure all this 64bit arithmetic will
413 * work all the time.. basically the spec says you need the
414 * number of 10ths of microseconds since jan 1, 1601.
415 */
416
417 gettimeofday(&t, NULL);
418 b->timestamp = (long long)t.tv_sec;
419 b->timestamp += 11644473600LL;
420 b->timestamp *= 1000000LL;
421 b->timestamp += (long long)t.tv_usec;
422 b->timestamp *= 10LL;
423
424 // need a ramdom client challenge
425 for (i = 0; i < 8; i++)
426 b->client_challenge[i] = (unsigned char) ((256.0 * rand()) / (RAND_MAX + 1.0)) ;
427
428 if( args_info.verbose_flag ) {
429 message("client_challenge is: ");
430 for( i = 0; i < 8; i++)
431 message("%02X", b->client_challenge[i]);
432 message("\n");
433 }
434
435 memcpy(&b->data_start, t_info, t_info_len);
436
437 hmac_md5(&pblob[8], bloblen - 8, userdomdigest, 16, responsedigest);
438
439 for(i = 0; i < 16; i++)
440 b->digest[i] = responsedigest[i];
441
442 if( args_info.verbose_flag ) {
443 message("HMAC is: ");
444 for( i = 0; i < 16; i++)
445 message("%02X", responsedigest[i]);
446 message("\n");
447 }
448
449 // LM2 response generation
450
451 for (i = 0; i < 8; i++)
452 lm2data[i] = challenge[i];
453
454 for (i = 0; i < 8; i++)
455 lm2data[8 + i] = b->client_challenge[i];
456
457 hmac_md5(lm2data, 16, userdomdigest, 16, lm2digest);
458
459 for (i = 0; i < 8; i++)
460 lm2digest[16 + i] = b->client_challenge[i];
461 }
462
463 // vim:noexpandtab:ts=4
464