Revert "Land #7009, egypt's rubyntlm cleanup"

This reverts commit d90f0779f8, reversing
changes made to e3e360cc83.
bug/bundler_fix
James Lee 2016-07-05 15:22:44 -05:00
parent 1e0dcb9268
commit 1164c025a2
9 changed files with 509 additions and 344 deletions

View File

@ -36,7 +36,6 @@ PATH
rex-text rex-text
rex-zip rex-zip
robots robots
rubyntlm
rubyzip rubyzip
sqlite3 sqlite3
sshkey sshkey

View File

@ -9,6 +9,11 @@ module Metasploit
extend ActiveSupport::Concern extend ActiveSupport::Concern
include Metasploit::Framework::Tcp::Client include Metasploit::Framework::Tcp::Client
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
# Encryption # Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off. ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on. ENCRYPT_ON = 0x01 #Encryption is available and on.
@ -16,23 +21,23 @@ module Metasploit
ENCRYPT_REQ = 0x03 #Encryption is required. ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type # Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement # Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status # Status
STATUS_NORMAL = 0x00 STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01 STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02 STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+ STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
# #
@ -50,14 +55,14 @@ module Metasploit
idx = 0 idx = 0
pkt = '' pkt = ''
pkt_hdr = '' pkt_hdr = ''
pkt_hdr = [ pkt_hdr = [
TYPE_TDS7_LOGIN, #type TYPE_TDS7_LOGIN, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
0x0000, # SPID 0x0000, # SPID
0x01, # PacketID (unused upon specification 0x01, # PacketID (unused upon specification
# but ms network monitor stil prefer 1 to decode correctly, wireshark don't care) # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
0x00 #Window 0x00 #Window
] ]
pkt << [ pkt << [
@ -80,18 +85,18 @@ module Metasploit
sname = Rex::Text.to_unicode( rhost ) sname = Rex::Text.to_unicode( rhost )
dname = Rex::Text.to_unicode( db ) dname = Rex::Text.to_unicode( db )
ntlm_options = {
:signing => false,
:usentlm2_session => use_ntlm2_session,
:use_ntlmv2 => use_ntlmv2,
:send_lm => send_lm,
:send_ntlm => send_ntlm
}
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
ntlm_client = ::Net::NTLM::Client.new( ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
user,
pass,
workstation: workstation_name,
domain: domain_name,
)
type1 = ntlm_client.init_context
# SQL 2012, at least, does not support KEY_EXCHANGE
type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
ntlmsspblob = type1.serialize
idx = pkt.size + 50 # lengths below idx = pkt.size + 50 # lengths below
@ -132,9 +137,9 @@ module Metasploit
pkt << ntlmsspblob pkt << ntlmsspblob
# Total packet length # Total packet length
pkt[0, 4] = [pkt.length].pack('V') pkt[0,4] = [pkt.length].pack('V')
pkt_hdr[2] = pkt.length + 8 pkt_hdr[2] = pkt.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt pkt = pkt_hdr.pack("CCnnCC") + pkt
@ -142,38 +147,64 @@ module Metasploit
# has a strange behavior that differs from the specifications # has a strange behavior that differs from the specifications
# upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
# is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
if tdsencryption == true if tdsencryption == true
proxy = TDSSSLProxy.new(sock) proxy = TDSSSLProxy.new(sock)
proxy.setup_ssl proxy.setup_ssl
resp = proxy.send_recv(pkt, 15, false) resp = proxy.send_recv(pkt)
else else
resp = mssql_send_recv(pkt, 15, false) resp = mssql_send_recv(pkt)
end end
# Strip the TDS header # Get default data
resp = resp[3..-1] begin
type3 = ntlm_client.init_context([resp].pack('m')) blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
type3_blob = type3.serialize # a domain.length < 3 will hit this
rescue NTLM_XCEPT::NTLMMissingChallenge
return false
end
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
default_name = blob_data[:default_name] || ''
#netbios domain
default_domain = blob_data[:default_domain] || ''
#dns name
dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
spnopt = {:use_spn => send_spn, :name => rhost}
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
domain_name, default_name, default_domain,
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
spnopt, ntlm_options)
ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
# Create an SSPIMessage # Create an SSPIMessage
idx = 0 idx = 0
pkt = '' pkt = ''
pkt_hdr = '' pkt_hdr = ''
pkt_hdr = [ pkt_hdr = [
TYPE_SSPI_MESSAGE, #type TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
0x0000, # SPID 0x0000, # SPID
0x01, # PacketID 0x01, # PacketID
0x00 #Window 0x00 #Window
] ]
pkt_hdr[2] = type3_blob.length + 8 pkt_hdr[2] = ntlmssp.length + 8
pkt = pkt_hdr.pack("CCnnCC") + type3_blob pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
if self.tdsencryption == true if self.tdsencryption == true
resp = mssql_ssl_send_recv(pkt, proxy) resp = mssql_ssl_send_recv(pkt,proxy)
proxy.cleanup proxy.cleanup
proxy = nil proxy = nil
else else
@ -252,7 +283,7 @@ module Metasploit
pkt << dname pkt << dname
# Total packet length # Total packet length
pkt[0, 4] = [pkt.length].pack('V') pkt[0,4] = [pkt.length].pack('V')
# Embedded packet lengths # Embedded packet lengths
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2 pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@ -263,7 +294,7 @@ module Metasploit
if self.tdsencryption == true if self.tdsencryption == true
proxy = TDSSSLProxy.new(sock) proxy = TDSSSLProxy.new(sock)
proxy.setup_ssl proxy.setup_ssl
resp = mssql_ssl_send_recv(pkt, proxy) resp = mssql_ssl_send_recv(pkt,proxy)
proxy.cleanup proxy.cleanup
proxy = nil proxy = nil
else else
@ -273,7 +304,7 @@ module Metasploit
end end
info = {:errors => []} info = {:errors => []}
info = mssql_parse_reply(resp, info) info = mssql_parse_reply(resp,info)
disconnect disconnect
@ -285,17 +316,17 @@ module Metasploit
# Parse an "environment change" TDS token # Parse an "environment change" TDS token
# #
def mssql_parse_env(data, info) def mssql_parse_env(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
type = buff.slice!(0, 1).unpack('C')[0] type = buff.slice!(0,1).unpack('C')[0]
nval = '' nval = ''
nlen = buff.slice!(0, 1).unpack('C')[0] || 0 nlen = buff.slice!(0,1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0 nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
oval = '' oval = ''
olen = buff.slice!(0, 1).unpack('C')[0] || 0 olen = buff.slice!(0,1).unpack('C')[0] || 0
oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0 oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
info[:envs] ||= [] info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval } info[:envs] << { :type => type, :old => oval, :new => nval }
@ -306,7 +337,7 @@ module Metasploit
# Parse a "ret" TDS token # Parse a "ret" TDS token
# #
def mssql_parse_ret(data, info) def mssql_parse_ret(data, info)
ret = data.slice!(0, 4).unpack('N')[0] ret = data.slice!(0,4).unpack('N')[0]
info[:ret] = ret info[:ret] = ret
info info
end end
@ -315,7 +346,7 @@ module Metasploit
# Parse a "done" TDS token # Parse a "done" TDS token
# #
def mssql_parse_done(data, info) def mssql_parse_done(data, info)
status, cmd, rows = data.slice!(0, 8).unpack('vvV') status,cmd,rows = data.slice!(0,8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows } info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info info
end end
@ -324,11 +355,11 @@ module Metasploit
# Parse an "error" TDS token # Parse an "error" TDS token
# #
def mssql_parse_error(data, info) def mssql_parse_error(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2) emsg = buff.slice!(0,elen * 2)
emsg.gsub!("\x00", '') emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@ -339,14 +370,14 @@ module Metasploit
# Parse an "information" TDS token # Parse an "information" TDS token
# #
def mssql_parse_info(data, info) def mssql_parse_info(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2) emsg = buff.slice!(0,elen * 2)
emsg.gsub!("\x00", '') emsg.gsub!("\x00", '')
info[:infos] ||= [] info[:infos]||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info info
end end
@ -355,8 +386,8 @@ module Metasploit
# Parse a "login ack" TDS token # Parse a "login ack" TDS token
# #
def mssql_parse_login_ack(data, info) def mssql_parse_login_ack(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
_buff = data.slice!(0, len) buff = data.slice!(0,len)
info[:login_ack] = true info[:login_ack] = true
end end
@ -367,7 +398,7 @@ module Metasploit
info[:errors] = [] info[:errors] = []
return if not data return if not data
until data.empty? until data.empty?
token = data.slice!(0, 1).unpack('C')[0] token = data.slice!(0,1).unpack('C')[0]
case token case token
when 0x81 when 0x81
mssql_parse_tds_reply(data, info) mssql_parse_tds_reply(data, info)
@ -403,14 +434,14 @@ module Metasploit
info[:colnames] ||= [] info[:colnames] ||= []
# Parse out the columns # Parse out the columns
cols = data.slice!(0, 2).unpack('v')[0] cols = data.slice!(0,2).unpack('v')[0]
0.upto(cols-1) do |col_idx| 0.upto(cols-1) do |col_idx|
col = {} col = {}
info[:colinfos][col_idx] = col info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0, 2).unpack('v')[0] col[:utype] = data.slice!(0,2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0] col[:flags] = data.slice!(0,2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0] col[:type] = data.slice!(0,1).unpack('C')[0]
case col[:type] case col[:type]
when 48 when 48
@ -427,8 +458,8 @@ module Metasploit
when 34 when 34
col[:id] = :image col[:id] = :image
col[:max_size] = data.slice!(0, 4).unpack('V')[0] col[:max_size] = data.slice!(0,4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0] col[:value_length] = data.slice!(0,2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '') col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36 when 36
@ -436,31 +467,31 @@ module Metasploit
when 38 when 38
col[:id] = :int col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0] col[:int_size] = data.slice!(0,1).unpack('C')[0]
when 127 when 127
col[:id] = :bigint col[:id] = :bigint
when 165 when 165
col[:id] = :hex col[:id] = :hex
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
when 173 when 173
col[:id] = :hex # binary(2) col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
when 231, 175, 167, 239 when 231,175,167,239
col[:id] = :string col[:id] = :string
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0] col[:codepage] = data.slice!(0,2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0] col[:cflags] = data.slice!(0,2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0] col[:charset_id] = data.slice!(0,1).unpack('C')[0]
else else
col[:id] = :unknown col[:id] = :unknown
end end
col[:msg_len] = data.slice!(0, 1).unpack('C')[0] col[:msg_len] = data.slice!(0,1).unpack('C')[0]
if(col[:msg_len] and col[:msg_len] > 0) if(col[:msg_len] and col[:msg_len] > 0)
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '') col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
@ -486,28 +517,28 @@ module Metasploit
case col[:id] case col[:id]
when :hex when :hex
str = "" str = ""
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
if(len > 0 and len < 65535) if(len > 0 and len < 65535)
str << data.slice!(0, len) str << data.slice!(0,len)
end end
row << str.unpack("H*")[0] row << str.unpack("H*")[0]
when :string when :string
str = "" str = ""
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
if(len > 0 and len < 65535) if(len > 0 and len < 65535)
str << data.slice!(0, len) str << data.slice!(0,len)
end end
row << str.gsub("\x00", '') row << str.gsub("\x00", '')
when :datetime when :datetime
row << data.slice!(0, 8).unpack("H*")[0] row << data.slice!(0,8).unpack("H*")[0]
when :rawint when :rawint
row << data.slice!(0, 4).unpack('V')[0] row << data.slice!(0,4).unpack('V')[0]
when :bigint when :bigint
row << data.slice!(0, 8).unpack("H*")[0] row << data.slice!(0,8).unpack("H*")[0]
when :smallint when :smallint
row << data.slice!(0, 2).unpack("v")[0] row << data.slice!(0, 2).unpack("v")[0]
@ -520,8 +551,8 @@ module Metasploit
when :image when :image
str = '' str = ''
len = data.slice!(0, 1).unpack('C')[0] len = data.slice!(0,1).unpack('C')[0]
str = data.slice!(0, len) if (len and len > 0) str = data.slice!(0,len) if (len and len > 0)
row << str.unpack("H*")[0] row << str.unpack("H*")[0]
when :int when :int
@ -529,7 +560,7 @@ module Metasploit
raw = data.slice!(0, len) if (len and len > 0) raw = data.slice!(0, len) if (len and len > 0)
case len case len
when 0, 255 when 0,255
row << '' row << ''
when 1 when 1
row << raw.unpack("C")[0] row << raw.unpack("C")[0]
@ -542,7 +573,7 @@ module Metasploit
when 8 when 8
row << raw.unpack('VV')[0] # XXX: missing high dword row << raw.unpack('VV')[0] # XXX: missing high dword
else else
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}" info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
end end
else else
info[:errors] << "unknown column type: #{col.inspect}" info[:errors] << "unknown column type: #{col.inspect}"
@ -564,7 +595,7 @@ module Metasploit
pkt_data = "" pkt_data = ""
pkt_hdr = [ pkt_hdr = [
TYPE_PRE_LOGIN_MESSAGE, #type TYPE_PRE_LOGIN_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
@ -573,7 +604,7 @@ module Metasploit
0x00 #Window 0x00 #Window
] ]
version = [0x55010008, 0x0000].pack("Vv") version = [0x55010008,0x0000].pack("Vv")
# if manually set, we will honour # if manually set, we will honour
if tdsencryption == true if tdsencryption == true
@ -584,45 +615,45 @@ module Metasploit
instoptdata = "MSSQLServer\0" instoptdata = "MSSQLServer\0"
threadid = "\0\0" + Rex::Text.rand_text(2) threadid = "\0\0" + Rex::Text.rand_text(2)
idx = 21 # size of pkt_data_token idx = 21 # size of pkt_data_token
pkt_data_token << [ pkt_data_token << [
0x00, # Token 0 type Version 0x00, # Token 0 type Version
idx , # VersionOffset idx , # VersionOffset
version.length, # VersionLength version.length, # VersionLength
0x01, # Token 1 type Encryption 0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength 0x01, # EncryptionLength
0x02, # Token 2 type InstOpt 0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength instoptdata.length, # InstOptLength
0x03, # Token 3 type Threadid 0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength 0x04, # ThreadIdLength
0xFF 0xFF
].pack("CnnCnnCnnCnnC") ].pack("CnnCnnCnnCnnC")
pkt_data << pkt_data_token pkt_data << pkt_data_token
pkt_data << version pkt_data << version
pkt_data << encryption pkt_data << encryption
pkt_data << instoptdata pkt_data << instoptdata
pkt_data << threadid pkt_data << threadid
pkt_hdr[2] = pkt_data.length + 8 pkt_hdr[2] = pkt_data.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt_data pkt = pkt_hdr.pack("CCnnCC") + pkt_data
resp = mssql_send_recv(pkt) resp = mssql_send_recv(pkt)
idx = 0 idx = 0
while resp && resp[0, 1] != "\xff" && resp.length > 5 while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0, 5) token = resp.slice!(0,5)
token = token.unpack("Cnn") token = token.unpack("Cnn")
idx -= 5 idx -= 5
if token[0] == 0x01 if token[0] == 0x01
@ -632,7 +663,7 @@ module Metasploit
end end
end end
if idx > 0 if idx > 0
encryption_mode = resp[idx, 1].unpack("C")[0] encryption_mode = resp[idx,1].unpack("C")[0]
else else
raise RunTimeError, "Unable to parse encryption req. "\ raise RunTimeError, "Unable to parse encryption req. "\
"from server during prelogin" "from server during prelogin"
@ -670,8 +701,8 @@ module Metasploit
idx = 0 idx = 0
while resp && resp[0, 1] != "\xff" && resp.length > 5 while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0, 5) token = resp.slice!(0,5)
token = token.unpack("Cnn") token = token.unpack("Cnn")
idx -= 5 idx -= 5
if token[0] == 0x01 if token[0] == 0x01
@ -680,7 +711,7 @@ module Metasploit
end end
end end
if idx > 0 if idx > 0
encryption_mode = resp[idx, 1].unpack("C")[0] encryption_mode = resp[idx,1].unpack("C")[0]
else else
raise RuntimeError, "Unable to parse encryption "\ raise RuntimeError, "Unable to parse encryption "\
"req during pre-login" "req during pre-login"
@ -704,17 +735,17 @@ module Metasploit
while(not done) while(not done)
head = sock.get_once(8, timeout) head = sock.get_once(8, timeout)
if !(head && head.length == 8) if !(head and head.length == 8)
return false return false
end end
# Is this the last buffer? # Is this the last buffer?
if head[1, 1] == "\x01" || !check_status if(head[1,1] == "\x01" or not check_status )
done = true done = true
end end
# Grab this block's length # Grab this block's length
rlen = head[2, 2].unpack('n')[0] - 8 rlen = head[2,2].unpack('n')[0] - 8
while(rlen > 0) while(rlen > 0)
buff = sock.get_once(rlen, timeout) buff = sock.get_once(rlen, timeout)
@ -727,7 +758,7 @@ module Metasploit
resp resp
end end
def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true) def mssql_ssl_send_recv(req,tdsproxy,timeout=15,check_status=true)
tdsproxy.send_recv(req) tdsproxy.send_recv(req)
end end

