1 /* 2 * Beware the LM hash is easy to crack (google for l0phtCrack) 3 * and though NTLM is more secure it is still breakable. 4 * Ntlmv2 is better and seen as good enough by the Windows community. 5 * For real security use Kerberos. 6 */ 7 #include <u.h> 8 #include <libc.h> 9 #include <mp.h> 10 #include <auth.h> 11 #include <libsec.h> 12 #include <ctype.h> 13 #include <fcall.h> 14 #include <thread.h> 15 #include <9p.h> 16 #include "cifs.h" 17 18 #define NTLMV2_TEST 1 19 #define DEF_AUTH "ntlmv2" 20 21 static enum { 22 MACkeylen = 40, /* MAC key len */ 23 MAClen = 8, /* signature length */ 24 MACoff = 14, /* sign. offset from start of SMB (not netbios) pkt */ 25 Bliplen = 8, /* size of LMv2 client nonce */ 26 }; 27 28 static void 29 dmp(char *s, int seq, void *buf, int n) 30 { 31 int i; 32 char *p = buf; 33 34 print("%s %3d ", s, seq); 35 while(n > 0){ 36 for(i = 0; i < 16 && n > 0; i++, n--) 37 print("%02x ", *p++ & 0xff); 38 if(n > 0) 39 print("\n"); 40 } 41 print("\n"); 42 } 43 44 static Auth * 45 auth_plain(char *windom, char *keyp, uchar *chal, int len) 46 { 47 UserPasswd *up; 48 static Auth *ap; 49 50 USED(chal, len); 51 52 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s", 53 windom, keyp); 54 if(! up) 55 sysfatal("cannot get key - %r"); 56 57 ap = emalloc9p(sizeof(Auth)); 58 memset(ap, 0, sizeof(ap)); 59 ap->user = estrdup9p(up->user); 60 ap->windom = estrdup9p(windom); 61 62 ap->resp[0] = estrdup9p(up->passwd); 63 ap->len[0] = strlen(up->passwd); 64 memset(up->passwd, 0, strlen(up->passwd)); 65 free(up); 66 67 return ap; 68 } 69 70 static Auth * 71 auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len) 72 { 73 int err; 74 Auth *ap; 75 char user[64]; 76 MSchapreply mcr; 77 78 err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr, 79 auth_getkey, "windom=%s proto=mschap role=client service=cifs %s", 80 windom, keyp); 81 if(err == -1) 82 sysfatal("cannot get key - %r"); 83 84 ap = emalloc9p(sizeof(Auth)); 85 memset(ap, 0, sizeof(ap)); 86 ap->user = estrdup9p(user); 87 ap->windom = estrdup9p(windom); 88 89 /* LM response */ 90 ap->len[0] = sizeof(mcr.LMresp); 91 ap->resp[0] = emalloc9p(ap->len[0]); 92 memcpy(ap->resp[0], mcr.LMresp, ap->len[0]); 93 94 /* NTLM response */ 95 ap->len[1] = sizeof(mcr.NTresp); 96 ap->resp[1] = emalloc9p(ap->len[1]); 97 memcpy(ap->resp[1], mcr.NTresp, ap->len[1]); 98 99 return ap; 100 } 101 102 /* 103 * NTLM response only, the LM response is a just 104 * copy of the NTLM one. We do this because the lm 105 * response is easily reversed - Google for l0pht for more info. 106 */ 107 static Auth * 108 auth_ntlm(char *windom, char *keyp, uchar *chal, int len) 109 { 110 Auth *ap; 111 112 if((ap = auth_lm_and_ntlm(windom, keyp, chal, len)) == nil) 113 return nil; 114 115 free(ap->resp[0]); 116 ap->len[0] = ap->len[1]; 117 ap->resp[0] = emalloc9p(ap->len[0]); 118 memcpy(ap->resp[0], ap->resp[1], ap->len[0]); 119 return ap; 120 } 121 122 /* 123 * This is not really nescessary as all fields hmac_md5'ed 124 * in the ntlmv2 protocol are less than 64 bytes long, however 125 * I still do this for completeness. 126 */ 127 static DigestState * 128 hmac_t64(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest, 129 DigestState *state) 130 { 131 if(klen > 64) 132 klen = 64; 133 return hmac_md5(data, dlen, key, klen, digest, state); 134 } 135 136 137 static int 138 ntv2_blob(uchar *blob, int len, char *windom) 139 { 140 int n; 141 uvlong nttime; 142 Rune r; 143 char *d; 144 uchar *p; 145 enum { /* name types */ 146 Beof, /* end of name list */ 147 Bnetbios, /* Netbios machine name */ 148 Bdomain, /* Windows Domain name (NT) */ 149 Bdnsfqdn, /* DNS Fully Qualified Domain Name */ 150 Bdnsname, /* DNS machine name (win2k) */ 151 }; 152 153 p = blob; 154 *p++ = 1; /* response type */ 155 *p++ = 1; /* max response type understood by client */ 156 157 *p++ = 0; 158 *p++ = 0; /* 2 bytes reserved */ 159 160 *p++ = 0; 161 *p++ = 0; 162 *p++ = 0; 163 *p++ = 0; /* 4 bytes unknown */ 164 165 #ifdef NTLMV2_TEST 166 *p++ = 0xf0; 167 *p++ = 0x20; 168 *p++ = 0xd0; 169 *p++ = 0xb6; 170 *p++ = 0xc2; 171 *p++ = 0x92; 172 *p++ = 0xbe; 173 *p++ = 0x01; 174 #else 175 nttime = time(nil); /* nt time now */ 176 nttime = nttime + 11644473600LL; 177 nttime = nttime * 10000000LL; 178 *p++ = nttime & 0xff; 179 *p++ = (nttime >> 8) & 0xff; 180 *p++ = (nttime >> 16) & 0xff; 181 *p++ = (nttime >> 24) & 0xff; 182 *p++ = (nttime >> 32) & 0xff; 183 *p++ = (nttime >> 40) & 0xff; 184 *p++ = (nttime >> 48) & 0xff; 185 *p++ = (nttime >> 56) & 0xff; 186 #endif 187 #ifdef NTLMV2_TEST 188 *p++ = 0x05; 189 *p++ = 0x83; 190 *p++ = 0x32; 191 *p++ = 0xec; 192 *p++ = 0xfa; 193 *p++ = 0xe4; 194 *p++ = 0xf3; 195 *p++ = 0x6d; 196 #else 197 genrandom(p, 8); 198 p += 8; /* client nonce */ 199 #endif 200 *p++ = 0x6f; 201 *p++ = 0; 202 *p++ = 0x6e; 203 *p++ = 0; /* unknown data */ 204 205 *p++ = Bdomain; 206 *p++ = 0; /* name type */ 207 208 n = utflen(windom) * 2; 209 *p++ = n; 210 *p++ = n >> 8; /* name length */ 211 212 d = windom; 213 while(*d && p - blob < len - 8){ 214 d += chartorune(&r, d); 215 r = toupperrune(r); 216 *p++ = r; 217 *p++ = r >> 8; 218 } 219 220 *p++ = 0; 221 *p++ = Beof; /* name type */ 222 223 *p++ = 0; 224 *p++ = 0; /* name length */ 225 226 *p++ = 0x65; 227 *p++ = 0; 228 *p++ = 0; 229 *p++ = 0; /* unknown data */ 230 return p - blob; 231 } 232 233 static Auth * 234 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len) 235 { 236 int i, n; 237 Rune r; 238 char *p, *u; 239 uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen]; 240 uchar lm_sesskey[MD5dlen]; 241 uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen]; 242 DigestState *ds; 243 UserPasswd *up; 244 static Auth *ap; 245 246 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s", 247 windom, keyp); 248 if(! up) 249 sysfatal("cannot get key - %r"); 250 251 #ifdef NTLMV2_TEST 252 { 253 static uchar srvchal[] = { 0x52, 0xaa, 0xc8, 0xe8, 0x2c, 0x06, 0x7f, 0xa1 }; 254 up->user = "ADMINISTRATOR"; 255 windom = "rocknroll"; 256 chal = srvchal; 257 } 258 #endif 259 ap = emalloc9p(sizeof(Auth)); 260 memset(ap, 0, sizeof(ap)); 261 262 /* Standard says unlimited length, experience says 128 max */ 263 if((n = strlen(up->passwd)) > 128) 264 n = 128; 265 266 ds = md4(nil, 0, nil, nil); 267 for(i = 0, p = up->passwd; i < n; i++) { 268 p += chartorune(&r, p); 269 c = r; 270 md4(&c, 1, nil, ds); 271 c = r >> 8; 272 md4(&c, 1, nil, ds); 273 } 274 md4(nil, 0, v1hash, ds); 275 276 #ifdef NTLMV2_TEST 277 { 278 uchar v1[] = { 279 0x0c, 0xb6, 0x94, 0x88, 0x05, 0xf7, 0x97, 0xbf, 280 0x2a, 0x82, 0x80, 0x79, 0x73, 0xb8, 0x95, 0x37 281 ; 282 memcpy(v1hash, v1, sizeof(v1)); 283 } 284 #endif 285 /* 286 * Some documentation insists that the username must be forced to 287 * uppercase, but the domain name should not be. Other shows both 288 * being forced to uppercase. I am pretty sure this is irrevevant as 289 * the domain name passed from the remote server always seems to be in 290 * uppercase already. 291 */ 292 ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil); 293 u = up->user; 294 while(*u){ 295 u += chartorune(&r, u); 296 r = toupperrune(r); 297 c = r & 0xff; 298 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 299 c = r >> 8; 300 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 301 } 302 u = windom; 303 304 while(*u){ 305 u += chartorune(&r, u); 306 c = r; 307 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 308 c = r >> 8; 309 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 310 } 311 hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds); 312 #ifdef NTLMV2_TEST 313 print("want: 40 e1 b3 24...\n"); 314 dmp("v2hash==kr", 0, v2hash, MD5dlen); 315 #endif 316 ap->user = estrdup9p(up->user); 317 ap->windom = estrdup9p(windom); 318 319 /* LM v2 */ 320 321 genrandom(blip, Bliplen); 322 #ifdef NTLMV2_TEST 323 { 324 uchar t[] = { 0x05, 0x83, 0x32, 0xec, 0xfa, 0xe4, 0xf3, 0x6d }; 325 memcpy(blip, t, 8); 326 } 327 #endif 328 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil); 329 hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds); 330 ap->len[0] = MD5dlen+Bliplen; 331 ap->resp[0] = emalloc9p(ap->len[0]); 332 memcpy(ap->resp[0], lm_hmac, MD5dlen); 333 memcpy(ap->resp[0]+MD5dlen, blip, Bliplen); 334 #ifdef NTLMV2_TEST 335 print("want: 38 6b ae...\n"); 336 dmp("lmv2 resp ", 0, lm_hmac, MD5dlen); 337 #endif 338 339 /* LM v2 session key */ 340 hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil); 341 342 /* LM v2 MAC key */ 343 ap->mackey[0] = emalloc9p(MACkeylen); 344 memcpy(ap->mackey[0], lm_sesskey, MD5dlen); 345 memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen); 346 347 /* NTLM v2 */ 348 n = ntv2_blob(blob, sizeof(blob), windom); 349 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil); 350 hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds); 351 ap->len[1] = MD5dlen+n; 352 ap->resp[1] = emalloc9p(ap->len[1]); 353 memcpy(ap->resp[1], nt_hmac, MD5dlen); 354 memcpy(ap->resp[1]+MD5dlen, blob, n); 355 #ifdef NTLMV2_TEST 356 print("want: 1a ad 55...\n"); 357 dmp("ntv2 resp ", 0, nt_hmac, MD5dlen); 358 #endif 359 360 /* NTLM v2 session key */ 361 hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil); 362 363 /* NTLM v2 MAC key */ 364 ap->mackey[1] = emalloc9p(MACkeylen); 365 memcpy(ap->mackey[1], nt_sesskey, MD5dlen); 366 memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen); 367 free(up); 368 369 return ap; 370 } 371 372 struct { 373 char *name; 374 Auth *(*func)(char *, char *, uchar *, int); 375 } methods[] = { 376 { "plain", auth_plain }, 377 { "lm+ntlm", auth_lm_and_ntlm }, 378 { "ntlm", auth_ntlm }, 379 { "ntlmv2", auth_ntlmv2 }, 380 // { "kerberos", auth_kerberos }, 381 }; 382 383 void 384 autherr(void) 385 { 386 int i; 387 388 fprint(2, "supported auth methods:\t"); 389 for(i = 0; i < nelem(methods); i++) 390 fprint(2, "%s ", methods[i].name); 391 fprint(2, "\n"); 392 exits("usage"); 393 } 394 395 Auth * 396 getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len) 397 { 398 int i; 399 Auth *ap; 400 401 if(name == nil){ 402 name = DEF_AUTH; 403 if((secmode & SECMODE_PW_ENCRYPT) == 0) 404 sysfatal("plaintext authentication required, use '-a plain'"); 405 } 406 407 ap = nil; 408 for(i = 0; i < nelem(methods); i++) 409 if(strcmp(methods[i].name, name) == 0){ 410 ap = methods[i].func(windom, keyp, chal, len); 411 break; 412 } 413 414 if(! ap){ 415 fprint(2, "%s: %s - unknown auth method\n", argv0, name); 416 autherr(); /* never returns */ 417 } 418 return ap; 419 } 420 421 static int 422 genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar mine[MAClen]) 423 { 424 DigestState *ds; 425 uchar *sig, digest[MD5dlen], their[MAClen]; 426 427 sig = buf+MACoff; 428 memcpy(their, sig, MAClen); 429 memset(sig, 0, MAClen); 430 sig[0] = seq; 431 sig[1] = seq >> 8; 432 sig[2] = seq >> 16; 433 sig[3] = seq >> 24; 434 435 ds = md5(key, MACkeylen, nil, nil); 436 md5(buf, len, nil, ds); 437 md5(nil, 0, digest, ds); 438 memcpy(mine, digest, MAClen); 439 440 return memcmp(their, mine, MAClen); 441 } 442 443 int 444 macsign(Pkt *p) 445 { 446 int i, len; 447 uchar *sig, *buf, mac[MAClen], zeros[MACkeylen]; 448 449 sig = p->buf + NBHDRLEN + MACoff; 450 buf = p->buf + NBHDRLEN; 451 len = (p->pos - p->buf) - NBHDRLEN; 452 453 for(i = -3; i < 4; i++){ 454 memset(zeros, 0, sizeof(zeros)); 455 if(genmac(buf, len, p->seq+i, zeros, mac) == 0){ 456 dmp("got", 0, buf, len); 457 dmp("Zero OK", p->seq, mac, MAClen); 458 return 0; 459 } 460 461 if(genmac(buf, len, p->seq+i, p->s->auth->mackey[0], mac) == 0){ 462 dmp("got", 0, buf, len); 463 dmp("LM-hash OK", p->seq, mac, MAClen); 464 return 0; 465 } 466 467 if(genmac(buf, len, p->seq+i, p->s->auth->mackey[1], mac) == 0){ 468 dmp("got", 0, buf, len); 469 dmp("NT-hash OK", p->seq, mac, MAClen); 470 return 0; 471 } 472 } 473 genmac(buf, len, p->seq, p->s->auth->mackey[0], mac); 474 475 memcpy(sig, mac, MAClen); 476 return -1; 477 } 478