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 = [] 
 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