View File

@ -2,6 +2,10 @@
require 'uri' require 'uri'
require 'digest' require 'digest'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
module Msf module Msf
### ###
@ -12,6 +16,15 @@ module Msf
### ###
module Exploit::Remote::HttpClient module Exploit::Remote::HttpClient
include Msf::Auxiliary::Report include Msf::Auxiliary::Report
include Exploit::Remote::NTLM::Client
#
# Constants
#
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
# #
# Initializes an exploit module that exploits a vulnerability in an HTTP # Initializes an exploit module that exploits a vulnerability in an HTTP
@ -180,6 +193,12 @@ module Exploit::Remote::HttpClient
'uri_fake_end' => datastore['HTTP::uri_fake_end'], 'uri_fake_end' => datastore['HTTP::uri_fake_end'],
'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'], 'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'],
'header_folding' => datastore['HTTP::header_folding'], 'header_folding' => datastore['HTTP::header_folding'],
'usentlm2_session' => datastore['NTLM::UseNTLM2_session'],
'use_ntlmv2' => datastore['NTLM::UseNTLMv2'],
'send_lm' => datastore['NTLM::SendLM'],
'send_ntlm' => datastore['NTLM::SendNTLM'],
'SendSPN' => datastore['NTLM::SendSPN'],
'UseLMKey' => datastore['NTLM::UseLMKey'],
'domain' => datastore['DOMAIN'], 'domain' => datastore['DOMAIN'],
'DigestAuthIIS' => datastore['DigestAuthIIS'] 'DigestAuthIIS' => datastore['DigestAuthIIS']
) )
@ -236,6 +255,12 @@ module Exploit::Remote::HttpClient
evade_uri_fake_end: datastore['HTTP::uri_fake_end'], evade_uri_fake_end: datastore['HTTP::uri_fake_end'],
evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'], evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'],
evade_header_folding: datastore['HTTP::header_folding'], evade_header_folding: datastore['HTTP::header_folding'],
ntlm_use_ntlmv2_session: datastore['NTLM::UseNTLM2_session'],
ntlm_use_ntlmv2: datastore['NTLM::UseNTLMv2'],
ntlm_send_lm: datastore['NTLM::SendLM'],
ntlm_send_ntlm: datastore['NTLM::SendNTLM'],
ntlm_send_spn: datastore['NTLM::SendSPN'],
ntlm_use_lm_key: datastore['NTLM::UseLMKey'],
ntlm_domain: datastore['DOMAIN'], ntlm_domain: datastore['DOMAIN'],
digest_auth_iis: datastore['DigestAuthIIS'] digest_auth_iis: datastore['DigestAuthIIS']
}.merge(conf) }.merge(conf)

