diff -r 000000000000 -r 6474c204b198 netwerk/test/ReadNTLM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netwerk/test/ReadNTLM.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -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 +#include +#include + +#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; ilength = 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 \n"); + return -1; + } + ReadMsg(argv[1], (uint32_t) strlen(argv[1])); + return 0; +}