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 +}