View File

@ -1,6 +1,11 @@
# -*- coding: binary -*- # -*- coding: binary -*-
require 'msf/core' require 'msf/core'
require 'msf/core/exploit/mssql_commands' require 'msf/core/exploit/mssql_commands'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
module Msf module Msf
@ -16,32 +21,41 @@ module Exploit::Remote::MSSQL
include Exploit::Remote::Tcp include Exploit::Remote::Tcp
include Exploit::Remote::NTLM::Client include Exploit::Remote::NTLM::Client
#
# Constants
#
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
# Encryption # Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off. ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on. ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available. ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required. ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type # Paquet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement # Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status # Status
STATUS_NORMAL = 0x00 STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01 STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02 STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+ STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
# #
# Creates an instance of a MSSQL exploit module. # Creates an instance of a MSSQL exploit module.
# #
@ -86,13 +100,16 @@ module Exploit::Remote::MSSQL
'MsfExploit' => self, 'MsfExploit' => self,
}) })
ping_sock.put("\x02") ping_sock.put("\x02")
resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout) resp, saddr, sport = ping_sock.recvfrom(65535, timeout)
ping_sock.close ping_sock.close
return data if not resp return data if not resp
return data if resp.length == 0 return data if resp.length == 0
var = nil
return mssql_ping_parse(resp) return mssql_ping_parse(resp)
end end
@ -128,15 +145,15 @@ module Exploit::Remote::MSSQL
# #
# Execute a system command via xp_cmdshell # Execute a system command via xp_cmdshell
# #
def mssql_xpcmdshell(cmd, doprint=false, opts={}) def mssql_xpcmdshell(cmd,doprint=false,opts={})
force_enable = false force_enable = false
begin begin
res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts) res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts)
if res[:errors] && !res[:errors].empty? if(res[:errors] and not res[:errors].empty?)
if res[:errors].join =~ /xp_cmdshell/ if(res[:errors].join =~ /xp_cmdshell/)
if force_enable if(force_enable)
print_error("The xp_cmdshell procedure is not available and could not be enabled") print_error("The xp_cmdshell procedure is not available and could not be enabled")
raise RuntimeError, "Failed to execute command" raise RuntimeError, "Failed to execute command"
else else
print_status("The server may have xp_cmdshell disabled, trying to enable it...") print_status("The server may have xp_cmdshell disabled, trying to enable it...")
mssql_query(mssql_xpcmdshell_enable()) mssql_query(mssql_xpcmdshell_enable())
@ -150,7 +167,7 @@ module Exploit::Remote::MSSQL
return res return res
rescue RuntimeError => e rescue RuntimeError => e
if e.to_s =~ /xp_cmdshell disabled/ if(e.to_s =~ /xp_cmdshell disabled/)
force_enable = true force_enable = true
retry retry
end end
@ -183,7 +200,7 @@ module Exploit::Remote::MSSQL
idx = 0 idx = 0
cnt = 500 cnt = 500
while(idx < hex.length - 1) while(idx < hex.length - 1)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false) mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
idx += cnt idx += cnt
end end
@ -217,7 +234,7 @@ module Exploit::Remote::MSSQL
idx = 0 idx = 0
cnt = 500 cnt = 500
while(idx < hex.length - 1) while(idx < hex.length - 1)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false) mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
idx += cnt idx += cnt
end end
print_status("Converting the payload utilizing PowerShell EncodedCommand...") print_status("Converting the payload utilizing PowerShell EncodedCommand...")
@ -243,17 +260,17 @@ module Exploit::Remote::MSSQL
while(not done) while(not done)
head = sock.get_once(8, timeout) head = sock.get_once(8, timeout)
if !(head && head.length == 8) if !(head and head.length == 8)
return false return false
end end
# Is this the last buffer? # Is this the last buffer?
if(head[1, 1] == "\x01" or not check_status ) if(head[1,1] == "\x01" or not check_status )
done = true done = true
end end
# Grab this block's length # Grab this block's length
rlen = head[2, 2].unpack('n')[0] - 8 rlen = head[2,2].unpack('n')[0] - 8
while(rlen > 0) while(rlen > 0)
buff = sock.get_once(rlen, timeout) buff = sock.get_once(rlen, timeout)
@ -285,77 +302,77 @@ module Exploit::Remote::MSSQL
pkt_data = "" pkt_data = ""
pkt_hdr = [ pkt_hdr = [
TYPE_PRE_LOGIN_MESSAGE, #type TYPE_PRE_LOGIN_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
0x0000, # SPID 0x0000, # SPID
0x00, # PacketID 0x00, # PacketID
0x00 #Window 0x00 #Window
] ]
version = [0x55010008, 0x0000].pack("Vv") version = [0x55010008,0x0000].pack("Vv")
encryption = ENCRYPT_NOT_SUP # off encryption = ENCRYPT_NOT_SUP # off
instoptdata = "MSSQLServer\0" instoptdata = "MSSQLServer\0"
threadid = "\0\0" + Rex::Text.rand_text(2) threadid = "\0\0" + Rex::Text.rand_text(2)
idx = 21 # size of pkt_data_token idx = 21 # size of pkt_data_token
pkt_data_token << [ pkt_data_token << [
0x00, # Token 0 type Version 0x00, # Token 0 type Version
idx, # VersionOffset idx , # VersionOffset
version.length, # VersionLength version.length, # VersionLength
0x01, # Token 1 type Encryption 0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength 0x01, # EncryptionLength
0x02, # Token 2 type InstOpt 0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength instoptdata.length, # InstOptLength
0x03, # Token 3 type Threadid 0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength 0x04, # ThreadIdLength
0xFF 0xFF
].pack("CnnCnnCnnCnnC") ].pack("CnnCnnCnnCnnC")
pkt_data << pkt_data_token pkt_data << pkt_data_token
pkt_data << version pkt_data << version
pkt_data << encryption pkt_data << encryption
pkt_data << instoptdata pkt_data << instoptdata
pkt_data << threadid pkt_data << threadid
pkt_hdr[2] = pkt_data.length + 8 pkt_hdr[2] = pkt_data.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt_data pkt = pkt_hdr.pack("CCnnCC") + pkt_data
resp = mssql_send_recv(pkt) resp = mssql_send_recv(pkt)
idx = 0 idx = 0
while resp && resp[0, 1] != "\xff" && resp.length > 5 while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0, 5) token = resp.slice!(0,5)
token = token.unpack("Cnn") token = token.unpack("Cnn")
idx -= 5 idx -= 5
if token[0] == 0x01 if token[0] == 0x01
idx += token[1]
break idx += token[1]
break
end
end
if idx > 0
encryption_mode = resp[idx,1].unpack("C")[0]
else
#force to ENCRYPT_NOT_SUP and hope for the best
encryption_mode = ENCRYPT_NOT_SUP
end end
end
if idx > 0 if encryption_mode != ENCRYPT_NOT_SUP and enc_error
encryption_mode = resp[idx, 1].unpack("C")[0] raise RuntimeError,"Encryption is not supported"
else end
# force to ENCRYPT_NOT_SUP and hope for the best encryption_mode
encryption_mode = ENCRYPT_NOT_SUP
end
if encryption_mode != ENCRYPT_NOT_SUP && enc_error
raise RuntimeError,"Encryption is not supported"
end
encryption_mode
end end
# #
@ -384,14 +401,14 @@ module Exploit::Remote::MSSQL
idx = 0 idx = 0
pkt = '' pkt = ''
pkt_hdr = '' pkt_hdr = ''
pkt_hdr = [ pkt_hdr = [
TYPE_TDS7_LOGIN, #type TYPE_TDS7_LOGIN, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
0x0000, # SPID 0x0000, # SPID
0x01, # PacketID (unused upon specification 0x01, # PacketID (unused upon specification
# but ms network monitor stil prefer 1 to decode correctly, wireshark don't care) # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
0x00 #Window 0x00 #Window
] ]
pkt << [ pkt << [
@ -414,18 +431,19 @@ module Exploit::Remote::MSSQL
sname = Rex::Text.to_unicode( rhost ) sname = Rex::Text.to_unicode( rhost )
dname = Rex::Text.to_unicode( db ) dname = Rex::Text.to_unicode( db )
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) ntlm_options = {
:signing => false,
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
:send_lm => datastore['NTLM::SendLM'],
:send_ntlm => datastore['NTLM::SendNTLM']
}
ntlm_client = ::Net::NTLM::Client.new( ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
user, workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
pass, domain_name = datastore['DOMAIN']
workstation: workstation_name,
domain: datastore['DOMAIN'], ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
)
type1 = ntlm_client.init_context
# SQL 2012, at least, does not support KEY_EXCHANGE
type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
ntlmsspblob = type1.serialize
idx = pkt.size + 50 # lengths below idx = pkt.size + 50 # lengths below
@ -466,9 +484,9 @@ module Exploit::Remote::MSSQL
pkt << ntlmsspblob pkt << ntlmsspblob
# Total packet length # Total packet length
pkt[0, 4] = [pkt.length].pack('V') pkt[0,4] = [pkt.length].pack('V')
pkt_hdr[2] = pkt.length + 8 pkt_hdr[2] = pkt.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt pkt = pkt_hdr.pack("CCnnCC") + pkt
@ -476,36 +494,56 @@ module Exploit::Remote::MSSQL
# has a strange behavior that differs from the specifications # has a strange behavior that differs from the specifications
# upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
# is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
resp = mssql_send_recv(pkt, 15, false) resp = mssql_send_recv(pkt,15, false)
unless resp.include?("NTLMSSP") # Get default data
begin
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
# a domain.length < 3 will hit this
rescue NTLM_XCEPT::NTLMMissingChallenge
info = {:errors => []} info = {:errors => []}
mssql_parse_reply(resp, info) mssql_parse_reply(resp, info)
mssql_print_reply(info) mssql_print_reply(info)
return false return false
end end
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
default_name = blob_data[:default_name] || ''
#netbios domain
default_domain = blob_data[:default_domain] || ''
#dns name
dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
# Get default data spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
resp = resp[3..-1]
type3 = ntlm_client.init_context([resp].pack('m')) resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
type3_blob = type3.serialize domain_name, default_name, default_domain,
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
spnopt, ntlm_options)
ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
# Create an SSPIMessage # Create an SSPIMessage
idx = 0 idx = 0
pkt = '' pkt = ''
pkt_hdr = '' pkt_hdr = ''
pkt_hdr = [ pkt_hdr = [
TYPE_SSPI_MESSAGE, #type TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status STATUS_END_OF_MESSAGE, #status
0x0000, #length 0x0000, #length
0x0000, # SPID 0x0000, # SPID
0x01, # PacketID 0x01, # PacketID
0x00 #Window 0x00 #Window
] ]
pkt_hdr[2] = type3_blob.length + 8 pkt_hdr[2] = ntlmssp.length + 8
pkt = pkt_hdr.pack("CCnnCC") + type3_blob pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
resp = mssql_send_recv(pkt) resp = mssql_send_recv(pkt)
@ -582,7 +620,7 @@ module Exploit::Remote::MSSQL
pkt << dname pkt << dname
# Total packet length # Total packet length
pkt[0, 4] = [pkt.length].pack('V') pkt[0,4] = [pkt.length].pack('V')
# Embedded packet lengths # Embedded packet lengths
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2 pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@ -599,7 +637,7 @@ module Exploit::Remote::MSSQL
end end
info = {:errors => []} info = {:errors => []}
info = mssql_parse_reply(resp, info) info = mssql_parse_reply(resp,info)
return false if not info return false if not info
info[:login_ack] ? true : false info[:login_ack] ? true : false
@ -652,17 +690,17 @@ module Exploit::Remote::MSSQL
print_status("SQL Query: #{info[:sql]}") print_status("SQL Query: #{info[:sql]}")
if info[:done] && info[:done][:rows].to_i > 0 if(info[:done] and info[:done][:rows].to_i > 0)
print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})") print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})")
end end
if info[:errors] && !info[:errors].empty? if(info[:errors] and not info[:errors].empty?)
info[:errors].each do |err| info[:errors].each do |err|
print_error(err) print_error(err)
end end
end end
if info[:rows] && !info[:rows].empty? if(info[:rows] and not info[:rows].empty?)
tbl = Rex::Ui::Text::Table.new( tbl = Rex::Ui::Text::Table.new(
'Indent' => 1, 'Indent' => 1,
@ -689,14 +727,14 @@ module Exploit::Remote::MSSQL
info[:colnames] ||= [] info[:colnames] ||= []
# Parse out the columns # Parse out the columns
cols = data.slice!(0, 2).unpack('v')[0] cols = data.slice!(0,2).unpack('v')[0]
0.upto(cols-1) do |col_idx| 0.upto(cols-1) do |col_idx|
col = {} col = {}
info[:colinfos][col_idx] = col info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0, 2).unpack('v')[0] col[:utype] = data.slice!(0,2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0] col[:flags] = data.slice!(0,2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0] col[:type] = data.slice!(0,1).unpack('C')[0]
case col[:type] case col[:type]
when 48 when 48
@ -713,8 +751,8 @@ module Exploit::Remote::MSSQL
when 34 when 34
col[:id] = :image col[:id] = :image
col[:max_size] = data.slice!(0, 4).unpack('V')[0] col[:max_size] = data.slice!(0,4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0] col[:value_length] = data.slice!(0,2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '') col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36 when 36
@ -722,33 +760,33 @@ module Exploit::Remote::MSSQL
when 38 when 38
col[:id] = :int col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0] col[:int_size] = data.slice!(0,1).unpack('C')[0]
when 127 when 127
col[:id] = :bigint col[:id] = :bigint
when 165 when 165
col[:id] = :hex col[:id] = :hex
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
when 173 when 173
col[:id] = :hex # binary(2) col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
when 231, 175, 167, 239 when 231,175,167,239
col[:id] = :string col[:id] = :string
col[:max_size] = data.slice!(0, 2).unpack('v')[0] col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0] col[:codepage] = data.slice!(0,2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0] col[:cflags] = data.slice!(0,2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0] col[:charset_id] = data.slice!(0,1).unpack('C')[0]
else else
col[:id] = :unknown col[:id] = :unknown
end end
col[:msg_len] = data.slice!(0, 1).unpack('C')[0] col[:msg_len] = data.slice!(0,1).unpack('C')[0]
if col[:msg_len] && col[:msg_len] > 0 if(col[:msg_len] and col[:msg_len] > 0)
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '') col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
end end
info[:colnames] << (col[:name] || 'NULL') info[:colnames] << (col[:name] || 'NULL')
@ -762,7 +800,7 @@ module Exploit::Remote::MSSQL
info[:errors] = [] info[:errors] = []
return if not data return if not data
until data.empty? until data.empty?
token = data.slice!(0, 1).unpack('C')[0] token = data.slice!(0,1).unpack('C')[0]
case token case token
when 0x81 when 0x81
mssql_parse_tds_reply(data, info) mssql_parse_tds_reply(data, info)
@ -806,28 +844,28 @@ module Exploit::Remote::MSSQL
case col[:id] case col[:id]
when :hex when :hex
str = "" str = ""
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
if len > 0 && len < 65535 if(len > 0 and len < 65535)
str << data.slice!(0, len) str << data.slice!(0,len)
end end
row << str.unpack("H*")[0] row << str.unpack("H*")[0]
when :string when :string
str = "" str = ""
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
if len > 0 && len < 65535 if(len > 0 and len < 65535)
str << data.slice!(0, len) str << data.slice!(0,len)
end end
row << str.gsub("\x00", '') row << str.gsub("\x00", '')
when :datetime when :datetime
row << data.slice!(0, 8).unpack("H*")[0] row << data.slice!(0,8).unpack("H*")[0]
when :rawint when :rawint
row << data.slice!(0, 4).unpack('V')[0] row << data.slice!(0,4).unpack('V')[0]
when :bigint when :bigint
row << data.slice!(0, 8).unpack("H*")[0] row << data.slice!(0,8).unpack("H*")[0]
when :smallint when :smallint
row << data.slice!(0, 2).unpack("v")[0] row << data.slice!(0, 2).unpack("v")[0]
@ -840,16 +878,16 @@ module Exploit::Remote::MSSQL
when :image when :image
str = '' str = ''
len = data.slice!(0, 1).unpack('C')[0] len = data.slice!(0,1).unpack('C')[0]
str = data.slice!(0, len) if len && len > 0 str = data.slice!(0,len) if (len and len > 0)
row << str.unpack("H*")[0] row << str.unpack("H*")[0]
when :int when :int
len = data.slice!(0, 1).unpack("C")[0] len = data.slice!(0, 1).unpack("C")[0]
raw = data.slice!(0, len) if len && len > 0 raw = data.slice!(0, len) if (len and len > 0)
case len case len
when 0, 255 when 0,255
row << '' row << ''
when 1 when 1
row << raw.unpack("C")[0] row << raw.unpack("C")[0]
@ -862,7 +900,7 @@ module Exploit::Remote::MSSQL
when 8 when 8
row << raw.unpack('VV')[0] # XXX: missing high dword row << raw.unpack('VV')[0] # XXX: missing high dword
else else
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}" info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
end end
else else
info[:errors] << "unknown column type: #{col.inspect}" info[:errors] << "unknown column type: #{col.inspect}"
@ -877,7 +915,7 @@ module Exploit::Remote::MSSQL
# Parse a "ret" TDS token # Parse a "ret" TDS token
# #
def mssql_parse_ret(data, info) def mssql_parse_ret(data, info)
ret = data.slice!(0, 4).unpack('N')[0] ret = data.slice!(0,4).unpack('N')[0]
info[:ret] = ret info[:ret] = ret
info info
end end
@ -886,7 +924,7 @@ module Exploit::Remote::MSSQL
# Parse a "done" TDS token # Parse a "done" TDS token
# #
def mssql_parse_done(data, info) def mssql_parse_done(data, info)
status, cmd, rows = data.slice!(0, 8).unpack('vvV') status,cmd,rows = data.slice!(0,8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows } info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info info
end end
@ -895,11 +933,11 @@ module Exploit::Remote::MSSQL
# Parse an "error" TDS token # Parse an "error" TDS token
# #
def mssql_parse_error(data, info) def mssql_parse_error(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2) emsg = buff.slice!(0,elen * 2)
emsg.gsub!("\x00", '') emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@ -910,17 +948,17 @@ module Exploit::Remote::MSSQL
# Parse an "environment change" TDS token # Parse an "environment change" TDS token
# #
def mssql_parse_env(data, info) def mssql_parse_env(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
type = buff.slice!(0, 1).unpack('C')[0] type = buff.slice!(0,1).unpack('C')[0]
nval = '' nval = ''
nlen = buff.slice!(0, 1).unpack('C')[0] || 0 nlen = buff.slice!(0,1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0 nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
oval = '' oval = ''
olen = buff.slice!(0, 1).unpack('C')[0] || 0 olen = buff.slice!(0,1).unpack('C')[0] || 0
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0 oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
info[:envs] ||= [] info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval } info[:envs] << { :type => type, :old => oval, :new => nval }
@ -931,14 +969,14 @@ module Exploit::Remote::MSSQL
# Parse an "information" TDS token # Parse an "information" TDS token
# #
def mssql_parse_info(data, info) def mssql_parse_info(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0, len) buff = data.slice!(0,len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2) emsg = buff.slice!(0,elen * 2)
emsg.gsub!("\x00", '') emsg.gsub!("\x00", '')
info[:infos] ||= [] info[:infos]||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info info
end end
@ -947,8 +985,8 @@ module Exploit::Remote::MSSQL
# Parse a "login ack" TDS token # Parse a "login ack" TDS token
# #
def mssql_parse_login_ack(data, info) def mssql_parse_login_ack(data, info)
len = data.slice!(0, 2).unpack('v')[0] len = data.slice!(0,2).unpack('v')[0]
_buff = data.slice!(0, len) buff = data.slice!(0,len)
info[:login_ack] = true info[:login_ack] = true
end end
end end

View File

@ -17,6 +17,12 @@ module Msf
module Exploit::NTLM module Exploit::NTLM
NTLM_CONST = ::Rex::Proto::NTLM::Constants
NTLM_CRYPT = ::Rex::Proto::NTLM::Crypt
NTLM_UTILS = ::Rex::Proto::NTLM::Utils
NTLM_BASE = ::Rex::Proto::NTLM::Base
NTLM_MESSAGE = ::Rex::Proto::NTLM::Message
module Client module Client
def initialize(info = {}) def initialize(info = {})
super super

View File

@ -3,6 +3,10 @@ require 'rex/socket'
require 'rex/proto/http' require 'rex/proto/http'
require 'rex/text' require 'rex/text'
require 'digest' require 'digest'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
require 'rex/proto/http/client_request' require 'rex/proto/http/client_request'
@ -309,6 +313,7 @@ class Client
# Send a series of requests to complete Digest Authentication # Send a series of requests to complete Digest Authentication
# #
# @param opts [Hash] the options used to build an HTTP request # @param opts [Hash] the options used to build an HTTP request
#
# @return [Response] the last valid HTTP response we received # @return [Response] the last valid HTTP response we received
def digest_auth(opts={}) def digest_auth(opts={})
@nonce_count = 0 @nonce_count = 0
@ -452,6 +457,13 @@ class Client
# #
# @return [Response] the last valid HTTP response we received # @return [Response] the last valid HTTP response we received
def negotiate_auth(opts={}) def negotiate_auth(opts={})
ntlm_options = {
:signing => false,
:usentlm2_session => self.config['usentlm2_session'],
:use_ntlmv2 => self.config['use_ntlmv2'],
:send_lm => self.config['send_lm'],
:send_ntlm => self.config['send_ntlm']
}
to = opts['timeout'] || 20 to = opts['timeout'] || 20
opts['username'] ||= '' opts['username'] ||= ''
@ -460,27 +472,28 @@ class Client
if opts['provider'] and opts['provider'].include? 'Negotiate' if opts['provider'] and opts['provider'].include? 'Negotiate'
provider = "Negotiate " provider = "Negotiate "
else else
provider = "NTLM " provider = 'NTLM '
end end
opts['method']||= 'GET' opts['method']||= 'GET'
opts['headers']||= {} opts['headers']||= {}
ntlmssp_flags = ::Rex::Proto::NTLM::Utils.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+6) workstation_name = Rex::Text.rand_text_alpha(rand(8)+6)
domain_name = self.config['domain'] domain_name = self.config['domain']
ntlm_client = ::Net::NTLM::Client.new( b64_blob = Rex::Text::encode_base64(
opts['username'], ::Rex::Proto::NTLM::Utils::make_ntlmssp_blob_init(
opts['password'], domain_name,
workstation: workstation_name, workstation_name,
domain: domain_name, ntlmssp_flags
) ))
type1 = ntlm_client.init_context
ntlm_message_1 = provider + b64_blob
begin begin
# First request to get the challenge # First request to get the challenge
opts['headers']['Authorization'] = provider + type1.encode64 opts['headers']['Authorization'] = ntlm_message_1
r = request_cgi(opts) r = request_cgi(opts)
resp = _send_recv(r, to) resp = _send_recv(r, to)
unless resp.kind_of? Rex::Proto::Http::Response unless resp.kind_of? Rex::Proto::Http::Response
@ -493,10 +506,47 @@ class Client
ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0] ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0]
return resp unless ntlm_challenge return resp unless ntlm_challenge
ntlm_message_3 = ntlm_client.init_context(ntlm_challenge) ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
blob_data = ::Rex::Proto::NTLM::Utils.parse_ntlm_type_2_blob(ntlm_message_2)
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
default_name = blob_data[:default_name] || '' #netbios name
default_domain = blob_data[:default_domain] || '' #netbios domain
dns_host_name = blob_data[:dns_host_name] || '' #dns name
dns_domain_name = blob_data[:dns_domain_name] || '' #dns domain
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' #Client time
spnopt = {:use_spn => self.config['SendSPN'], :name => self.hostname}
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = ::Rex::Proto::NTLM::Utils.create_lm_ntlm_responses(
opts['username'],
opts['password'],
challenge_key,
domain_name,
default_name,
default_domain,
dns_host_name,
dns_domain_name,
chall_MsvAvTimestamp,
spnopt,
ntlm_options
)
ntlm_message_3 = ::Rex::Proto::NTLM::Utils.make_ntlmssp_blob_auth(
domain_name,
workstation_name,
opts['username'],
resp_lm,
resp_ntlm,
'',
ntlmssp_flags
)
ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
# Send the response # Send the response
opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3.encode64}" opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3}"
r = request_cgi(opts) r = request_cgi(opts)
resp = _send_recv(r, to, true) resp = _send_recv(r, to, true)
unless resp.kind_of? Rex::Proto::Http::Response unless resp.kind_of? Rex::Proto::Http::Response
@ -508,7 +558,6 @@ class Client
return nil return nil
end end
end end
# #
# Read a response from the server # Read a response from the server
# #
@ -664,6 +713,7 @@ protected
attr_accessor :hostname, :port # :nodoc: attr_accessor :hostname, :port # :nodoc:
end end
end end

