-
Notifications
You must be signed in to change notification settings - Fork 13.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add mssql_version module #18907
add mssql_version module #18907
Changes from all commits
3897b49
6fd8c8b
ae091bf
d0a714d
d8c7a26
04c5d8b
c382066
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -129,10 +129,7 @@ def detect_platform_and_arch | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def mssql_login(user='sa', pass='', db='', domain_name='') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
disconnect if self.sock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
connect | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mssql_prelogin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prelogin_data = mssql_prelogin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if auth == Msf::Exploit::Remote::AuthOption::KERBEROS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt = '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -236,6 +233,7 @@ def mssql_login(user='sa', pass='', db='', domain_name='') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
info = {:errors => []} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
info = mssql_parse_reply(resp, info) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.initial_connection_info = info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.initial_connection_info[:prelogin_data] = prelogin_data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return false if not info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return info[:login_ack] ? true : false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -468,6 +466,7 @@ def mssql_login(user='sa', pass='', db='', domain_name='') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
info = {:errors => []} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
info = mssql_parse_reply(resp, info) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.initial_connection_info = info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.initial_connection_info[:prelogin_data] = prelogin_data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return false if not info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
info[:login_ack] ? true : false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -477,85 +476,20 @@ def mssql_login(user='sa', pass='', db='', domain_name='') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#this method send a prelogin packet and check if encryption is off | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def mssql_prelogin(enc_error=false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_hdr = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data_token = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_hdr = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TYPE_PRE_LOGIN_MESSAGE, #type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
STATUS_END_OF_MESSAGE, #status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x0000, #length | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x0000, # SPID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x00, # PacketID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x00 #Window | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
version = [0x55010008, 0x0000].pack("Vv") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# if manually set, we will honour | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if tdsencryption == true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption = ENCRYPT_ON | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption = ENCRYPT_NOT_SUP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
instoptdata = "MSSQLServer\0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
threadid = "\0\0" + Rex::Text.rand_text(2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = 21 # size of pkt_data_token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data_token << [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x00, # Token 0 type Version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx , # VersionOffset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
version.length, # VersionLength | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x01, # Token 1 type Encryption | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = idx + version.length, # EncryptionOffset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x01, # EncryptionLength | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x02, # Token 2 type InstOpt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = idx + 1, # InstOptOffset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
instoptdata.length, # InstOptLength | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x03, # Token 3 type Threadid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx + instoptdata.length, # ThreadIdOffset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x04, # ThreadIdLength | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0xFF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
].pack("CnnCnnCnnCnnC") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data << pkt_data_token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data << version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data << encryption | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data << instoptdata | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_data << threadid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt_hdr[2] = pkt_data.length + 8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
disconnect if self.sock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
connect | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt = pkt_hdr.pack("CCnnCC") + pkt_data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pkt = mssql_prelogin_packet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
resp = mssql_send_recv(pkt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think if we renamed
It would also be unit-testable which would be nice There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea, but can you explain what you're envisioning? Where would we reuse it, and what are you suggesting we restrict from the method? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can get rid of the first block of copy/pasta on lines metasploit-framework/lib/rex/proto/mssql/client.rb Lines 491 to 507 in 95283f7
and metasploit-framework/lib/rex/proto/mssql/client.rb Lines 538 to 555 in 95283f7
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data = parse_prelogin_response(resp) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while resp && resp[0, 1] != "\xff" && resp.length > 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
token = resp.slice!(0, 5) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
token = token.unpack("Cnn") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx -= 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if token[0] == 0x01 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx += token[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if idx > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption_mode = resp[idx, 1].unpack("C")[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
unless data[:encryption] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
framework_module.print_error("Unable to parse encryption req " \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"during pre-login, this may not be a MSSQL server") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption_mode = ENCRYPT_NOT_SUP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data[:encryption] = ENCRYPT_NOT_SUP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
########################################################## | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -573,7 +507,7 @@ def mssql_prelogin(enc_error=false) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
########################################################## | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if encryption_mode == ENCRYPT_REQ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if data[:encryption] == ENCRYPT_REQ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# restart prelogin process except that we tell SQL Server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# than we are now able to encrypt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
disconnect if self.sock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -586,27 +520,15 @@ def mssql_prelogin(enc_error=false) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"been enabled based on server response.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
resp = mssql_send_recv(pkt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data = parse_prelogin_response(resp) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while resp && resp[0, 1] != "\xff" && resp.length > 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
token = resp.slice!(0, 5) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
token = token.unpack("Cnn") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx -= 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if token[0] == 0x01 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
idx += token[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if idx > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption_mode = resp[idx, 1].unpack("C")[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
unless data[:encryption] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
framework_module.print_error("Unable to parse encryption req " \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"during pre-login, this may not be a MSSQL server") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption_mode = ENCRYPT_NOT_SUP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data[:encryption] = ENCRYPT_NOT_SUP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
encryption_mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,6 +86,88 @@ def mssql_print_reply(info) | |
end | ||
end | ||
|
||
def mssql_prelogin_packet | ||
pkt = "" | ||
pkt_hdr = "" | ||
pkt_data_token = "" | ||
pkt_data = "" | ||
|
||
|
||
pkt_hdr = [ | ||
TYPE_PRE_LOGIN_MESSAGE, #type | ||
STATUS_END_OF_MESSAGE, #status | ||
0x0000, #length | ||
0x0000, # SPID | ||
0x00, # PacketID | ||
0x00 #Window | ||
] | ||
|
||
version = [0x55010008, 0x0000].pack("Vv") | ||
|
||
# if manually set, we will honour | ||
if tdsencryption == true | ||
encryption = ENCRYPT_ON | ||
else | ||
encryption = ENCRYPT_NOT_SUP | ||
end | ||
|
||
instoptdata = "MSSQLServer\0" | ||
|
||
threadid = "\0\0" + Rex::Text.rand_text(2) | ||
|
||
idx = 21 # size of pkt_data_token | ||
pkt_data_token << [ | ||
0x00, # Token 0 type Version | ||
idx , # VersionOffset | ||
version.length, # VersionLength | ||
|
||
0x01, # Token 1 type Encryption | ||
idx = idx + version.length, # EncryptionOffset | ||
0x01, # EncryptionLength | ||
|
||
0x02, # Token 2 type InstOpt | ||
idx = idx + 1, # InstOptOffset | ||
instoptdata.length, # InstOptLength | ||
|
||
0x03, # Token 3 type Threadid | ||
idx + instoptdata.length, # ThreadIdOffset | ||
0x04, # ThreadIdLength | ||
|
||
0xFF | ||
].pack('CnnCnnCnnCnnC') | ||
|
||
pkt_data << pkt_data_token | ||
pkt_data << version | ||
pkt_data << encryption | ||
pkt_data << instoptdata | ||
pkt_data << threadid | ||
|
||
pkt_hdr[2] = pkt_data.length + 8 | ||
|
||
pkt = pkt_hdr.pack('CCnnCC') + pkt_data | ||
pkt | ||
end | ||
|
||
def parse_prelogin_response(resp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be great to add tests for this as part of this PR so we can circle back to swapping this out with alternative implementations in the future 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already working on it, just pushed this in the meantime 👍 |
||
data = {} | ||
if resp.length > 5 # minimum size for response specification | ||
version_index = resp.slice(1, 2).unpack('n')[0] | ||
|
||
major = resp.slice(version_index, 1).unpack('C')[0] | ||
minor = resp.slice(version_index+1, 1).unpack('C')[0] | ||
build = resp.slice(version_index+2, 2).unpack('n')[0] | ||
|
||
enc_index = resp.slice(6, 2).unpack('n')[0] | ||
data[:encryption] = resp.slice(enc_index, 1).unpack('C')[0] | ||
end | ||
|
||
if major && minor && build | ||
data[:version] = "#{major}.#{minor}.#{build}" | ||
end | ||
|
||
return data | ||
end | ||
|
||
def mssql_send_recv(req, timeout=15, check_status = true) | ||
sock.put(req) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we just need a standalone method for creating the mssql client instance here - since the only way to get access to one is via
mssql_login
- which we don't have creds for