Coverage for /root/GitHubProjects/impacket/impacket/examples/ntlmrelayx/servers/socksplugins/mssql.py: 11%

# Coverage for /root/GitHubProjects/impacket/impacket/examples/ntlmrelayx/servers/socksplugins/mssql.py : 11%

## 158 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# 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# A Socks Proxy for the MSSQL Protocol

8#

9# Author:

10# Alberto Solino (@agsolino)

11#

12# Description:

13# A simple SOCKS server that proxy connection to relayed connections

14#

15# ToDo:

16#

17

18 import struct

19 import random

20

21 from impacket import LOG

22 from impacket.examples.ntlmrelayx.servers.socksserver import SocksRelay

23 from impacket.tds import TDSPacket, TDS_STATUS_NORMAL, TDS_STATUS_EOM, TDS_PRE_LOGIN, TDS_ENCRYPT_NOT_SUP, TDS_TABULAR, \

24 TDS_LOGIN, TDS_LOGIN7, TDS_PRELOGIN, TDS_INTEGRATED_SECURITY_ON

25 from impacket.ntlm import NTLMAuthChallengeResponse

26 try:

27 from OpenSSL import SSL

28 except:

29 LOG.critical("pyOpenSSL is not installed, can't continue")

30 raise

31

32# Besides using this base class you need to define one global variable when

33# writing a plugin:

34 PLUGIN_CLASS = "MSSQLSocksRelay"

35

36 class MSSQLSocksRelay(SocksRelay):

37 PLUGIN_NAME = 'MSSQL Socks Plugin'

38 PLUGIN_SCHEME = 'MSSQL'

39

40 def __init__(self, targetHost, targetPort, socksSocket, activeRelays):

41 SocksRelay.__init__(self, targetHost, targetPort, socksSocket, activeRelays)

42 self.isSSL = False

43 self.tlsSocket = None

44 self.packetSize = 32763

45 self.session = None

46

47 @staticmethod

48 def getProtocolPort():

49 return 1433

50

51 def initConnection(self):

52 pass

53

54 def skipAuthentication(self):

55

56 # 1. First packet should be a TDS_PRELOGIN()

57 tds = self.recvTDS()

58 if tds['Type'] != TDS_PRE_LOGIN:

59 # Unexpected packet

60 LOG.debug('Unexpected packet type %d instead of TDS_PRE_LOGIN' % tds['Type'])

61 return False

62

63 prelogin = TDS_PRELOGIN()

64 prelogin['Version'] = b"\x08\x00\x01\x55\x00\x00"

65 prelogin['Encryption'] = TDS_ENCRYPT_NOT_SUP

66 prelogin['ThreadID'] = struct.pack('<L',random.randint(0,65535))

67 prelogin['Instance'] = b'\x00'

68

69 # Answering who we are

70 self.sendTDS(TDS_TABULAR, prelogin.getData(), 0)

71

72 # 2. Packet should be a TDS_LOGIN

73 tds = self.recvTDS()

74

75 if tds['Type'] != TDS_LOGIN7:

76 # Unexpected packet

77 LOG.debug('Unexpected packet type %d instead of TDS_LOGIN' % tds['Type'])

78 return False

79

80 login = TDS_LOGIN()

81 login.fromString(tds['Data'])

82 if login['OptionFlags2'] & TDS_INTEGRATED_SECURITY_ON:

83 # Windows Authentication enabled

84 # Send the resp we've got from the original relay

85 TDSResponse = self.sessionData['NTLM_CHALLENGE']

86 self.sendTDS(TDSResponse['Type'], TDSResponse['Data'], 0)

87

88 # Here we should get the NTLM_AUTHENTICATE

89 tds = self.recvTDS()

90 authenticateMessage = NTLMAuthChallengeResponse()

91 authenticateMessage.fromString(tds['Data'])

92 self.username = authenticateMessage['user_name']

93 try:

94 self.username = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'),

95 authenticateMessage['user_name'].decode('utf-16le'))).upper()

96 except UnicodeDecodeError:

97 # Not Unicode encoded?

98 self.username = ('%s/%s' % (authenticateMessage['domain_name'], authenticateMessage['user_name'])).upper()

99

100 else:

101 if login['UserName'].find('/') >=0:

102 try:

103 self.username = login['UserName'].upper().decode('utf-16le')

104 except UnicodeDecodeError:

105 # Not Unicode encoded?

106 self.username = login['UserName'].upper()

107

108 else:

109 try:

110 self.username = ('/%s' % login['UserName'].decode('utf-16le')).upper()

111 except UnicodeDecodeError:

112 # Not Unicode encoded?

113 self.username = ('/%s' % login['UserName']).upper()

114

115 # Check if we have a connection for the user

116 if self.username in self.activeRelays:

117 # Check the connection is not inUse

118 if self.activeRelays[self.username]['inUse'] is True:

