netwerk/test/ReadNTLM.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/test/ReadNTLM.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,325 @@
     1.4 +/* vim: set ts=2 sw=2 et cindent: */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <stdlib.h>
    1.10 +#include <stdio.h>
    1.11 +#include <ctype.h>
    1.12 +
    1.13 +#include "plbase64.h"
    1.14 +#include "nsStringAPI.h"
    1.15 +#include "prmem.h"
    1.16 +
    1.17 +/*
    1.18 + * ReadNTLM : reads NTLM messages.
    1.19 + *
    1.20 + * based on http://davenport.sourceforge.net/ntlm.html
    1.21 + */
    1.22 +
    1.23 +#define kNegotiateUnicode               0x00000001
    1.24 +#define kNegotiateOEM                   0x00000002
    1.25 +#define kRequestTarget                  0x00000004
    1.26 +#define kUnknown1                       0x00000008
    1.27 +#define kNegotiateSign                  0x00000010
    1.28 +#define kNegotiateSeal                  0x00000020
    1.29 +#define kNegotiateDatagramStyle         0x00000040
    1.30 +#define kNegotiateLanManagerKey         0x00000080
    1.31 +#define kNegotiateNetware               0x00000100
    1.32 +#define kNegotiateNTLMKey               0x00000200
    1.33 +#define kUnknown2                       0x00000400
    1.34 +#define kUnknown3                       0x00000800
    1.35 +#define kNegotiateDomainSupplied        0x00001000
    1.36 +#define kNegotiateWorkstationSupplied   0x00002000
    1.37 +#define kNegotiateLocalCall             0x00004000
    1.38 +#define kNegotiateAlwaysSign            0x00008000
    1.39 +#define kTargetTypeDomain               0x00010000
    1.40 +#define kTargetTypeServer               0x00020000
    1.41 +#define kTargetTypeShare                0x00040000
    1.42 +#define kNegotiateNTLM2Key              0x00080000
    1.43 +#define kRequestInitResponse            0x00100000
    1.44 +#define kRequestAcceptResponse          0x00200000
    1.45 +#define kRequestNonNTSessionKey         0x00400000
    1.46 +#define kNegotiateTargetInfo            0x00800000
    1.47 +#define kUnknown4                       0x01000000
    1.48 +#define kUnknown5                       0x02000000
    1.49 +#define kUnknown6                       0x04000000
    1.50 +#define kUnknown7                       0x08000000
    1.51 +#define kUnknown8                       0x10000000
    1.52 +#define kNegotiate128                   0x20000000
    1.53 +#define kNegotiateKeyExchange           0x40000000
    1.54 +#define kNegotiate56                    0x80000000
    1.55 +
    1.56 +static const char NTLM_SIGNATURE[] = "NTLMSSP";
    1.57 +static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
    1.58 +static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
    1.59 +static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
    1.60 +
    1.61 +#define NTLM_MARKER_LEN 4
    1.62 +#define NTLM_TYPE1_HEADER_LEN 32
    1.63 +#define NTLM_TYPE2_HEADER_LEN 32
    1.64 +#define NTLM_TYPE3_HEADER_LEN 64
    1.65 +
    1.66 +#define LM_HASH_LEN 16
    1.67 +#define LM_RESP_LEN 24
    1.68 +
    1.69 +#define NTLM_HASH_LEN 16
    1.70 +#define NTLM_RESP_LEN 24
    1.71 +
    1.72 +static void PrintFlags(uint32_t flags)
    1.73 +{
    1.74 +#define TEST(_flag) \
    1.75 +  if (flags & k ## _flag) \
    1.76 +    printf("    0x%08x (" # _flag ")\n", k ## _flag)
    1.77 +
    1.78 +  TEST(NegotiateUnicode);
    1.79 +  TEST(NegotiateOEM);
    1.80 +  TEST(RequestTarget);
    1.81 +  TEST(Unknown1);
    1.82 +  TEST(NegotiateSign);
    1.83 +  TEST(NegotiateSeal);
    1.84 +  TEST(NegotiateDatagramStyle);
    1.85 +  TEST(NegotiateLanManagerKey);
    1.86 +  TEST(NegotiateNetware);
    1.87 +  TEST(NegotiateNTLMKey);
    1.88 +  TEST(Unknown2);
    1.89 +  TEST(Unknown3);
    1.90 +  TEST(NegotiateDomainSupplied);
    1.91 +  TEST(NegotiateWorkstationSupplied);
    1.92 +  TEST(NegotiateLocalCall);
    1.93 +  TEST(NegotiateAlwaysSign);
    1.94 +  TEST(TargetTypeDomain);
    1.95 +  TEST(TargetTypeServer);
    1.96 +  TEST(TargetTypeShare);
    1.97 +  TEST(NegotiateNTLM2Key);
    1.98 +  TEST(RequestInitResponse);
    1.99 +  TEST(RequestAcceptResponse);
   1.100 +  TEST(RequestNonNTSessionKey);
   1.101 +  TEST(NegotiateTargetInfo);
   1.102 +  TEST(Unknown4);
   1.103 +  TEST(Unknown5);
   1.104 +  TEST(Unknown6);
   1.105 +  TEST(Unknown7);
   1.106 +  TEST(Unknown8);
   1.107 +  TEST(Negotiate128);
   1.108 +  TEST(NegotiateKeyExchange);
   1.109 +  TEST(Negotiate56);
   1.110 +
   1.111 +#undef TEST
   1.112 +}
   1.113 +
   1.114 +static void
   1.115 +PrintBuf(const char *tag, const uint8_t *buf, uint32_t bufLen)
   1.116 +{
   1.117 +  int i;
   1.118 +
   1.119 +  printf("%s =\n", tag);
   1.120 +  while (bufLen > 0)
   1.121 +  {
   1.122 +    int count = bufLen;
   1.123 +    if (count > 8)
   1.124 +      count = 8;
   1.125 +
   1.126 +    printf("    ");
   1.127 +    for (i=0; i<count; ++i)
   1.128 +    {
   1.129 +      printf("0x%02x ", int(buf[i]));
   1.130 +    }
   1.131 +    for (; i<8; ++i)
   1.132 +    {
   1.133 +      printf("     ");
   1.134 +    }
   1.135 +
   1.136 +    printf("   ");
   1.137 +    for (i=0; i<count; ++i)
   1.138 +    {
   1.139 +      if (isprint(buf[i]))
   1.140 +        printf("%c", buf[i]);
   1.141 +      else
   1.142 +        printf(".");
   1.143 +    }
   1.144 +    printf("\n");
   1.145 +
   1.146 +    bufLen -= count;
   1.147 +    buf += count;
   1.148 +  }
   1.149 +}
   1.150 +
   1.151 +static uint16_t
   1.152 +ReadUint16(const uint8_t *&buf)
   1.153 +{
   1.154 +  uint16_t x;
   1.155 +#ifdef IS_BIG_ENDIAN
   1.156 +  x = ((uint16_t) buf[1]) | ((uint16_t) buf[0] << 8);
   1.157 +#else
   1.158 +  x = ((uint16_t) buf[0]) | ((uint16_t) buf[1] << 8);
   1.159 +#endif
   1.160 +  buf += sizeof(x);
   1.161 +  return x;
   1.162 +}
   1.163 +
   1.164 +static uint32_t
   1.165 +ReadUint32(const uint8_t *&buf)
   1.166 +{
   1.167 +  uint32_t x;
   1.168 +#ifdef IS_BIG_ENDIAN
   1.169 +  x = ( (uint32_t) buf[3])        |
   1.170 +      (((uint32_t) buf[2]) << 8)  |
   1.171 +      (((uint32_t) buf[1]) << 16) |
   1.172 +      (((uint32_t) buf[0]) << 24);
   1.173 +#else
   1.174 +  x = ( (uint32_t) buf[0])        |
   1.175 +      (((uint32_t) buf[1]) << 8)  |
   1.176 +      (((uint32_t) buf[2]) << 16) |
   1.177 +      (((uint32_t) buf[3]) << 24);
   1.178 +#endif
   1.179 +  buf += sizeof(x);
   1.180 +  return x;
   1.181 +}
   1.182 +
   1.183 +typedef struct {
   1.184 +  uint16_t length;
   1.185 +  uint16_t capacity;
   1.186 +  uint32_t offset;
   1.187 +} SecBuf;
   1.188 +
   1.189 +static void
   1.190 +ReadSecBuf(SecBuf *s, const uint8_t *&buf)
   1.191 +{
   1.192 +  s->length = ReadUint16(buf);
   1.193 +  s->capacity = ReadUint16(buf);
   1.194 +  s->offset = ReadUint32(buf);
   1.195 +}
   1.196 +
   1.197 +static void
   1.198 +ReadType1MsgBody(const uint8_t *inBuf, uint32_t start)
   1.199 +{
   1.200 +  const uint8_t *cursor = inBuf + start;
   1.201 +  uint32_t flags;
   1.202 +
   1.203 +  PrintBuf("flags", cursor, 4);
   1.204 +  // read flags
   1.205 +  flags = ReadUint32(cursor);
   1.206 +  PrintFlags(flags);
   1.207 +
   1.208 +  // type 1 message may not include trailing security buffers
   1.209 +  if ((flags & kNegotiateDomainSupplied) | 
   1.210 +      (flags & kNegotiateWorkstationSupplied))
   1.211 +  {
   1.212 +    SecBuf secbuf;
   1.213 +    ReadSecBuf(&secbuf, cursor);
   1.214 +    PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
   1.215 +
   1.216 +    ReadSecBuf(&secbuf, cursor);
   1.217 +    PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
   1.218 +  }
   1.219 +}
   1.220 +
   1.221 +static void
   1.222 +ReadType2MsgBody(const uint8_t *inBuf, uint32_t start)
   1.223 +{
   1.224 +  uint16_t targetLen, offset;
   1.225 +  uint32_t flags;
   1.226 +  const uint8_t *target;
   1.227 +  const uint8_t *cursor = inBuf + start;
   1.228 +
   1.229 +  // read target name security buffer
   1.230 +  targetLen = ReadUint16(cursor);
   1.231 +  ReadUint16(cursor); // discard next 16-bit value
   1.232 +  offset = ReadUint32(cursor); // get offset from inBuf
   1.233 +  target = inBuf + offset;
   1.234 +
   1.235 +  PrintBuf("target", target, targetLen);
   1.236 +
   1.237 +  PrintBuf("flags", cursor, 4);
   1.238 +  // read flags
   1.239 +  flags = ReadUint32(cursor);
   1.240 +  PrintFlags(flags);
   1.241 +
   1.242 +  // read challenge
   1.243 +  PrintBuf("challenge", cursor, 8);
   1.244 +  cursor += 8;
   1.245 +
   1.246 +  PrintBuf("context", cursor, 8);
   1.247 +  cursor += 8;
   1.248 +
   1.249 +  SecBuf secbuf;
   1.250 +  ReadSecBuf(&secbuf, cursor);
   1.251 +  PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
   1.252 +}
   1.253 +
   1.254 +static void
   1.255 +ReadType3MsgBody(const uint8_t *inBuf, uint32_t start)
   1.256 +{
   1.257 +  const uint8_t *cursor = inBuf + start;
   1.258 +
   1.259 +  SecBuf secbuf;
   1.260 +
   1.261 +  ReadSecBuf(&secbuf, cursor); // LM response
   1.262 +  PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
   1.263 +
   1.264 +  ReadSecBuf(&secbuf, cursor); // NTLM response
   1.265 +  PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
   1.266 +
   1.267 +  ReadSecBuf(&secbuf, cursor); // domain name
   1.268 +  PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
   1.269 +
   1.270 +  ReadSecBuf(&secbuf, cursor); // user name
   1.271 +  PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
   1.272 +
   1.273 +  ReadSecBuf(&secbuf, cursor); // workstation name
   1.274 +  PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
   1.275 +
   1.276 +  ReadSecBuf(&secbuf, cursor); // session key
   1.277 +  PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
   1.278 +
   1.279 +  uint32_t flags = ReadUint32(cursor);
   1.280 +  PrintBuf("flags", (const uint8_t *) &flags, sizeof(flags));
   1.281 +  PrintFlags(flags);
   1.282 +}
   1.283 +
   1.284 +static void
   1.285 +ReadMsg(const char *base64buf, uint32_t bufLen)
   1.286 +{
   1.287 +  uint8_t *inBuf = (uint8_t *) PL_Base64Decode(base64buf, bufLen, nullptr);
   1.288 +  if (!inBuf)
   1.289 +  {
   1.290 +    printf("PL_Base64Decode failed\n");
   1.291 +    return;
   1.292 +  }
   1.293 +
   1.294 +  const uint8_t *cursor = inBuf;
   1.295 +
   1.296 +  PrintBuf("signature", cursor, 8);
   1.297 +
   1.298 +  // verify NTLMSSP signature
   1.299 +  if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
   1.300 +  {
   1.301 +    printf("### invalid or corrupt NTLM signature\n");
   1.302 +  }
   1.303 +  cursor += sizeof(NTLM_SIGNATURE);
   1.304 +
   1.305 +  PrintBuf("message type", cursor, 4);
   1.306 +
   1.307 +  if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
   1.308 +    ReadType1MsgBody(inBuf, 12);
   1.309 +  else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
   1.310 +    ReadType2MsgBody(inBuf, 12);
   1.311 +  else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
   1.312 +    ReadType3MsgBody(inBuf, 12);
   1.313 +  else
   1.314 +    printf("### invalid or unknown message type\n"); 
   1.315 +
   1.316 +  PR_Free(inBuf);
   1.317 +}
   1.318 +
   1.319 +int main(int argc, char **argv)
   1.320 +{
   1.321 +  if (argc == 1)
   1.322 +  {
   1.323 +    printf("usage: ntlmread <msg>\n");
   1.324 +    return -1;
   1.325 +  }
   1.326 +  ReadMsg(argv[1], (uint32_t) strlen(argv[1]));
   1.327 +  return 0;
   1.328 +}

mercurial