summaryrefslogtreecommitdiffstats
path: root/netwerk/test/ReadNTLM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/ReadNTLM.cpp')
-rw-r--r--netwerk/test/ReadNTLM.cpp325
1 files changed, 325 insertions, 0 deletions
diff --git a/netwerk/test/ReadNTLM.cpp b/netwerk/test/ReadNTLM.cpp
new file mode 100644
index 000000000..20411e336
--- /dev/null
+++ b/netwerk/test/ReadNTLM.cpp
@@ -0,0 +1,325 @@
+/* vim: set ts=2 sw=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "plbase64.h"
+#include "nsStringAPI.h"
+#include "prmem.h"
+
+/*
+ * ReadNTLM : reads NTLM messages.
+ *
+ * based on http://davenport.sourceforge.net/ntlm.html
+ */
+
+#define kNegotiateUnicode 0x00000001
+#define kNegotiateOEM 0x00000002
+#define kRequestTarget 0x00000004
+#define kUnknown1 0x00000008
+#define kNegotiateSign 0x00000010
+#define kNegotiateSeal 0x00000020
+#define kNegotiateDatagramStyle 0x00000040
+#define kNegotiateLanManagerKey 0x00000080
+#define kNegotiateNetware 0x00000100
+#define kNegotiateNTLMKey 0x00000200
+#define kUnknown2 0x00000400
+#define kUnknown3 0x00000800
+#define kNegotiateDomainSupplied 0x00001000
+#define kNegotiateWorkstationSupplied 0x00002000
+#define kNegotiateLocalCall 0x00004000
+#define kNegotiateAlwaysSign 0x00008000
+#define kTargetTypeDomain 0x00010000
+#define kTargetTypeServer 0x00020000
+#define kTargetTypeShare 0x00040000
+#define kNegotiateNTLM2Key 0x00080000
+#define kRequestInitResponse 0x00100000
+#define kRequestAcceptResponse 0x00200000
+#define kRequestNonNTSessionKey 0x00400000
+#define kNegotiateTargetInfo 0x00800000
+#define kUnknown4 0x01000000
+#define kUnknown5 0x02000000
+#define kUnknown6 0x04000000
+#define kUnknown7 0x08000000
+#define kUnknown8 0x10000000
+#define kNegotiate128 0x20000000
+#define kNegotiateKeyExchange 0x40000000
+#define kNegotiate56 0x80000000
+
+static const char NTLM_SIGNATURE[] = "NTLMSSP";
+static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
+static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
+static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
+
+#define NTLM_MARKER_LEN 4
+#define NTLM_TYPE1_HEADER_LEN 32
+#define NTLM_TYPE2_HEADER_LEN 32
+#define NTLM_TYPE3_HEADER_LEN 64
+
+#define LM_HASH_LEN 16
+#define LM_RESP_LEN 24
+
+#define NTLM_HASH_LEN 16
+#define NTLM_RESP_LEN 24
+
+static void PrintFlags(uint32_t flags)
+{
+#define TEST(_flag) \
+ if (flags & k ## _flag) \
+ printf(" 0x%08x (" # _flag ")\n", k ## _flag)
+
+ TEST(NegotiateUnicode);
+ TEST(NegotiateOEM);
+ TEST(RequestTarget);
+ TEST(Unknown1);
+ TEST(NegotiateSign);
+ TEST(NegotiateSeal);
+ TEST(NegotiateDatagramStyle);
+ TEST(NegotiateLanManagerKey);
+ TEST(NegotiateNetware);
+ TEST(NegotiateNTLMKey);
+ TEST(Unknown2);
+ TEST(Unknown3);
+ TEST(NegotiateDomainSupplied);
+ TEST(NegotiateWorkstationSupplied);
+ TEST(NegotiateLocalCall);
+ TEST(NegotiateAlwaysSign);
+ TEST(TargetTypeDomain);
+ TEST(TargetTypeServer);
+ TEST(TargetTypeShare);
+ TEST(NegotiateNTLM2Key);
+ TEST(RequestInitResponse);
+ TEST(RequestAcceptResponse);
+ TEST(RequestNonNTSessionKey);
+ TEST(NegotiateTargetInfo);
+ TEST(Unknown4);
+ TEST(Unknown5);
+ TEST(Unknown6);
+ TEST(Unknown7);
+ TEST(Unknown8);
+ TEST(Negotiate128);
+ TEST(NegotiateKeyExchange);
+ TEST(Negotiate56);
+
+#undef TEST
+}
+
+static void
+PrintBuf(const char *tag, const uint8_t *buf, uint32_t bufLen)
+{
+ int i;
+
+ printf("%s =\n", tag);
+ while (bufLen > 0)
+ {
+ int count = bufLen;
+ if (count > 8)
+ count = 8;
+
+ printf(" ");
+ for (i=0; i<count; ++i)
+ {
+ printf("0x%02x ", int(buf[i]));
+ }
+ for (; i<8; ++i)
+ {
+ printf(" ");
+ }
+
+ printf(" ");
+ for (i=0; i<count; ++i)
+ {
+ if (isprint(buf[i]))
+ printf("%c", buf[i]);
+ else
+ printf(".");
+ }
+ printf("\n");
+
+ bufLen -= count;
+ buf += count;
+ }
+}
+
+static uint16_t
+ReadUint16(const uint8_t *&buf)
+{
+ uint16_t x;
+#ifdef IS_BIG_ENDIAN
+ x = ((uint16_t) buf[1]) | ((uint16_t) buf[0] << 8);
+#else
+ x = ((uint16_t) buf[0]) | ((uint16_t) buf[1] << 8);
+#endif
+ buf += sizeof(x);
+ return x;
+}
+
+static uint32_t
+ReadUint32(const uint8_t *&buf)
+{
+ uint32_t x;
+#ifdef IS_BIG_ENDIAN
+ x = ( (uint32_t) buf[3]) |
+ (((uint32_t) buf[2]) << 8) |
+ (((uint32_t) buf[1]) << 16) |
+ (((uint32_t) buf[0]) << 24);
+#else
+ x = ( (uint32_t) buf[0]) |
+ (((uint32_t) buf[1]) << 8) |
+ (((uint32_t) buf[2]) << 16) |
+ (((uint32_t) buf[3]) << 24);
+#endif
+ buf += sizeof(x);
+ return x;
+}
+
+typedef struct {
+ uint16_t length;
+ uint16_t capacity;
+ uint32_t offset;
+} SecBuf;
+
+static void
+ReadSecBuf(SecBuf *s, const uint8_t *&buf)
+{
+ s->length = ReadUint16(buf);
+ s->capacity = ReadUint16(buf);
+ s->offset = ReadUint32(buf);
+}
+
+static void
+ReadType1MsgBody(const uint8_t *inBuf, uint32_t start)
+{
+ const uint8_t *cursor = inBuf + start;
+ uint32_t flags;
+
+ PrintBuf("flags", cursor, 4);
+ // read flags
+ flags = ReadUint32(cursor);
+ PrintFlags(flags);
+
+ // type 1 message may not include trailing security buffers
+ if ((flags & kNegotiateDomainSupplied) |
+ (flags & kNegotiateWorkstationSupplied))
+ {
+ SecBuf secbuf;
+ ReadSecBuf(&secbuf, cursor);
+ PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor);
+ PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
+ }
+}
+
+static void
+ReadType2MsgBody(const uint8_t *inBuf, uint32_t start)
+{
+ uint16_t targetLen, offset;
+ uint32_t flags;
+ const uint8_t *target;
+ const uint8_t *cursor = inBuf + start;
+
+ // read target name security buffer
+ targetLen = ReadUint16(cursor);
+ ReadUint16(cursor); // discard next 16-bit value
+ offset = ReadUint32(cursor); // get offset from inBuf
+ target = inBuf + offset;
+
+ PrintBuf("target", target, targetLen);
+
+ PrintBuf("flags", cursor, 4);
+ // read flags
+ flags = ReadUint32(cursor);
+ PrintFlags(flags);
+
+ // read challenge
+ PrintBuf("challenge", cursor, 8);
+ cursor += 8;
+
+ PrintBuf("context", cursor, 8);
+ cursor += 8;
+
+ SecBuf secbuf;
+ ReadSecBuf(&secbuf, cursor);
+ PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
+}
+
+static void
+ReadType3MsgBody(const uint8_t *inBuf, uint32_t start)
+{
+ const uint8_t *cursor = inBuf + start;
+
+ SecBuf secbuf;
+
+ ReadSecBuf(&secbuf, cursor); // LM response
+ PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor); // NTLM response
+ PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor); // domain name
+ PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor); // user name
+ PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor); // workstation name
+ PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
+
+ ReadSecBuf(&secbuf, cursor); // session key
+ PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
+
+ uint32_t flags = ReadUint32(cursor);
+ PrintBuf("flags", (const uint8_t *) &flags, sizeof(flags));
+ PrintFlags(flags);
+}
+
+static void
+ReadMsg(const char *base64buf, uint32_t bufLen)
+{
+ uint8_t *inBuf = (uint8_t *) PL_Base64Decode(base64buf, bufLen, nullptr);
+ if (!inBuf)
+ {
+ printf("PL_Base64Decode failed\n");
+ return;
+ }
+
+ const uint8_t *cursor = inBuf;
+
+ PrintBuf("signature", cursor, 8);
+
+ // verify NTLMSSP signature
+ if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
+ {
+ printf("### invalid or corrupt NTLM signature\n");
+ }
+ cursor += sizeof(NTLM_SIGNATURE);
+
+ PrintBuf("message type", cursor, 4);
+
+ if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
+ ReadType1MsgBody(inBuf, 12);
+ else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
+ ReadType2MsgBody(inBuf, 12);
+ else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
+ ReadType3MsgBody(inBuf, 12);
+ else
+ printf("### invalid or unknown message type\n");
+
+ PR_Free(inBuf);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc == 1)
+ {
+ printf("usage: ntlmread <msg>\n");
+ return -1;
+ }
+ ReadMsg(argv[1], (uint32_t) strlen(argv[1]));
+ return 0;
+}