119 LOG.error('MSSQL: Connection for %s@%s(%s) is being used at the moment!' % (

120 self.username, self.targetHost, self.targetPort))

121 return False

122 else:

123 LOG.info('MSSQL: Proxying client session for %s@%s(%s)' % (

124 self.username, self.targetHost, self.targetPort))

125 self.session = self.activeRelays[self.username]['protocolClient'].session

126 else:

127 LOG.error('MSSQL: No session for %s@%s(%s) available' % (

128 self.username, self.targetHost, self.targetPort))

129 return False

130

131 # We have a session relayed, let's answer back with the data

132 if login['OptionFlags2'] & TDS_INTEGRATED_SECURITY_ON:

133 TDSResponse = self.sessionData['AUTH_ANSWER']

134 self.sendTDS(TDSResponse['Type'], TDSResponse['Data'], 0)

135 else:

136 TDSResponse = self.sessionData['AUTH_ANSWER']

137 self.sendTDS(TDSResponse['Type'], TDSResponse['Data'], 0)

138

139 return True

140

141 def tunnelConnection(self):

142 # For the rest of the remaining packets, we should just read and send. Except when trying to log out,

143 # that's forbidden! ;)

144 try:

145 while True:

146 # 1. Get Data from client

147 tds = self.recvTDS()

148 # 2. Send it to the relayed session

149 self.session.sendTDS(tds['Type'], tds['Data'], 0)

150 # 3. Get the target's answer

151 tds = self.session.recvTDS()

152 # 4. Send it back to the client

153 self.sendTDS(tds['Type'], tds['Data'], 0)

154 except Exception:

155 # Probably an error here

156 LOG.debug('Exception:', exc_info=True)

157

158 return True

159

160 def sendTDS(self, packetType, data, packetID = 1):

161 if (len(data)-8) > self.packetSize:

162 remaining = data[self.packetSize-8:]

163 tds = TDSPacket()

164 tds['Type'] = packetType

165 tds['Status'] = TDS_STATUS_NORMAL

166 tds['PacketID'] = packetID

167 tds['Data'] = data[:self.packetSize-8]

168 self.socketSendall(tds.getData())

169

170 while len(remaining) > (self.packetSize-8):

171 packetID += 1

172 tds['PacketID'] = packetID

173 tds['Data'] = remaining[:self.packetSize-8]

174 self.socketSendall(tds.getData())

175 remaining = remaining[self.packetSize-8:]

176 data = remaining

177 packetID+=1

178

179 tds = TDSPacket()

180 tds['Type'] = packetType

181 tds['Status'] = TDS_STATUS_EOM

182 tds['PacketID'] = packetID

183 tds['Data'] = data

184 self.socketSendall(tds.getData())

185

186 def socketSendall(self,data):

187 if self.tlsSocket is None:

188 return self.socksSocket.sendall(data)

189 else:

190 self.tlsSocket.sendall(data)

191 dd = self.tlsSocket.bio_read(self.packetSize)

192 return self.socksSocket.sendall(dd)

193

194 def socketRecv(self, packetSize):

195 data = self.socksSocket.recv(packetSize)

196 if self.tlsSocket is not None:

197 dd = b''

198 self.tlsSocket.bio_write(data)

199 while True:

200 try:

201 dd += self.tlsSocket.read(packetSize)

202 except SSL.WantReadError:

203 data2 = self.socksSocket.recv(packetSize - len(data) )

204 self.tlsSocket.bio_write(data2)

205 pass

206 else:

207 data = dd

208 break

209 return data

210

211 def recvTDS(self, packetSize=None):

212 # Do reassembly here

213 if packetSize is None:

214 packetSize = self.packetSize

215 packet = TDSPacket(self.socketRecv(packetSize))

216 status = packet['Status']

217 packetLen = packet['Length'] - 8

218 while packetLen > len(packet['Data']):

219 data = self.socketRecv(packetSize)

220 packet['Data'] += data

221

222 remaining = None

223 if packetLen < len(packet['Data']):

224 remaining = packet['Data'][packetLen:]

225 packet['Data'] = packet['Data'][:packetLen]

226

227 while status != TDS_STATUS_EOM:

228 if remaining is not None:

229 tmpPacket = TDSPacket(remaining)

230 else:

231 tmpPacket = TDSPacket(self.socketRecv(packetSize))

232

233 packetLen = tmpPacket['Length'] - 8

234 while packetLen > len(tmpPacket['Data']):

235 data = self.socketRecv(packetSize)

236 tmpPacket['Data'] += data

237

238 remaining = None

239 if packetLen < len(tmpPacket['Data']):

240 remaining = tmpPacket['Data'][packetLen:]

241 tmpPacket['Data'] = tmpPacket['Data'][:packetLen]

242

243 status = tmpPacket['Status']

244 packet['Data'] += tmpPacket['Data']

245 packet['Length'] += tmpPacket['Length'] - 8

246

247 # print packet['Length']

248 return packet