View File

@ -4,8 +4,6 @@ module Proto
module SMB module SMB
class Client class Client
require 'net/ntlm'
require 'rex/text' require 'rex/text'
require 'rex/struct2' require 'rex/struct2'
require 'rex/proto/smb/constants' require 'rex/proto/smb/constants'
@ -625,15 +623,16 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Authenticate and establish a session # Authenticate and establish a session
def session_setup(user='', pass='', domain='', do_recv=true) def session_setup(*args)
if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/) if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
if (self.challenge_key) if (self.challenge_key)
return self.session_setup_no_ntlmssp(user, pass, domain, do_recv) return self.session_setup_no_ntlmssp(*args)
end end
if ( self.extended_security ) if ( self.extended_security )
return self.session_setup_with_ntlmssp(user, pass, domain, nil, do_recv) return self.session_setup_with_ntlmssp(*args)
end end
end end
@ -832,16 +831,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
name = Rex::Text.rand_text_alphanumeric(16) name = Rex::Text.rand_text_alphanumeric(16)
end end
@ntlm_client = Net::NTLM::Client.new( blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
user,
pass,
workstation: name,
domain: domain,
flags: ntlmssp_flags
)
blob = @ntlm_client.init_context.serialize
native_data = '' native_data = ''
native_data << self.native_os + "\x00" native_data << self.native_os + "\x00"
@ -902,9 +892,37 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Save the temporary UserID for use in the next request # Save the temporary UserID for use in the next request
temp_user_id = ack['Payload']['SMB'].v['UserID'] temp_user_id = ack['Payload']['SMB'].v['UserID']
type3 = @ntlm_client.init_context([blob].pack('m')) # Get default data
type3_blob = type3.serialize blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
self.signing_key = @ntlm_client.session_key self.challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
self.default_name = blob_data[:default_name] || ''
#netbios domain
self.default_domain = blob_data[:default_domain] || ''
#dns name
self.dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
self.dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain,
default_name, default_domain, dns_host_name,
dns_domain_name, chall_MsvAvTimestamp ,
self.spnopt, ntlm_options)
enc_session_key = ''
self.sequence_counter = 0
if self.require_signing
self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain,
self.challenge_key, client_challenge, ntlm_cli_challenge,
ntlm_options)
end
# Create the security blob data
blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags)
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB']) self.smb_defaults(pkt['Payload']['SMB'])
@ -926,8 +944,8 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
pkt['Payload'].v['VCNum'] = 1 pkt['Payload'].v['VCNum'] = 1
pkt['Payload'].v['Capabilities'] = 0x8000d05c pkt['Payload'].v['Capabilities'] = 0x8000d05c
pkt['Payload'].v['SessionKey'] = self.session_id pkt['Payload'].v['SessionKey'] = self.session_id
pkt['Payload'].v['SecurityBlobLen'] = type3_blob.length pkt['Payload'].v['SecurityBlobLen'] = blob.length
pkt['Payload'].v['Payload'] = type3_blob + native_data pkt['Payload'].v['Payload'] = blob + native_data
# NOTE: if do_recv is set to false, we cant reach here... # NOTE: if do_recv is set to false, we cant reach here...
self.smb_send(pkt.to_s) self.smb_send(pkt.to_s)
@ -1753,7 +1771,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Remove the NetBIOS header # Remove the NetBIOS header
resp_rpkt.slice!(0, 4) resp_rpkt.slice!(0, 4)
_resp_parm = resp_rpkt[poff, pcnt] resp_parm = resp_rpkt[poff, pcnt]
resp_data = resp_rpkt[doff, dcnt] resp_data = resp_rpkt[doff, dcnt]
return resp_data return resp_data
@ -1779,7 +1797,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Remove the NetBIOS header # Remove the NetBIOS header
resp_rpkt.slice!(0, 4) resp_rpkt.slice!(0, 4)
_resp_parm = resp_rpkt[poff, pcnt] resp_parm = resp_rpkt[poff, pcnt]
resp_data = resp_rpkt[doff, dcnt] resp_data = resp_rpkt[doff, dcnt]
return resp_data return resp_data
@ -2012,9 +2030,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Creates a new directory on the mounted tree # Creates a new directory on the mounted tree
def create_directory(name) def create_directory(name)
files = { }
parm = [0].pack('V') + name + "\x00" parm = [0].pack('V') + name + "\x00"
resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '') resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
resp
end end
# public read/write methods # public read/write methods

