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# SMTP Protocol Client 

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

12# 

13# Author: 

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

15# Alberto Solino (@agsolino) 

16# 

17import smtplib 

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

28 

29class SMTPRelayClient(ProtocolClient): 

30 PLUGIN_NAME = "SMTP" 

31 

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

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

34 

35 def initConnection(self): 

36 self.session = smtplib.SMTP(self.targetHost,self.targetPort) 

37 # Turn on to debug SMTP messages 

38 # self.session.debuglevel = 3 

39 self.session.ehlo() 

40 

41 if 'AUTH NTLM' not in self.session.ehlo_resp: 

42 LOG.error('SMTP server does not support NTLM authentication!') 

43 return False 

44 return True 

45 

46 def sendNegotiate(self,negotiateMessage): 

47 negotiate = base64.b64encode(negotiateMessage) 

48 self.session.putcmd('AUTH NTLM') 

49 code, resp = self.session.getreply() 

50 if code != 334: 

51 LOG.error('SMTP Client error, expected 334 NTLM supported, got %d %s ' % (code, resp)) 

52 return False 

53 else: 

54 self.session.putcmd(negotiate) 

55 try: 

56 code, serverChallengeBase64 = self.session.getreply() 

57 serverChallenge = base64.b64decode(serverChallengeBase64) 

58 challenge = NTLMAuthChallenge() 

59 challenge.fromString(serverChallenge) 

60 return challenge 

61 except (IndexError, KeyError, AttributeError): 

62 LOG.error('No NTLM challenge returned from SMTP server') 

63 raise 

64 

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

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

67 respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) 

68 token = respToken2['ResponseToken'] 

69 else: 

70 token = authenticateMessageBlob 

71 auth = base64.b64encode(token) 

72 self.session.putcmd(auth) 

73 typ, data = self.session.getreply() 

74 if typ == 235: 

75 self.session.state = 'AUTH' 

76 return None, STATUS_SUCCESS 

77 else: 

78 LOG.error('SMTP: %s' % ''.join(data)) 

79 return None, STATUS_ACCESS_DENIED 

80 

81 def killConnection(self): 

82 if self.session is not None: 

83 self.session.close() 

84 self.session = None 

85 

86 def keepAlive(self): 

87 # Send a NOOP 

88 self.session.noop()