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

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

# 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. 

# 

# A Socks Proxy for the MSSQL Protocol 

# 

# Author: 

# Alberto Solino (@agsolino) 

# 

# Description: 

# A simple SOCKS server that proxy connection to relayed connections 

# 

# ToDo: 

# 

 

import struct 

import random 

 

from impacket import LOG 

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

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

TDS_LOGIN, TDS_LOGIN7, TDS_PRELOGIN, TDS_INTEGRATED_SECURITY_ON 

from impacket.ntlm import NTLMAuthChallengeResponse 

try: 

from OpenSSL import SSL 

except: 

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

raise 

 

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

# writing a plugin: 

PLUGIN_CLASS = "MSSQLSocksRelay" 

 

class MSSQLSocksRelay(SocksRelay): 

PLUGIN_NAME = 'MSSQL Socks Plugin' 

PLUGIN_SCHEME = 'MSSQL' 

 

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

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

self.isSSL = False 

self.tlsSocket = None 

self.packetSize = 32763 

self.session = None 

 

@staticmethod 

def getProtocolPort(): 

return 1433 

 

def initConnection(self): 

pass 

 

def skipAuthentication(self): 

 

# 1. First packet should be a TDS_PRELOGIN() 

tds = self.recvTDS() 

if tds['Type'] != TDS_PRE_LOGIN: 

# Unexpected packet 

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

return False 

 

prelogin = TDS_PRELOGIN() 

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

prelogin['Encryption'] = TDS_ENCRYPT_NOT_SUP 

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

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

 

# Answering who we are 

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

 

# 2. Packet should be a TDS_LOGIN 

tds = self.recvTDS() 

 

if tds['Type'] != TDS_LOGIN7: 

# Unexpected packet 

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

return False 

 

login = TDS_LOGIN() 

login.fromString(tds['Data']) 

if login['OptionFlags2'] & TDS_INTEGRATED_SECURITY_ON: 

# Windows Authentication enabled 

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

TDSResponse = self.sessionData['NTLM_CHALLENGE'] 

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

 

# Here we should get the NTLM_AUTHENTICATE 

tds = self.recvTDS() 

authenticateMessage = NTLMAuthChallengeResponse() 

authenticateMessage.fromString(tds['Data']) 

self.username = authenticateMessage['user_name'] 

try: 

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

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

except UnicodeDecodeError: 

# Not Unicode encoded? 

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

 

else: 

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

try: 

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

except UnicodeDecodeError: 

# Not Unicode encoded? 

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

 

else: 

try: 

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

except UnicodeDecodeError: 

# Not Unicode encoded? 

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

 

# Check if we have a connection for the user 

if self.username in self.activeRelays: 

# Check the connection is not inUse 

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

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

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

return False 

else: 

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

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

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

else: 

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

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

return False 

 

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

if login['OptionFlags2'] & TDS_INTEGRATED_SECURITY_ON: 

TDSResponse = self.sessionData['AUTH_ANSWER'] 

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

else: 

TDSResponse = self.sessionData['AUTH_ANSWER'] 

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

 

return True 

 

def tunnelConnection(self): 

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

# that's forbidden! ;) 

try: 

while True: 

# 1. Get Data from client 

tds = self.recvTDS() 

# 2. Send it to the relayed session 

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

# 3. Get the target's answer 

tds = self.session.recvTDS() 

# 4. Send it back to the client 

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

except Exception: 

# Probably an error here 

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

 

return True 

 

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

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

remaining = data[self.packetSize-8:] 

tds = TDSPacket() 

tds['Type'] = packetType 

tds['Status'] = TDS_STATUS_NORMAL 

tds['PacketID'] = packetID 

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

self.socketSendall(tds.getData()) 

 

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

packetID += 1 

tds['PacketID'] = packetID 

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

self.socketSendall(tds.getData()) 

remaining = remaining[self.packetSize-8:] 

data = remaining 

packetID+=1 

 

tds = TDSPacket() 

tds['Type'] = packetType 

tds['Status'] = TDS_STATUS_EOM 

tds['PacketID'] = packetID 

tds['Data'] = data 

self.socketSendall(tds.getData()) 

 

def socketSendall(self,data): 

if self.tlsSocket is None: 

return self.socksSocket.sendall(data) 

else: 

self.tlsSocket.sendall(data) 

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

return self.socksSocket.sendall(dd) 

 

def socketRecv(self, packetSize): 

data = self.socksSocket.recv(packetSize) 

if self.tlsSocket is not None: 

dd = b'' 

self.tlsSocket.bio_write(data) 

while True: 

try: 

dd += self.tlsSocket.read(packetSize) 

except SSL.WantReadError: 

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

self.tlsSocket.bio_write(data2) 

pass 

else: 

data = dd 

break 

return data 

 

def recvTDS(self, packetSize=None): 

# Do reassembly here 

if packetSize is None: 

packetSize = self.packetSize 

packet = TDSPacket(self.socketRecv(packetSize)) 

status = packet['Status'] 

packetLen = packet['Length'] - 8 

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

data = self.socketRecv(packetSize) 

packet['Data'] += data 

 

remaining = None 

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

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

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

 

while status != TDS_STATUS_EOM: 

if remaining is not None: 

tmpPacket = TDSPacket(remaining) 

else: 

tmpPacket = TDSPacket(self.socketRecv(packetSize)) 

 

packetLen = tmpPacket['Length'] - 8 

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

data = self.socketRecv(packetSize) 

tmpPacket['Data'] += data 

 

remaining = None 

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

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

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

 

status = tmpPacket['Status'] 

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

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

 

# print packet['Length'] 

return packet