1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 import array
38 import random
39 import struct
40 from socket import gethostname
41 import Cryptodome.Cipher.DES as DES
42 import Cryptodome.Cipher.ARC4 as RC4
43 import Cryptodome.Hash.HMAC as HMAC
44 import Cryptodome.Hash.MD4 as MD4
45 import Cryptodome.Hash.MD5 as MD5
46 import core
47 import model
48 import nttime
49
51 """
52 Return an 64-bit des key by adding a zero to the least significant bit
53 of each character.
54 K should be a 7 char string
55 """
56 in_key = K + "\0"
57 out_key = [K[0]]
58 for ix in xrange(1,len(in_key)):
59 out_key.append(chr( ((ord(in_key[ix-1]) << (8-ix)) & 0xFF) | (ord(in_key[ix]) >> ix)) )
60 return "".join(out_key)
61
65
67 return DES(K[:7], D) + DES(K[7:14], D) + DES(K[14:16] + "\0"*5, D)
68
70 return array.array("B", [random.getrandbits(8) for x in xrange(length) ])
71
76
77
78 NTLM_SIGNATURE = "NTLMSSP\x00"
79
84
85 MessageType.import_items(globals())
86
87 -class Ntlm(core.Frame):
109
133
134 NegotiateFlags.import_items(globals())
135
140
141 ProductMajorVersionFlags.import_items(globals())
142
148
149 ProductMinorVersionFlags.import_items(globals())
150
154
155 NTLMRevisionCurrentFlags.import_items(globals())
156
180
182 message_type = NtLmNegotiate
184 core.Frame.__init__(self, parent)
185 if parent is not None:
186 parent.message = self
187 self.negotiate_flags = 0
188 self.domain_name = ""
189 self.workstation_name = gethostname()
190 self.version = None
191
238
239 -class AvId(core.ValueEnum):
251
252 AvId.import_items(globals())
253
284
286 for p in av_pairs:
287 if p.av_id == av_id:
288 return p
289
291 message_type = NtLmChallenge
293 core.Frame.__init__(self, parent)
294 if parent is not None:
295 parent.message = self
296 self.target_name = None
297 self.negotiate_flags = 0
298 self.server_challenge = array.array('B', [0]*8)
299 self.target_info = []
300 self.version = None
337
339 message_type = NtLmAuthenticate
341 core.Frame.__init__(self, parent)
342 if parent is not None:
343 parent.message = self
344 self.lm_challenge_response = None
345 self.nt_challenge_response = None
346 self.domain_name = None
347 self.user_name = None
348 self.workstation_name = gethostname()
349 self.encrypted_random_session_key = None
350 self.negotiate_flags = None
351 self.version = None
352 self.mic = None
353
355 is_unicode = self.negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE
356
357 message_start = cur - 8
358 cur.encode_uint32le(self.message_type)
359
360 if self.lm_challenge_response is not None:
361 lm_challenge_response_len = len(self.lm_challenge_response)
362 else:
363 lm_challenge_response_len = 0
364 cur.encode_uint16le(lm_challenge_response_len)
365 cur.encode_uint16le(lm_challenge_response_len)
366 lm_challenge_response_offset_hole = cur.hole.encode_uint32le(0)
367
368 if self.nt_challenge_response is not None:
369 nt_challenge_response_len = len(self.nt_challenge_response)
370 else:
371 nt_challenge_response_len = 0
372 cur.encode_uint16le(nt_challenge_response_len)
373 cur.encode_uint16le(nt_challenge_response_len)
374 nt_challenge_response_offset_hole = cur.hole.encode_uint32le(0)
375
376 if self.domain_name is not None:
377 domain_name_len = len(self.domain_name)
378 else:
379 domain_name_len = 0
380 if is_unicode:
381 domain_name_len = domain_name_len * 2
382 cur.encode_uint16le(domain_name_len)
383 cur.encode_uint16le(domain_name_len)
384 domain_name_offset_hole = cur.hole.encode_uint32le(0)
385
386 if self.user_name is not None:
387 user_name_len = len(self.user_name)
388 else:
389 user_name_len = 0
390 if is_unicode:
391 user_name_len = user_name_len * 2
392 cur.encode_uint16le(user_name_len)
393 cur.encode_uint16le(user_name_len)
394 user_name_offset_hole = cur.hole.encode_uint32le(0)
395
396 if self.workstation_name is not None:
397 workstation_name_len = len(self.workstation_name)
398 else:
399 workstation_name_len = 0
400 if is_unicode:
401 workstation_name_len = workstation_name_len * 2
402 cur.encode_uint16le(workstation_name_len)
403 cur.encode_uint16le(workstation_name_len)
404 workstation_name_offset_hole = cur.hole.encode_uint32le(0)
405
406 if self.negotiate_flags & NTLMSSP_NEGOTIATE_KEY_EXCH and \
407 self.encrypted_random_session_key is not None:
408 encrypted_random_session_key_len = len(self.encrypted_random_session_key)
409 else:
410 encrypted_random_session_key_len = 0
411 cur.encode_uint16le(encrypted_random_session_key_len)
412 cur.encode_uint16le(encrypted_random_session_key_len)
413 encrypted_random_session_key_offset_hole = cur.hole.encode_uint32le(0)
414
415 cur.encode_uint32le(self.negotiate_flags)
416
417 if self.negotiate_flags & NTLMSSP_NEGOTIATE_VERSION and \
418 self.version is not None:
419 self.version.encode(cur)
420 else:
421 cur.encode_uint64le(0)
422
423 if self.mic is not None:
424 cur.encode_bytes(self.mic[:16])
425
426 lm_challenge_response_offset_hole(cur - message_start)
427 if lm_challenge_response_len > 0:
428 cur.encode_bytes(self.lm_challenge_response)
429
430 nt_challenge_response_offset_hole(cur - message_start)
431 if nt_challenge_response_len > 0:
432 cur.encode_bytes(self.nt_challenge_response)
433
434 domain_name_offset_hole(cur - message_start)
435 if domain_name_len > 0:
436 if is_unicode:
437 cur.encode_utf16le(self.domain_name)
438 else:
439 cur.encode_bytes(self.domain_name)
440
441 user_name_offset_hole(cur - message_start)
442 if user_name_len > 0:
443 if is_unicode:
444 cur.encode_utf16le(self.user_name)
445 else:
446 cur.encode_bytes(self.user_name)
447
448 workstation_name_offset_hole(cur - message_start)
449 if workstation_name_len > 0:
450 if is_unicode:
451 cur.encode_utf16le(self.workstation_name)
452 else:
453 cur.encode_bytes(self.workstation_name)
454
455 encrypted_random_session_key_offset_hole(cur - message_start)
456 if encrypted_random_session_key_len > 0:
457 cur.encode_bytes(self.encrypted_random_session_key)
458
462
463 NtlmVersion.import_items(globals())
464
465
466
467
468
470 lm_passwd = (password.upper() + "\0"*14)
471 magic = "KGS!@#$%"
472 return DES(lm_passwd[:7], magic) + \
473 DES(lm_passwd[7:14], magic)
474
476 nt_passwd = password.encode("utf-16-le")
477 return MD4.new(nt_passwd).digest()
478
479 -def ComputeResponsev1(NegFlg, ResponseKeyNT, ResponseKeyLM, ServerChallenge,
480 ClientChallenge, Time=None, ServerName=None):
481 if NegFlg & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
482 NtChallengeResponse = DESL(ResponseKeyNT,
483 MD5.new(ServerChallenge + \
484 ClientChallenge).digest()[:8])
485 LmChallengeResponse = ClientChallenge + "\0"*16
486 else:
487 NtChallengeResponse = DESL(ResponseKeyNT, ServerChallenge)
488 LmChallengeResponse = DESL(ResponseKeyLM, ServerChallenge)
489 SessionBaseKey = MD4.new(ResponseKeyNT).digest()
490 return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
491
492 -def KXKEY(NegFlg, SessionBaseKey, LmChallengeResponse,
493 ServerChallenge, ResponseKeyLM):
494 if NegFlg & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
495 hm = HMAC.new(SessionBaseKey,
496 ServerChallenge +\
497 LmChallengeResponse[:8],
498 MD5)
499 KeyExchangeKey = hm.digest()
500 else:
501 LMOWF = ResponseKeyLM
502 if NegFlg & NTLMSSP_NEGOTIATE_LMKEY:
503 data = LmChallengeResponse[:8]
504 KeyExchangeKey = DES(LMOWF[:7], data) + \
505 DES(LMOWF[8] + "\xbd"*6, data)
506 else:
507 if NegFlg & NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
508 KeyExchangeKey = LMOWF[:8] + "\0"*8
509 else:
510 KeyExchangeKey = SessionBaseKey
511 return KeyExchangeKey
512
513
514
515
516
525
528 core.Frame.__init__(self, parent)
529 if parent is not None:
530 parent.challenge = self
531 self.time_stamp = array.array("B", "\0"*8)
532 self.challenge_from_client = array.array("B", "\0"*8)
533 self.av_pairs = []
544
545 -def NTOWFv2(password, user, userdom):
546 nt_passwd = password.encode("utf-16-le")
547 nt_hash_passwd = MD4.new(nt_passwd).digest()
548 nt_userdom = (user.upper() + userdom).encode("utf-16-le")
549 return HMAC.new(nt_hash_passwd,
550 nt_userdom,
551 MD5).digest()
552
553 -def ComputeResponsev2(NegFlg, ResponseKeyNT, ResponseKeyLM, ServerChallenge,
554 ClientChallenge, Time=None, ServerName=None, av_pairs=None):
555 if Time is None:
556 Time = nttime.NtTime(nttime.datetime.now())
557 if ServerName is None:
558 ServerName = "SERVER"
559 ServerName = ServerName.encode("utf-16-le")
560
561 TimeBuf = array.array("B")
562 cur = core.Cursor(TimeBuf,0)
563 cur.encode_uint64le(Time)
564
565 Responseversion = "\x01"
566 HiResponseversion = "\x01"
567
568 ntlmv2_client_challenge = NTLMv2ClientChallenge()
569 ntlmv2_client_challenge.time_stamp = Time
570 ntlmv2_client_challenge.challenge_from_client = ClientChallenge
571 if av_pairs is not None:
572 ntlmv2_client_challenge.av_pairs = av_pairs
573 temp = encode_frame(ntlmv2_client_challenge).tostring()
574 NTProofStr = HMAC.new(ResponseKeyNT,
575 ServerChallenge + temp,
576 MD5).digest()
577 NtChallengeResponse = NTProofStr + temp
578 LmChallengeResponse = HMAC.new(ResponseKeyLM,
579 ServerChallenge + ClientChallenge,
580 MD5).digest() +\
581 ClientChallenge
582 SessionBaseKey = HMAC.new(ResponseKeyNT, NTProofStr, MD5).digest()
583 return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
584
586 """
587 State machine for conducting ntlm authentication
588 """
589 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |\
590 NTLM_NEGOTIATE_OEM |\
591 NTLMSSP_REQUEST_TARGET |\
592 NTLMSSP_NEGOTIATE_NTLM |\
593 NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED |\
594 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |\
595 NTLM_NEGOTIATE_SIGN |\
596 NTLM_NEGOTIATE_SEAL |\
597 NTLMSSP_NEGOTIATE_128 |\
598 NTLMSSP_NEGOTIATE_56 |\
599 NTLMSSP_NEGOTIATE_KEY_EXCH
600
601 auth_flags = NTLMSSP_NEGOTIATE_UNICODE |\
602 NTLMSSP_REQUEST_TARGET |\
603 NTLMSSP_NEGOTIATE_NTLM |\
604 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |\
605 NTLM_NEGOTIATE_SIGN |\
606 NTLM_NEGOTIATE_SEAL |\
607 NTLMSSP_NEGOTIATE_TARGET_INFO |\
608 NTLMSSP_NEGOTIATE_128 |\
609 NTLMSSP_NEGOTIATE_56 |\
610 NTLMSSP_TARGET_TYPE_DOMAIN |\
611 NTLMSSP_NEGOTIATE_KEY_EXCH
612
613 - def __init__(self, domain, username, password):
614 self.messages = []
615 self.domain = domain
616 self.username = username
617 self.password = password
618 self.version = Version()
619 self.version.product_build = 9999
620 self.ntlm_version = NTLMv2
621
622 self.client_challenge = nonce(8)
623 self.session_base_key = nonce(16)
624
625 self.negotiate_message = None
626 self.negotiate_buffer = None
627 self.challenge_message = None
628 self.challenge_buffer = None
629 self.authenticate_message = None
630 self.authenticate_buffer = None
631
633 self.lm_hash = LMOWFv1(self.password)
634 self.nt_hash = NTOWFv1(self.password)
635 (self.nt_challenge_response,
636 self.lm_challenge_response,
637 self.session_base_key) = ComputeResponsev1(self.auth_flags,
638 self.nt_hash,
639 self.lm_hash,
640 self.server_challenge.tostring(),
641 self.client_challenge.tostring())
642 self.key_exchange_key = KXKEY(self.auth_flags,
643 self.session_base_key,
644 self.lm_challenge_response,
645 self.server_challenge.tostring(),
646 self.lm_hash)
647
649 ctarget_info = self.challenge_message.message.target_info
650 server_time = extract_pair(ctarget_info, MsvAvTimestamp)
651 if server_time is not None:
652 time = nttime.NtTime(struct.unpack("<Q", server_time.value)[0])
653 else:
654 time = nttime.NtTime(nttime.datetime.now())
655 server_name = extract_pair(ctarget_info,
656 MsvAvNbComputerName)
657 if server_name is not None:
658 server_name = server_name.value
659
660 self.nt_hash = NTOWFv2(self.password, self.username, self.domain)
661 (self.nt_challenge_response,
662 self.lm_challenge_response,
663 self.session_base_key) = ComputeResponsev2(self.auth_flags,
664 self.nt_hash,
665 self.nt_hash,
666 self.server_challenge.tostring(),
667 self.client_challenge.tostring(),
668 time,
669 server_name,
670 ctarget_info)
671 self.key_exchange_key = self.session_base_key
672
673 if extract_pair(ctarget_info, MsvAvTimestamp) is not None:
674 self.lm_challenge_response = "\0"*24
675
677 if self.auth_flags & NTLMSSP_NEGOTIATE_KEY_EXCH:
678 r = RC4.new(self.key_exchange_key)
679 self.exported_session_key = nonce(16)
680 return r.encrypt(self.exported_session_key.tostring())
681 else:
682 self.exported_session_key = self.key_exchange_key
683
685 ntlm = Ntlm()
686 neg = NtLmNegotiateMessage(ntlm)
687 neg.negotiate_flags = self.neg_flags
688 neg.domain_name = self.domain
689 neg.version = self.version
690 self.negotiate_buffer = array.array('B')
691 ntlm.encode(core.Cursor(self.negotiate_buffer, 0))
692 self.negotiate_message = ntlm
693 return self.negotiate_buffer
694
696
697 self.challenge_buffer = challenge_buf
698 ntlm_challenge = Ntlm()
699 ntlm_challenge.decode(core.Cursor(challenge_buf, 0))
700 self.server_challenge = ntlm_challenge.message.server_challenge
701 self.challenge_message = ntlm_challenge
702
703
704 ntlm = Ntlm()
705 auth = NtLmAuthenticateMessage(ntlm)
706 auth.negotiate_flags = self.auth_flags
707 auth.version = self.version
708 auth.domain_name = self.domain
709 auth.user_name = self.username
710
711
712 if self.ntlm_version == NTLMv1:
713 self.ntlmv1()
714 elif self.ntlm_version == NTLMv2:
715 self.ntlmv2()
716 else:
717 raise NotImplementedError("Unknown NTLM version {0}".format(self.ntlm_version))
718
719
720 auth.nt_challenge_response = self.nt_challenge_response
721 auth.lm_challenge_response = self.lm_challenge_response
722
723
724 session_key = self.session_key()
725 if session_key is not None:
726 auth.encrypted_random_session_key = session_key
727
728 self.authenticate_buffer = array.array('B')
729 ntlm.encode(core.Cursor(self.authenticate_buffer, 0))
730 self.authenticate_message = ntlm
731 return self.authenticate_buffer
732