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 DEF_AUTH "ntlmv2" 19 20 static enum { 21 MACkeylen = 40, /* MAC key len */ 22 MAClen = 8, /* signature length */ 23 MACoff = 14, /* sign. offset from start of SMB (not netbios) pkt */ 24 Bliplen = 8, /* size of LMv2 client nonce */ 25 }; 26 27 static void 28 dmp(char *s, int seq, void *buf, int n) 29 { 30 int i; 31 char *p = buf; 32 33 print("%s %3d ", s, seq); 34 while(n > 0){ 35 for(i = 0; i < 16 && n > 0; i++, n--) 36 print("%02x ", *p++ & 0xff); 37 if(n > 0) 38 print("\n"); 39 } 40 print("\n"); 41 } 42 43 static Auth * 44 auth_plain(char *windom, char *keyp, uchar *chal, int len) 45 { 46 UserPasswd *up; 47 static Auth *ap; 48 49 USED(chal, len); 50 51 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s", 52 windom, keyp); 53 if(! up) 54 sysfatal("cannot get key - %r"); 55 56 ap = emalloc9p(sizeof(Auth)); 57 memset(ap, 0, sizeof(ap)); 58 ap->user = estrdup9p(up->user); 59 ap->windom = estrdup9p(windom); 60 61 ap->resp[0] = estrdup9p(up->passwd); 62 ap->len[0] = strlen(up->passwd); 63 memset(up->passwd, 0, strlen(up->passwd)); 64 free(up); 65 66 return ap; 67 } 68 69 static Auth * 70 auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len) 71 { 72 int err; 73 char user[64]; 74 Auth *ap; 75 MSchapreply mcr; 76 77 err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr, 78 auth_getkey, "windom=%s proto=mschap role=client service=cifs %s", 79 windom, keyp); 80 if(err == -1) 81 sysfatal("cannot get key - %r"); 82 83 ap = emalloc9p(sizeof(Auth)); 84 memset(ap, 0, sizeof(ap)); 85 ap->user = estrdup9p(user); 86 ap->windom = estrdup9p(windom); 87 88 /* LM response */ 89 ap->len[0] = sizeof(mcr.LMresp); 90 ap->resp[0] = emalloc9p(ap->len[0]); 91 memcpy(ap->resp[0], mcr.LMresp, ap->len[0]); 92 93 /* NTLM response */ 94 ap->len[1] = sizeof(mcr.NTresp); 95 ap->resp[1] = emalloc9p(ap->len[1]); 96 memcpy(ap->resp[1], mcr.NTresp, ap->len[1]); 97 98 return ap; 99 } 100 101 /* 102 * NTLM response only, the LM response is a just 103 * copy of the NTLM one. we do this because the lm 104 * response is easily reversed - Google for l0pht 105 * 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 nttime = time(nil); /* nt time now */ 166 nttime += 11644473600LL; 167 nttime *= 10000000LL; 168 *p++ = nttime; 169 *p++ = nttime >> 8; 170 *p++ = nttime >> 16; 171 *p++ = nttime >> 24; 172 *p++ = nttime >> 32; 173 *p++ = nttime >> 40; 174 *p++ = nttime >> 48; 175 *p++ = nttime >> 56; 176 177 genrandom(p, 8); 178 p += 8; /* client nonce */ 179 *p++ = 0x6f; 180 *p++ = 0; 181 *p++ = 0x6e; 182 *p++ = 0; /* unknown data */ 183 184 *p++ = Bdomain; 185 *p++ = 0; /* name type */ 186 187 n = utflen(windom) * 2; 188 *p++ = n; 189 *p++ = n >> 8; /* name length */ 190 191 d = windom; 192 while(*d && p-blob < (len-8)){ 193 d += chartorune(&r, d); 194 r = toupperrune(r); 195 *p++ = r; 196 *p++ = r >> 8; 197 } 198 199 *p++ = 0; 200 *p++ = Beof; /* name type */ 201 202 *p++ = 0; 203 *p++ = 0; /* name length */ 204 205 *p++ = 0x65; 206 *p++ = 0; 207 *p++ = 0; 208 *p++ = 0; /* unknown data */ 209 return p - blob; 210 } 211 212 static Auth * 213 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len) 214 { 215 int i, n; 216 Rune r; 217 char *p, *u; 218 uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen]; 219 uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen], 220 lm_sesskey[MD5dlen]; 221 DigestState *ds; 222 UserPasswd *up; 223 static Auth *ap; 224 225 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s", 226 windom, keyp); 227 if(!up) 228 sysfatal("cannot get key - %r"); 229 230 ap = emalloc9p(sizeof(Auth)); 231 memset(ap, 0, sizeof(ap)); 232 233 /* Standard says unlimited length, experience says 128 max */ 234 if((n = strlen(up->passwd)) > 128) 235 n = 128; 236 237 ds = md4(nil, 0, nil, nil); 238 for(i=0, p=up->passwd; i < n; i++) { 239 p += chartorune(&r, p); 240 c = r; 241 md4(&c, 1, nil, ds); 242 c = r >> 8; 243 md4(&c, 1, nil, ds); 244 } 245 md4(nil, 0, v1hash, ds); 246 247 /* 248 * Some documentation insists that the username must be forced to 249 * uppercase, but the domain name should not be. Other shows both 250 * being forced to uppercase. I am pretty sure this is irrevevant as the 251 * domain name passed from the remote server always seems to be in 252 * uppercase already. 253 */ 254 ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil); 255 u = up->user; 256 while(*u){ 257 u += chartorune(&r, u); 258 r = toupperrune(r); 259 c = r; 260 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 261 c = r >> 8; 262 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 263 } 264 u = windom; 265 266 while(*u){ 267 u += chartorune(&r, u); 268 c = r; 269 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 270 c = r >> 8; 271 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds); 272 } 273 hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds); 274 ap->user = estrdup9p(up->user); 275 ap->windom = estrdup9p(windom); 276 277 /* LM v2 */ 278 279 genrandom(blip, Bliplen); 280 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil); 281 hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds); 282 ap->len[0] = MD5dlen+Bliplen; 283 ap->resp[0] = emalloc9p(ap->len[0]); 284 memcpy(ap->resp[0], lm_hmac, MD5dlen); 285 memcpy(ap->resp[0]+MD5dlen, blip, Bliplen); 286 287 /* LM v2 session key */ 288 hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil); 289 290 /* LM v2 MAC key */ 291 ap->mackey[0] = emalloc9p(MACkeylen); 292 memcpy(ap->mackey[0], lm_sesskey, MD5dlen); 293 memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen); 294 295 /* NTLM v2 */ 296 n = ntv2_blob(blob, sizeof(blob), windom); 297 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil); 298 hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds); 299 ap->len[1] = MD5dlen+n; 300 ap->resp[1] = emalloc9p(ap->len[1]); 301 memcpy(ap->resp[1], nt_hmac, MD5dlen); 302 memcpy(ap->resp[1]+MD5dlen, blob, n); 303 304 /* 305 * v2hash definitely OK by 306 * the time we get here. 307 */ 308 /* NTLM v2 session key */ 309 hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil); 310 311 /* NTLM v2 MAC key */ 312 ap->mackey[1] = emalloc9p(MACkeylen); 313 memcpy(ap->mackey[1], nt_sesskey, MD5dlen); 314 memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen); 315 free(up); 316 317 return ap; 318 } 319 320 struct { 321 char *name; 322 Auth *(*func)(char *, char *, uchar *, int); 323 } methods[] = { 324 { "plain", auth_plain }, 325 { "lm+ntlm", auth_lm_and_ntlm }, 326 { "ntlm", auth_ntlm }, 327 { "ntlmv2", auth_ntlmv2 }, 328 // { "kerberos", auth_kerberos }, 329 }; 330 331 void 332 autherr(void) 333 { 334 int i; 335 336 fprint(2, "supported auth methods:\t"); 337 for(i = 0; i < nelem(methods); i++) 338 fprint(2, "%s ", methods[i].name); 339 fprint(2, "\n"); 340 exits("usage"); 341 } 342 343 Auth * 344 getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len) 345 { 346 int i; 347 Auth *ap; 348 349 if(name == nil){ 350 name = DEF_AUTH; 351 if((secmode & SECMODE_PW_ENCRYPT) == 0) 352 sysfatal("plaintext authentication required, use '-a plain'"); 353 } 354 355 ap = nil; 356 for(i = 0; i < nelem(methods); i++) 357 if(strcmp(methods[i].name, name) == 0){ 358 ap = methods[i].func(windom, keyp, chal, len); 359 break; 360 } 361 362 if(! ap){ 363 fprint(2, "%s: %s - unknown auth method\n", argv0, name); 364 autherr(); /* never returns */ 365 } 366 return ap; 367 } 368 369 static int 370 genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar ours[MAClen]) 371 { 372 DigestState *ds; 373 uchar *sig, digest[MD5dlen], theirs[MAClen]; 374 375 sig = buf+MACoff; 376 memcpy(theirs, sig, MAClen); 377 378 memset(sig, 0, MAClen); 379 sig[0] = seq; 380 sig[1] = seq >> 8; 381 sig[2] = seq >> 16; 382 sig[3] = seq >> 24; 383 384 ds = md5(key, MACkeylen, nil, nil); 385 md5(buf, len, digest, ds); 386 memcpy(ours, digest, MAClen); 387 388 return memcmp(theirs, ours, MAClen); 389 } 390 391 int 392 macsign(Pkt *p, int seq) 393 { 394 int rc, len; 395 uchar *sig, *buf, mac[MAClen]; 396 397 sig = p->buf + NBHDRLEN + MACoff; 398 buf = p->buf + NBHDRLEN; 399 len = (p->pos - p->buf) - NBHDRLEN; 400 401 #ifdef DEBUG_MAC 402 if(seq & 1) 403 dmp("rx", seq, sig, MAClen); 404 #endif 405 rc = 0; 406 if(! p->s->seqrun) 407 memcpy(mac, "BSRSPYL ", 8); /* no idea, ask MS */ 408 else 409 rc = genmac(buf, len, seq, p->s->auth->mackey[0], mac); 410 #ifdef DEBUG_MAC 411 if(!(seq & 1)) 412 dmp("tx", seq, mac, MAClen); 413 #endif 414 memcpy(sig, mac, MAClen); 415 return rc; 416 } 417