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

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

mercurial