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/. */
11 #include "nsStringAPI.h"
15 * ReadNTLM : reads NTLM messages.
17 * based on http://davenport.sourceforge.net/ntlm.html
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
)
72 if (flags & k ## _flag) \
73 printf(" 0x%08x (" # _flag ")\n", k ## _flag)
75 TEST(NegotiateUnicode
);
81 TEST(NegotiateDatagramStyle
);
82 TEST(NegotiateLanManagerKey
);
83 TEST(NegotiateNetware
);
84 TEST(NegotiateNTLMKey
);
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
);
105 TEST(NegotiateKeyExchange
);
112 PrintBuf(const char *tag
, const uint8_t *buf
, uint32_t bufLen
)
116 printf("%s =\n", tag
);
124 for (i
=0; i
<count
; ++i
)
126 printf("0x%02x ", int(buf
[i
]));
134 for (i
=0; i
<count
; ++i
)
137 printf("%c", buf
[i
]);
149 ReadUint16(const uint8_t *&buf
)
153 x
= ((uint16_t) buf
[1]) | ((uint16_t) buf
[0] << 8);
155 x
= ((uint16_t) buf
[0]) | ((uint16_t) buf
[1] << 8);
162 ReadUint32(const uint8_t *&buf
)
166 x
= ( (uint32_t) buf
[3]) |
167 (((uint32_t) buf
[2]) << 8) |
168 (((uint32_t) buf
[1]) << 16) |
169 (((uint32_t) buf
[0]) << 24);
171 x
= ( (uint32_t) buf
[0]) |
172 (((uint32_t) buf
[1]) << 8) |
173 (((uint32_t) buf
[2]) << 16) |
174 (((uint32_t) buf
[3]) << 24);
187 ReadSecBuf(SecBuf
*s
, const uint8_t *&buf
)
189 s
->length
= ReadUint16(buf
);
190 s
->capacity
= ReadUint16(buf
);
191 s
->offset
= ReadUint32(buf
);
195 ReadType1MsgBody(const uint8_t *inBuf
, uint32_t start
)
197 const uint8_t *cursor
= inBuf
+ start
;
200 PrintBuf("flags", cursor
, 4);
202 flags
= ReadUint32(cursor
);
205 // type 1 message may not include trailing security buffers
206 if ((flags
& kNegotiateDomainSupplied
) |
207 (flags
& kNegotiateWorkstationSupplied
))
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
);
219 ReadType2MsgBody(const uint8_t *inBuf
, uint32_t start
)
221 uint16_t targetLen
, offset
;
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);
236 flags
= ReadUint32(cursor
);
240 PrintBuf("challenge", cursor
, 8);
243 PrintBuf("context", cursor
, 8);
247 ReadSecBuf(&secbuf
, cursor
);
248 PrintBuf("target information", inBuf
+ secbuf
.offset
, secbuf
.length
);
252 ReadType3MsgBody(const uint8_t *inBuf
, uint32_t start
)
254 const uint8_t *cursor
= inBuf
+ start
;
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
));
282 ReadMsg(const char *base64buf
, uint32_t bufLen
)
284 uint8_t *inBuf
= (uint8_t *) PL_Base64Decode(base64buf
, bufLen
, nullptr);
287 printf("PL_Base64Decode failed\n");
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)
298 printf("### invalid or corrupt NTLM signature\n");
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);
311 printf("### invalid or unknown message type\n");
316 int main(int argc
, char **argv
)
320 printf("usage: ntlmread <msg>\n");
323 ReadMsg(argv
[1], (uint32_t) strlen(argv
[1]));