View File

@ -75,8 +75,6 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'msgpack' spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS. # get list of network interfaces, like eth* from OS.
spec.add_runtime_dependency 'network_interface' spec.add_runtime_dependency 'network_interface'
# NTLM authentication
spec.add_runtime_dependency 'rubyntlm'
# Needed by anemone crawler # Needed by anemone crawler
spec.add_runtime_dependency 'nokogiri' spec.add_runtime_dependency 'nokogiri'
# Needed by db.rb and Msf::Exploit::Capture # Needed by db.rb and Msf::Exploit::Capture

View File

@ -31,7 +31,7 @@ class MetasploitModule < Msf::Auxiliary
def run_host(ip) def run_host(ip)
if !mssql_login_datastore if !mssql_login_datastore
print_error("Invalid SQL Server credentials") print_error("#{rhost}:#{rport} - Invalid SQL Server credentials")
return return
end end
@ -150,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary
login = create_credential_login(login_data) login = create_credential_login(login_data)
tbl << [row[0], row[1]] tbl << [row[0], row[1]]
print_good("Saving #{hashtype} = #{row[0]}:#{row[1]}") print_good("#{rhost}:#{rport} - Saving #{hashtype} = #{row[0]}:#{row[1]}")
end end
end end
@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary
is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0] is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]
if is_sysadmin == 0 if is_sysadmin == 0
print_error("The provided credentials do not have privileges to read the password hashes") print_error("#{rhost}:#{rport} - The provided credentials do not have privileges to read the password hashes")
return nil return nil
end end