auth-testcase.C 11 KB

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