ReadNTLM.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include "plbase64.h"
  8. #include "nsStringAPI.h"
  9. #include "prmem.h"
  10. /*
  11. * ReadNTLM : reads NTLM messages.
  12. *
  13. * based on http://davenport.sourceforge.net/ntlm.html
  14. */
  15. #define kNegotiateUnicode 0x00000001
  16. #define kNegotiateOEM 0x00000002
  17. #define kRequestTarget 0x00000004
  18. #define kUnknown1 0x00000008
  19. #define kNegotiateSign 0x00000010
  20. #define kNegotiateSeal 0x00000020
  21. #define kNegotiateDatagramStyle 0x00000040
  22. #define kNegotiateLanManagerKey 0x00000080
  23. #define kNegotiateNetware 0x00000100
  24. #define kNegotiateNTLMKey 0x00000200
  25. #define kUnknown2 0x00000400
  26. #define kUnknown3 0x00000800
  27. #define kNegotiateDomainSupplied 0x00001000
  28. #define kNegotiateWorkstationSupplied 0x00002000
  29. #define kNegotiateLocalCall 0x00004000
  30. #define kNegotiateAlwaysSign 0x00008000
  31. #define kTargetTypeDomain 0x00010000
  32. #define kTargetTypeServer 0x00020000
  33. #define kTargetTypeShare 0x00040000
  34. #define kNegotiateNTLM2Key 0x00080000
  35. #define kRequestInitResponse 0x00100000
  36. #define kRequestAcceptResponse 0x00200000
  37. #define kRequestNonNTSessionKey 0x00400000
  38. #define kNegotiateTargetInfo 0x00800000
  39. #define kUnknown4 0x01000000
  40. #define kUnknown5 0x02000000
  41. #define kUnknown6 0x04000000
  42. #define kUnknown7 0x08000000
  43. #define kUnknown8 0x10000000
  44. #define kNegotiate128 0x20000000
  45. #define kNegotiateKeyExchange 0x40000000
  46. #define kNegotiate56 0x80000000
  47. static const char NTLM_SIGNATURE[] = "NTLMSSP";
  48. static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
  49. static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
  50. static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
  51. #define NTLM_MARKER_LEN 4
  52. #define NTLM_TYPE1_HEADER_LEN 32
  53. #define NTLM_TYPE2_HEADER_LEN 32
  54. #define NTLM_TYPE3_HEADER_LEN 64
  55. #define LM_HASH_LEN 16
  56. #define LM_RESP_LEN 24
  57. #define NTLM_HASH_LEN 16
  58. #define NTLM_RESP_LEN 24
  59. static void PrintFlags(uint32_t flags)
  60. {
  61. #define TEST(_flag) \
  62. if (flags & k ## _flag) \
  63. printf(" 0x%08x (" # _flag ")\n", k ## _flag)
  64. TEST(NegotiateUnicode);
  65. TEST(NegotiateOEM);
  66. TEST(RequestTarget);
  67. TEST(Unknown1);
  68. TEST(NegotiateSign);
  69. TEST(NegotiateSeal);
  70. TEST(NegotiateDatagramStyle);
  71. TEST(NegotiateLanManagerKey);
  72. TEST(NegotiateNetware);
  73. TEST(NegotiateNTLMKey);
  74. TEST(Unknown2);
  75. TEST(Unknown3);
  76. TEST(NegotiateDomainSupplied);
  77. TEST(NegotiateWorkstationSupplied);
  78. TEST(NegotiateLocalCall);
  79. TEST(NegotiateAlwaysSign);
  80. TEST(TargetTypeDomain);
  81. TEST(TargetTypeServer);
  82. TEST(TargetTypeShare);
  83. TEST(NegotiateNTLM2Key);
  84. TEST(RequestInitResponse);
  85. TEST(RequestAcceptResponse);
  86. TEST(RequestNonNTSessionKey);
  87. TEST(NegotiateTargetInfo);
  88. TEST(Unknown4);
  89. TEST(Unknown5);
  90. TEST(Unknown6);
  91. TEST(Unknown7);
  92. TEST(Unknown8);
  93. TEST(Negotiate128);
  94. TEST(NegotiateKeyExchange);
  95. TEST(Negotiate56);
  96. #undef TEST
  97. }
  98. static void
  99. PrintBuf(const char *tag, const uint8_t *buf, uint32_t bufLen)
  100. {
  101. int i;
  102. printf("%s =\n", tag);
  103. while (bufLen > 0)
  104. {
  105. int count = bufLen;
  106. if (count > 8)
  107. count = 8;
  108. printf(" ");
  109. for (i=0; i<count; ++i)
  110. {
  111. printf("0x%02x ", int(buf[i]));
  112. }
  113. for (; i<8; ++i)
  114. {
  115. printf(" ");
  116. }
  117. printf(" ");
  118. for (i=0; i<count; ++i)
  119. {
  120. if (isprint(buf[i]))
  121. printf("%c", buf[i]);
  122. else
  123. printf(".");
  124. }
  125. printf("\n");
  126. bufLen -= count;
  127. buf += count;
  128. }
  129. }
  130. static uint16_t
  131. ReadUint16(const uint8_t *&buf)
  132. {
  133. uint16_t x;
  134. #ifdef IS_BIG_ENDIAN
  135. x = ((uint16_t) buf[1]) | ((uint16_t) buf[0] << 8);
  136. #else
  137. x = ((uint16_t) buf[0]) | ((uint16_t) buf[1] << 8);
  138. #endif
  139. buf += sizeof(x);
  140. return x;
  141. }
  142. static uint32_t
  143. ReadUint32(const uint8_t *&buf)
  144. {
  145. uint32_t x;
  146. #ifdef IS_BIG_ENDIAN
  147. x = ( (uint32_t) buf[3]) |
  148. (((uint32_t) buf[2]) << 8) |
  149. (((uint32_t) buf[1]) << 16) |
  150. (((uint32_t) buf[0]) << 24);
  151. #else
  152. x = ( (uint32_t) buf[0]) |
  153. (((uint32_t) buf[1]) << 8) |
  154. (((uint32_t) buf[2]) << 16) |
  155. (((uint32_t) buf[3]) << 24);
  156. #endif
  157. buf += sizeof(x);
  158. return x;
  159. }
  160. typedef struct {
  161. uint16_t length;
  162. uint16_t capacity;
  163. uint32_t offset;
  164. } SecBuf;
  165. static void
  166. ReadSecBuf(SecBuf *s, const uint8_t *&buf)
  167. {
  168. s->length = ReadUint16(buf);
  169. s->capacity = ReadUint16(buf);
  170. s->offset = ReadUint32(buf);
  171. }
  172. static void
  173. ReadType1MsgBody(const uint8_t *inBuf, uint32_t start)
  174. {
  175. const uint8_t *cursor = inBuf + start;
  176. uint32_t flags;
  177. PrintBuf("flags", cursor, 4);
  178. // read flags
  179. flags = ReadUint32(cursor);
  180. PrintFlags(flags);
  181. // type 1 message may not include trailing security buffers
  182. if ((flags & kNegotiateDomainSupplied) |
  183. (flags & kNegotiateWorkstationSupplied))
  184. {
  185. SecBuf secbuf;
  186. ReadSecBuf(&secbuf, cursor);
  187. PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
  188. ReadSecBuf(&secbuf, cursor);
  189. PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
  190. }
  191. }
  192. static void
  193. ReadType2MsgBody(const uint8_t *inBuf, uint32_t start)
  194. {
  195. uint16_t targetLen, offset;
  196. uint32_t flags;
  197. const uint8_t *target;
  198. const uint8_t *cursor = inBuf + start;
  199. // read target name security buffer
  200. targetLen = ReadUint16(cursor);
  201. ReadUint16(cursor); // discard next 16-bit value
  202. offset = ReadUint32(cursor); // get offset from inBuf
  203. target = inBuf + offset;
  204. PrintBuf("target", target, targetLen);
  205. PrintBuf("flags", cursor, 4);
  206. // read flags
  207. flags = ReadUint32(cursor);
  208. PrintFlags(flags);
  209. // read challenge
  210. PrintBuf("challenge", cursor, 8);
  211. cursor += 8;
  212. PrintBuf("context", cursor, 8);
  213. cursor += 8;
  214. SecBuf secbuf;
  215. ReadSecBuf(&secbuf, cursor);
  216. PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
  217. }
  218. static void
  219. ReadType3MsgBody(const uint8_t *inBuf, uint32_t start)
  220. {
  221. const uint8_t *cursor = inBuf + start;
  222. SecBuf secbuf;
  223. ReadSecBuf(&secbuf, cursor); // LM response
  224. PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
  225. ReadSecBuf(&secbuf, cursor); // NTLM response
  226. PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
  227. ReadSecBuf(&secbuf, cursor); // domain name
  228. PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
  229. ReadSecBuf(&secbuf, cursor); // user name
  230. PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
  231. ReadSecBuf(&secbuf, cursor); // workstation name
  232. PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
  233. ReadSecBuf(&secbuf, cursor); // session key
  234. PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
  235. uint32_t flags = ReadUint32(cursor);
  236. PrintBuf("flags", (const uint8_t *) &flags, sizeof(flags));
  237. PrintFlags(flags);
  238. }
  239. static void
  240. ReadMsg(const char *base64buf, uint32_t bufLen)
  241. {
  242. uint8_t *inBuf = (uint8_t *) PL_Base64Decode(base64buf, bufLen, nullptr);
  243. if (!inBuf)
  244. {
  245. printf("PL_Base64Decode failed\n");
  246. return;
  247. }
  248. const uint8_t *cursor = inBuf;
  249. PrintBuf("signature", cursor, 8);
  250. // verify NTLMSSP signature
  251. if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
  252. {
  253. printf("### invalid or corrupt NTLM signature\n");
  254. }
  255. cursor += sizeof(NTLM_SIGNATURE);
  256. PrintBuf("message type", cursor, 4);
  257. if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
  258. ReadType1MsgBody(inBuf, 12);
  259. else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
  260. ReadType2MsgBody(inBuf, 12);
  261. else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
  262. ReadType3MsgBody(inBuf, 12);
  263. else
  264. printf("### invalid or unknown message type\n");
  265. PR_Free(inBuf);
  266. }
  267. int main(int argc, char **argv)
  268. {
  269. if (argc == 1)
  270. {
  271. printf("usage: ntlmread <msg>\n");
  272. return -1;
  273. }
  274. ReadMsg(argv[1], (uint32_t) strlen(argv[1]));
  275. return 0;
  276. }