netwerk/test/ReadNTLM.cpp

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial