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

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#
18import struct
19import random
21from impacket import LOG
22from impacket.examples.ntlmrelayx.servers.socksserver import SocksRelay
23from 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
25from impacket.ntlm import NTLMAuthChallengeResponse
26try:
27 from OpenSSL import SSL
28except:
29 LOG.critical("pyOpenSSL is not installed, can't continue")
30 raise
32# Besides using this base class you need to define one global variable when
33# writing a plugin:
34PLUGIN_CLASS = "MSSQLSocksRelay"
36class MSSQLSocksRelay(SocksRelay):
37 PLUGIN_NAME = 'MSSQL Socks Plugin'
38 PLUGIN_SCHEME = 'MSSQL'
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
47 @staticmethod
48 def getProtocolPort():
49 return 1433
51 def initConnection(self):
52 pass
54 def skipAuthentication(self):
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
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'
69 # Answering who we are
70 self.sendTDS(TDS_TABULAR, prelogin.getData(), 0)
72 # 2. Packet should be a TDS_LOGIN
73 tds = self.recvTDS()
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
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)
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()
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()
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()
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
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)
139 return True
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)
158 return True
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())
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
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())
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)
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
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
222 remaining = None
223 if packetLen < len(packet['Data']):
224 remaining = packet['Data'][packetLen:]
225 packet['Data'] = packet['Data'][:packetLen]
227 while status != TDS_STATUS_EOM:
228 if remaining is not None:
229 tmpPacket = TDSPacket(remaining)
230 else:
231 tmpPacket = TDSPacket(self.socketRecv(packetSize))
233 packetLen = tmpPacket['Length'] - 8
234 while packetLen > len(tmpPacket['Data']):
235 data = self.socketRecv(packetSize)
236 tmpPacket['Data'] += data
238 remaining = None
239 if packetLen < len(tmpPacket['Data']):
240 remaining = tmpPacket['Data'][packetLen:]
241 tmpPacket['Data'] = tmpPacket['Data'][:packetLen]
243 status = tmpPacket['Status']
244 packet['Data'] += tmpPacket['Data']
245 packet['Length'] += tmpPacket['Length'] - 8
247 # print packet['Length']
248 return packet