mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-09-11 17:08:02 +02:00
Revert "Revert "Land #7009, egypt's rubyntlm cleanup""
This reverts commit 1164c025a2
.
This commit is contained in:
parent
82e092c2df
commit
cfb56211e7
@ -36,6 +36,7 @@ PATH
|
||||
rex-text
|
||||
rex-zip
|
||||
robots
|
||||
rubyntlm
|
||||
rubyzip
|
||||
sqlite3
|
||||
sshkey
|
||||
|
@ -9,11 +9,6 @@ module Metasploit
|
||||
extend ActiveSupport::Concern
|
||||
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
|
||||
ENCRYPT_OFF = 0x00 #Encryption is available but off.
|
||||
ENCRYPT_ON = 0x01 #Encryption is available and on.
|
||||
@ -85,18 +80,18 @@ module Metasploit
|
||||
sname = Rex::Text.to_unicode( rhost )
|
||||
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)
|
||||
|
||||
ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
|
||||
ntlm_client = ::Net::NTLM::Client.new(
|
||||
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
|
||||
|
||||
@ -147,44 +142,18 @@ module Metasploit
|
||||
# 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
|
||||
# is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
|
||||
|
||||
if tdsencryption == true
|
||||
proxy = TDSSSLProxy.new(sock)
|
||||
proxy.setup_ssl
|
||||
resp = proxy.send_recv(pkt)
|
||||
resp = proxy.send_recv(pkt, 15, false)
|
||||
else
|
||||
resp = mssql_send_recv(pkt)
|
||||
resp = mssql_send_recv(pkt, 15, false)
|
||||
end
|
||||
|
||||
# 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
|
||||
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)
|
||||
# Strip the TDS header
|
||||
resp = resp[3..-1]
|
||||
type3 = ntlm_client.init_context([resp].pack('m'))
|
||||
type3_blob = type3.serialize
|
||||
|
||||
# Create an SSPIMessage
|
||||
idx = 0
|
||||
@ -199,9 +168,9 @@ module Metasploit
|
||||
0x00 #Window
|
||||
]
|
||||
|
||||
pkt_hdr[2] = ntlmssp.length + 8
|
||||
pkt_hdr[2] = type3_blob.length + 8
|
||||
|
||||
pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
|
||||
pkt = pkt_hdr.pack("CCnnCC") + type3_blob
|
||||
|
||||
if self.tdsencryption == true
|
||||
resp = mssql_ssl_send_recv(pkt, proxy)
|
||||
@ -387,7 +356,7 @@ module Metasploit
|
||||
#
|
||||
def mssql_parse_login_ack(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0,len)
|
||||
_buff = data.slice!(0, len)
|
||||
info[:login_ack] = true
|
||||
end
|
||||
|
||||
@ -652,7 +621,7 @@ module Metasploit
|
||||
|
||||
idx = 0
|
||||
|
||||
while resp and resp[0,1] != "\xff" and resp.length > 5
|
||||
while resp && resp[0, 1] != "\xff" && resp.length > 5
|
||||
token = resp.slice!(0, 5)
|
||||
token = token.unpack("Cnn")
|
||||
idx -= 5
|
||||
@ -701,7 +670,7 @@ module Metasploit
|
||||
|
||||
idx = 0
|
||||
|
||||
while resp and resp[0,1] != "\xff" and resp.length > 5
|
||||
while resp && resp[0, 1] != "\xff" && resp.length > 5
|
||||
token = resp.slice!(0, 5)
|
||||
token = token.unpack("Cnn")
|
||||
idx -= 5
|
||||
@ -735,12 +704,12 @@ module Metasploit
|
||||
|
||||
while(not done)
|
||||
head = sock.get_once(8, timeout)
|
||||
if !(head and head.length == 8)
|
||||
if !(head && head.length == 8)
|
||||
return false
|
||||
end
|
||||
|
||||
# Is this the last buffer?
|
||||
if(head[1,1] == "\x01" or not check_status )
|
||||
if head[1, 1] == "\x01" || !check_status
|
||||
done = true
|
||||
end
|
||||
|
||||
|
@ -2,10 +2,6 @@
|
||||
|
||||
require 'uri'
|
||||
require 'digest'
|
||||
require 'rex/proto/ntlm/crypt'
|
||||
require 'rex/proto/ntlm/constants'
|
||||
require 'rex/proto/ntlm/utils'
|
||||
require 'rex/proto/ntlm/exceptions'
|
||||
module Msf
|
||||
|
||||
###
|
||||
@ -16,15 +12,6 @@ module Msf
|
||||
###
|
||||
module Exploit::Remote::HttpClient
|
||||
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
|
||||
@ -193,12 +180,6 @@ module Exploit::Remote::HttpClient
|
||||
'uri_fake_end' => datastore['HTTP::uri_fake_end'],
|
||||
'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'],
|
||||
'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'],
|
||||
'DigestAuthIIS' => datastore['DigestAuthIIS']
|
||||
)
|
||||
@ -255,12 +236,6 @@ module Exploit::Remote::HttpClient
|
||||
evade_uri_fake_end: datastore['HTTP::uri_fake_end'],
|
||||
evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'],
|
||||
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'],
|
||||
digest_auth_iis: datastore['DigestAuthIIS']
|
||||
}.merge(conf)
|
||||
|
@ -1,11 +1,6 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
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
|
||||
|
||||
@ -21,21 +16,13 @@ module Exploit::Remote::MSSQL
|
||||
include Exploit::Remote::Tcp
|
||||
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
|
||||
ENCRYPT_OFF = 0x00 #Encryption is available but off.
|
||||
ENCRYPT_ON = 0x01 #Encryption is available and on.
|
||||
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
|
||||
ENCRYPT_REQ = 0x03 #Encryption is required.
|
||||
|
||||
# Paquet Type
|
||||
# Packet Type
|
||||
TYPE_SQL_BATCH = 1 # (Client) SQL command
|
||||
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
|
||||
TYPE_RPC = 3 # (Client) RPC
|
||||
@ -55,7 +42,6 @@ module Exploit::Remote::MSSQL
|
||||
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
|
||||
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
|
||||
|
||||
|
||||
#
|
||||
# Creates an instance of a MSSQL exploit module.
|
||||
#
|
||||
@ -100,16 +86,13 @@ module Exploit::Remote::MSSQL
|
||||
'MsfExploit' => self,
|
||||
})
|
||||
|
||||
|
||||
ping_sock.put("\x02")
|
||||
resp, saddr, sport = ping_sock.recvfrom(65535, timeout)
|
||||
resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout)
|
||||
ping_sock.close
|
||||
|
||||
return data if not resp
|
||||
return data if resp.length == 0
|
||||
|
||||
var = nil
|
||||
|
||||
return mssql_ping_parse(resp)
|
||||
end
|
||||
|
||||
@ -149,9 +132,9 @@ module Exploit::Remote::MSSQL
|
||||
force_enable = false
|
||||
begin
|
||||
res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts)
|
||||
if(res[:errors] and not res[:errors].empty?)
|
||||
if(res[:errors].join =~ /xp_cmdshell/)
|
||||
if(force_enable)
|
||||
if res[:errors] && !res[:errors].empty?
|
||||
if res[:errors].join =~ /xp_cmdshell/
|
||||
if force_enable
|
||||
print_error("The xp_cmdshell procedure is not available and could not be enabled")
|
||||
raise RuntimeError, "Failed to execute command"
|
||||
else
|
||||
@ -167,7 +150,7 @@ module Exploit::Remote::MSSQL
|
||||
return res
|
||||
|
||||
rescue RuntimeError => e
|
||||
if(e.to_s =~ /xp_cmdshell disabled/)
|
||||
if e.to_s =~ /xp_cmdshell disabled/
|
||||
force_enable = true
|
||||
retry
|
||||
end
|
||||
@ -260,7 +243,7 @@ module Exploit::Remote::MSSQL
|
||||
|
||||
while(not done)
|
||||
head = sock.get_once(8, timeout)
|
||||
if !(head and head.length == 8)
|
||||
if !(head && head.length == 8)
|
||||
return false
|
||||
end
|
||||
|
||||
@ -352,16 +335,16 @@ module Exploit::Remote::MSSQL
|
||||
|
||||
idx = 0
|
||||
|
||||
while resp and resp[0,1] != "\xff" and resp.length > 5
|
||||
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
|
||||
@ -369,7 +352,7 @@ module Exploit::Remote::MSSQL
|
||||
encryption_mode = ENCRYPT_NOT_SUP
|
||||
end
|
||||
|
||||
if encryption_mode != ENCRYPT_NOT_SUP and enc_error
|
||||
if encryption_mode != ENCRYPT_NOT_SUP && enc_error
|
||||
raise RuntimeError,"Encryption is not supported"
|
||||
end
|
||||
encryption_mode
|
||||
@ -431,19 +414,18 @@ module Exploit::Remote::MSSQL
|
||||
sname = Rex::Text.to_unicode( rhost )
|
||||
dname = Rex::Text.to_unicode( db )
|
||||
|
||||
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']
|
||||
}
|
||||
|
||||
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
|
||||
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
|
||||
domain_name = datastore['DOMAIN']
|
||||
|
||||
ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
|
||||
ntlm_client = ::Net::NTLM::Client.new(
|
||||
user,
|
||||
pass,
|
||||
workstation: workstation_name,
|
||||
domain: datastore['DOMAIN'],
|
||||
)
|
||||
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
|
||||
|
||||
@ -496,37 +478,17 @@ module Exploit::Remote::MSSQL
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
unless resp.include?("NTLMSSP")
|
||||
info = {:errors => []}
|
||||
mssql_parse_reply(resp, info)
|
||||
mssql_print_reply(info)
|
||||
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 => datastore['NTLM::SendSPN'], :name => self.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)
|
||||
# Get default data
|
||||
resp = resp[3..-1]
|
||||
type3 = ntlm_client.init_context([resp].pack('m'))
|
||||
type3_blob = type3.serialize
|
||||
|
||||
# Create an SSPIMessage
|
||||
idx = 0
|
||||
@ -541,9 +503,9 @@ module Exploit::Remote::MSSQL
|
||||
0x00 #Window
|
||||
]
|
||||
|
||||
pkt_hdr[2] = ntlmssp.length + 8
|
||||
pkt_hdr[2] = type3_blob.length + 8
|
||||
|
||||
pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
|
||||
pkt = pkt_hdr.pack("CCnnCC") + type3_blob
|
||||
|
||||
resp = mssql_send_recv(pkt)
|
||||
|
||||
@ -690,17 +652,17 @@ module Exploit::Remote::MSSQL
|
||||
|
||||
print_status("SQL Query: #{info[:sql]}")
|
||||
|
||||
if(info[:done] and info[:done][:rows].to_i > 0)
|
||||
if info[:done] && info[:done][:rows].to_i > 0
|
||||
print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})")
|
||||
end
|
||||
|
||||
if(info[:errors] and not info[:errors].empty?)
|
||||
if info[:errors] && !info[:errors].empty?
|
||||
info[:errors].each do |err|
|
||||
print_error(err)
|
||||
end
|
||||
end
|
||||
|
||||
if(info[:rows] and not info[:rows].empty?)
|
||||
if info[:rows] && !info[:rows].empty?
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Indent' => 1,
|
||||
@ -786,7 +748,7 @@ module Exploit::Remote::MSSQL
|
||||
|
||||
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
if(col[:msg_len] and col[:msg_len] > 0)
|
||||
if col[:msg_len] && col[:msg_len] > 0
|
||||
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
|
||||
end
|
||||
info[:colnames] << (col[:name] || 'NULL')
|
||||
@ -845,7 +807,7 @@ module Exploit::Remote::MSSQL
|
||||
when :hex
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if(len > 0 and len < 65535)
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.unpack("H*")[0]
|
||||
@ -853,7 +815,7 @@ module Exploit::Remote::MSSQL
|
||||
when :string
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if(len > 0 and len < 65535)
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.gsub("\x00", '')
|
||||
@ -879,12 +841,12 @@ module Exploit::Remote::MSSQL
|
||||
when :image
|
||||
str = ''
|
||||
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 && len > 0
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :int
|
||||
len = data.slice!(0, 1).unpack("C")[0]
|
||||
raw = data.slice!(0, len) if (len and len > 0)
|
||||
raw = data.slice!(0, len) if len && len > 0
|
||||
|
||||
case len
|
||||
when 0, 255
|
||||
@ -986,7 +948,7 @@ module Exploit::Remote::MSSQL
|
||||
#
|
||||
def mssql_parse_login_ack(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0,len)
|
||||
_buff = data.slice!(0, len)
|
||||
info[:login_ack] = true
|
||||
end
|
||||
end
|
||||
|
@ -17,12 +17,6 @@ module Msf
|
||||
|
||||
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
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
@ -3,10 +3,6 @@ require 'rex/socket'
|
||||
require 'rex/proto/http'
|
||||
require 'rex/text'
|
||||
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'
|
||||
|
||||
@ -313,7 +309,6 @@ class Client
|
||||
# Send a series of requests to complete Digest Authentication
|
||||
#
|
||||
# @param opts [Hash] the options used to build an HTTP request
|
||||
#
|
||||
# @return [Response] the last valid HTTP response we received
|
||||
def digest_auth(opts={})
|
||||
@nonce_count = 0
|
||||
@ -457,13 +452,6 @@ class Client
|
||||
#
|
||||
# @return [Response] the last valid HTTP response we received
|
||||
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
|
||||
opts['username'] ||= ''
|
||||
@ -472,28 +460,27 @@ class Client
|
||||
if opts['provider'] and opts['provider'].include? 'Negotiate'
|
||||
provider = "Negotiate "
|
||||
else
|
||||
provider = 'NTLM '
|
||||
provider = "NTLM "
|
||||
end
|
||||
|
||||
opts['method']||= 'GET'
|
||||
opts['headers']||= {}
|
||||
|
||||
ntlmssp_flags = ::Rex::Proto::NTLM::Utils.make_ntlm_flags(ntlm_options)
|
||||
workstation_name = Rex::Text.rand_text_alpha(rand(8)+6)
|
||||
domain_name = self.config['domain']
|
||||
|
||||
b64_blob = Rex::Text::encode_base64(
|
||||
::Rex::Proto::NTLM::Utils::make_ntlmssp_blob_init(
|
||||
domain_name,
|
||||
workstation_name,
|
||||
ntlmssp_flags
|
||||
))
|
||||
|
||||
ntlm_message_1 = provider + b64_blob
|
||||
ntlm_client = ::Net::NTLM::Client.new(
|
||||
opts['username'],
|
||||
opts['password'],
|
||||
workstation: workstation_name,
|
||||
domain: domain_name,
|
||||
)
|
||||
type1 = ntlm_client.init_context
|
||||
|
||||
begin
|
||||
# First request to get the challenge
|
||||
opts['headers']['Authorization'] = ntlm_message_1
|
||||
opts['headers']['Authorization'] = provider + type1.encode64
|
||||
|
||||
r = request_cgi(opts)
|
||||
resp = _send_recv(r, to)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
@ -506,47 +493,10 @@ class Client
|
||||
ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0]
|
||||
return resp unless 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)
|
||||
ntlm_message_3 = ntlm_client.init_context(ntlm_challenge)
|
||||
|
||||
# Send the response
|
||||
opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3}"
|
||||
opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3.encode64}"
|
||||
r = request_cgi(opts)
|
||||
resp = _send_recv(r, to, true)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
@ -558,6 +508,7 @@ class Client
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Read a response from the server
|
||||
#
|
||||
@ -713,7 +664,6 @@ protected
|
||||
|
||||
attr_accessor :hostname, :port # :nodoc:
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -4,6 +4,8 @@ module Proto
|
||||
module SMB
|
||||
class Client
|
||||
|
||||
require 'net/ntlm'
|
||||
|
||||
require 'rex/text'
|
||||
require 'rex/struct2'
|
||||
require 'rex/proto/smb/constants'
|
||||
@ -623,16 +625,15 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
|
||||
|
||||
# Authenticate and establish a session
|
||||
def session_setup(*args)
|
||||
|
||||
def session_setup(user='', pass='', domain='', do_recv=true)
|
||||
if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
|
||||
|
||||
if (self.challenge_key)
|
||||
return self.session_setup_no_ntlmssp(*args)
|
||||
return self.session_setup_no_ntlmssp(user, pass, domain, do_recv)
|
||||
end
|
||||
|
||||
if ( self.extended_security )
|
||||
return self.session_setup_with_ntlmssp(*args)
|
||||
return self.session_setup_with_ntlmssp(user, pass, domain, nil, do_recv)
|
||||
end
|
||||
|
||||
end
|
||||
@ -831,7 +832,16 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
name = Rex::Text.rand_text_alphanumeric(16)
|
||||
end
|
||||
|
||||
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
|
||||
@ntlm_client = Net::NTLM::Client.new(
|
||||
user,
|
||||
pass,
|
||||
workstation: name,
|
||||
domain: domain,
|
||||
flags: ntlmssp_flags
|
||||
)
|
||||
|
||||
|
||||
blob = @ntlm_client.init_context.serialize
|
||||
|
||||
native_data = ''
|
||||
native_data << self.native_os + "\x00"
|
||||
@ -892,37 +902,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
# Save the temporary UserID for use in the next request
|
||||
temp_user_id = ack['Payload']['SMB'].v['UserID']
|
||||
|
||||
# Get default data
|
||||
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
|
||||
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)
|
||||
type3 = @ntlm_client.init_context([blob].pack('m'))
|
||||
type3_blob = type3.serialize
|
||||
self.signing_key = @ntlm_client.session_key
|
||||
|
||||
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
||||
self.smb_defaults(pkt['Payload']['SMB'])
|
||||
@ -944,8 +926,8 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
pkt['Payload'].v['VCNum'] = 1
|
||||
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
||||
pkt['Payload'].v['SessionKey'] = self.session_id
|
||||
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
||||
pkt['Payload'].v['Payload'] = blob + native_data
|
||||
pkt['Payload'].v['SecurityBlobLen'] = type3_blob.length
|
||||
pkt['Payload'].v['Payload'] = type3_blob + native_data
|
||||
|
||||
# NOTE: if do_recv is set to false, we cant reach here...
|
||||
self.smb_send(pkt.to_s)
|
||||
@ -1771,7 +1753,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
# Remove the NetBIOS header
|
||||
resp_rpkt.slice!(0, 4)
|
||||
|
||||
resp_parm = resp_rpkt[poff, pcnt]
|
||||
_resp_parm = resp_rpkt[poff, pcnt]
|
||||
resp_data = resp_rpkt[doff, dcnt]
|
||||
return resp_data
|
||||
|
||||
@ -1797,7 +1779,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
# Remove the NetBIOS header
|
||||
resp_rpkt.slice!(0, 4)
|
||||
|
||||
resp_parm = resp_rpkt[poff, pcnt]
|
||||
_resp_parm = resp_rpkt[poff, pcnt]
|
||||
resp_data = resp_rpkt[doff, dcnt]
|
||||
return resp_data
|
||||
|
||||
@ -2030,9 +2012,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||
|
||||
# Creates a new directory on the mounted tree
|
||||
def create_directory(name)
|
||||
files = { }
|
||||
parm = [0].pack('V') + name + "\x00"
|
||||
resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
|
||||
resp
|
||||
end
|
||||
|
||||
# public read/write methods
|
||||
|
@ -75,6 +75,8 @@ Gem::Specification.new do |spec|
|
||||
spec.add_runtime_dependency 'msgpack'
|
||||
# get list of network interfaces, like eth* from OS.
|
||||
spec.add_runtime_dependency 'network_interface'
|
||||
# NTLM authentication
|
||||
spec.add_runtime_dependency 'rubyntlm'
|
||||
# Needed by anemone crawler
|
||||
spec.add_runtime_dependency 'nokogiri'
|
||||
# Needed by db.rb and Msf::Exploit::Capture
|
||||
|
@ -31,7 +31,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
def run_host(ip)
|
||||
|
||||
if !mssql_login_datastore
|
||||
print_error("#{rhost}:#{rport} - Invalid SQL Server credentials")
|
||||
print_error("Invalid SQL Server credentials")
|
||||
return
|
||||
end
|
||||
|
||||
@ -150,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
login = create_credential_login(login_data)
|
||||
|
||||
tbl << [row[0], row[1]]
|
||||
print_good("#{rhost}:#{rport} - Saving #{hashtype} = #{row[0]}:#{row[1]}")
|
||||
print_good("Saving #{hashtype} = #{row[0]}:#{row[1]}")
|
||||
end
|
||||
end
|
||||
|
||||
@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]
|
||||
|
||||
if is_sysadmin == 0
|
||||
print_error("#{rhost}:#{rport} - The provided credentials do not have privileges to read the password hashes")
|
||||
print_error("The provided credentials do not have privileges to read the password hashes")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user