2005-09-16 09:27:41 +00:00
|
|
|
module Rex
|
|
|
|
module Proto
|
|
|
|
module SMB
|
|
|
|
class Client
|
|
|
|
|
|
|
|
require 'rex/text'
|
|
|
|
require 'rex/struct2'
|
|
|
|
require 'rex/proto/smb/constants'
|
2005-09-22 09:04:40 +00:00
|
|
|
require 'rex/proto/smb/exceptions'
|
2005-09-23 03:43:04 +00:00
|
|
|
require 'rex/proto/smb/evasions'
|
2005-09-16 09:27:41 +00:00
|
|
|
require 'rex/proto/smb/utils'
|
2011-03-07 19:57:53 +00:00
|
|
|
require 'rex/proto/smb/crypt'
|
|
|
|
require 'rex/proto/ntlm/crypt'
|
|
|
|
require 'rex/proto/ntlm/constants'
|
|
|
|
require 'rex/proto/ntlm/utils'
|
2005-09-16 09:27:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Some short-hand class aliases
|
|
|
|
CONST = Rex::Proto::SMB::Constants
|
|
|
|
CRYPT = Rex::Proto::SMB::Crypt
|
|
|
|
UTILS = Rex::Proto::SMB::Utils
|
2005-09-22 09:04:40 +00:00
|
|
|
XCEPT = Rex::Proto::SMB::Exceptions
|
2005-09-23 03:43:04 +00:00
|
|
|
EVADE = Rex::Proto::SMB::Evasions
|
2011-03-07 19:57:53 +00:00
|
|
|
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
|
|
|
|
NTLM_CONST = Rex::Proto::NTLM::Constants
|
|
|
|
NTLM_UTILS = Rex::Proto::NTLM::Utils
|
2005-09-16 09:27:41 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
def initialize(socket)
|
2005-09-16 09:27:41 +00:00
|
|
|
self.socket = socket
|
|
|
|
self.native_os = 'Windows 2000 2195'
|
|
|
|
self.native_lm = 'Windows 2000 5.0'
|
2006-05-03 04:43:19 +00:00
|
|
|
self.encrypt_passwords = true
|
|
|
|
self.extended_security = false
|
2005-09-19 23:35:51 +00:00
|
|
|
self.multiplex_id = rand(0xffff)
|
|
|
|
self.process_id = rand(0xffff)
|
2005-09-22 09:04:40 +00:00
|
|
|
self.read_timeout = 10
|
2006-04-30 19:49:27 +00:00
|
|
|
self.evasion_opts = {
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-02-04 01:54:10 +00:00
|
|
|
# Padding is performed between packet headers and data
|
|
|
|
'pad_data' => EVADE::EVASION_NONE,
|
|
|
|
|
|
|
|
# File path padding is performed on all open/create calls
|
|
|
|
'pad_file' => EVADE::EVASION_NONE,
|
|
|
|
|
|
|
|
# Modify the \PIPE\ string in trans_named_pipe calls
|
|
|
|
'obscure_trans_pipe' => EVADE::EVASION_NONE,
|
2006-04-30 19:49:27 +00:00
|
|
|
}
|
2011-03-07 19:57:53 +00:00
|
|
|
self.verify_signature = false
|
|
|
|
self.use_ntlmv2 = false
|
|
|
|
self.usentlm2_session = true
|
|
|
|
self.send_lm = true
|
|
|
|
self.use_lanman_key = false
|
|
|
|
self.send_ntlm = true
|
|
|
|
#signing
|
|
|
|
self.sequence_counter = 0
|
|
|
|
self.signing_key = ''
|
|
|
|
self.require_signing = false
|
|
|
|
|
2005-09-16 09:27:41 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Read a SMB packet from the socket
|
|
|
|
def smb_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-07-14 17:07:10 +00:00
|
|
|
data = socket.timed_read(4, self.read_timeout)
|
2005-11-16 17:56:07 +00:00
|
|
|
if (data.nil? or data.length < 4)
|
2005-10-03 13:51:05 +00:00
|
|
|
raise XCEPT::NoReply
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
recv_len = data[2,2].unpack('n')[0]
|
2005-09-19 23:35:51 +00:00
|
|
|
if (recv_len == 0)
|
2005-11-16 17:56:07 +00:00
|
|
|
return data
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
recv_len += 4
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
while (data.length != recv_len)
|
2005-09-23 09:14:03 +00:00
|
|
|
buff = ''
|
|
|
|
|
|
|
|
begin
|
2005-11-16 17:56:07 +00:00
|
|
|
buff << self.socket.timed_read(recv_len - data.length, self.read_timeout)
|
2005-10-03 13:51:05 +00:00
|
|
|
rescue Timeout::Error
|
2005-09-23 09:14:03 +00:00
|
|
|
rescue
|
|
|
|
raise XCEPT::ReadPacket
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
if (buff.nil? or buff.length == 0)
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::ReadPacket
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
data << buff
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
#signing
|
|
|
|
if self.require_signing && self.signing_key != ''
|
|
|
|
if self.verify_signature
|
|
|
|
raise XCEPT::IncorrectSigningError if not CRYPT::is_signature_correct?(self.signing_key,self.sequence_counter,data)
|
|
|
|
end
|
|
|
|
self.sequence_counter += 1
|
|
|
|
end
|
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
return data
|
2011-03-07 19:57:53 +00:00
|
|
|
|
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Send a SMB packet down the socket
|
2006-05-30 16:11:00 +00:00
|
|
|
def smb_send(data, evasion_level=0)
|
2006-04-30 19:49:27 +00:00
|
|
|
|
2006-05-30 16:11:00 +00:00
|
|
|
# evasion_level is ignored, since real evasion happens
|
|
|
|
# in the actual socket layer
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-17 19:41:54 +00:00
|
|
|
size = 0
|
|
|
|
wait = 0
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
#signing
|
|
|
|
if self.require_signing && self.signing_key != ''
|
|
|
|
data = CRYPT::sign_smb_packet(self.signing_key, self.sequence_counter, data)
|
|
|
|
self.sequence_counter += 1
|
|
|
|
end
|
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
begin
|
2005-09-23 03:43:04 +00:00
|
|
|
# Just send the packet and return
|
|
|
|
if (size == 0 or size >= data.length)
|
|
|
|
return self.socket.put(data)
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Break the packet up into chunks and wait between them
|
|
|
|
ret = 0
|
|
|
|
while ( (chunk = data.slice!(0, size)).length > 0 )
|
|
|
|
ret = self.socket.put(chunk)
|
|
|
|
if (wait > 0)
|
2010-05-20 20:42:17 +00:00
|
|
|
::IO.select(nil, nil, nil, wait)
|
2005-09-23 03:43:04 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return ret
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the SMB parameters to some reasonable defaults
|
|
|
|
def smb_defaults(packet)
|
|
|
|
packet.v['MultiplexID'] = self.multiplex_id.to_i
|
2005-09-22 09:04:40 +00:00
|
|
|
packet.v['TreeID'] = self.last_tree_id.to_i
|
2005-09-19 23:35:51 +00:00
|
|
|
packet.v['UserID'] = self.auth_user_id.to_i
|
|
|
|
packet.v['ProcessID'] = self.process_id.to_i
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# The main dispatcher for all incoming SMB packets
|
2005-09-23 03:43:04 +00:00
|
|
|
def smb_recv_parse(expected_type, ignore_errors = false)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# This will throw an exception if it fails to read the whole packet
|
2005-09-19 23:35:51 +00:00
|
|
|
data = self.smb_recv
|
2005-12-13 06:08:40 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt = CONST::SMB_BASE_PKT.make_struct
|
|
|
|
pkt.from_s(data)
|
2005-09-23 03:43:04 +00:00
|
|
|
res = pkt
|
2011-03-07 19:57:53 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
begin
|
|
|
|
case pkt['Payload']['SMB'].v['Command']
|
|
|
|
|
|
|
|
when CONST::SMB_COM_NEGOTIATE
|
|
|
|
res = smb_parse_negotiate(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
res = smb_parse_session_setup(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_TREE_CONNECT_ANDX
|
|
|
|
res = smb_parse_tree_connect(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_TREE_DISCONNECT
|
|
|
|
res = smb_parse_tree_disconnect(pkt, data)
|
|
|
|
|
2006-04-26 16:59:44 +00:00
|
|
|
when CONST::SMB_COM_NT_CREATE_ANDX
|
2005-09-23 03:43:04 +00:00
|
|
|
res = smb_parse_create(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_TRANSACTION, CONST::SMB_COM_TRANSACTION2
|
|
|
|
res = smb_parse_trans(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_NT_TRANSACT
|
|
|
|
res = smb_parse_nttrans(pkt, data)
|
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
when CONST::SMB_COM_NT_TRANSACT_SECONDARY
|
|
|
|
res = smb_parse_nttrans(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
when CONST::SMB_COM_OPEN_ANDX
|
|
|
|
res = smb_parse_open(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_WRITE_ANDX
|
|
|
|
res = smb_parse_write(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
when CONST::SMB_COM_READ_ANDX
|
|
|
|
res = smb_parse_read(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
when CONST::SMB_COM_CLOSE
|
|
|
|
res = smb_parse_close(pkt, data)
|
|
|
|
|
|
|
|
when CONST::SMB_COM_DELETE
|
|
|
|
res = smb_parse_delete(pkt, data)
|
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
else
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidCommand
|
2009-10-20 17:24:33 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['Command'] != expected_type)
|
|
|
|
raise XCEPT::InvalidType
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
if (ignore_errors == false and pkt['Payload']['SMB'].v['ErrorClass'] != 0)
|
|
|
|
raise XCEPT::ErrorCode
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
rescue XCEPT::InvalidWordCount, XCEPT::InvalidCommand, XCEPT::InvalidType, XCEPT::ErrorCode
|
|
|
|
$!.word_count = pkt['Payload']['SMB'].v['WordCount']
|
|
|
|
$!.command = pkt['Payload']['SMB'].v['Command']
|
|
|
|
$!.error_code = pkt['Payload']['SMB'].v['ErrorClass']
|
|
|
|
raise $!
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2005-12-13 06:08:40 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
return res
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Process incoming SMB_COM_NEGOTIATE packets
|
2006-04-30 19:49:27 +00:00
|
|
|
def smb_parse_negotiate(pkt, data)
|
2006-01-27 05:28:16 +00:00
|
|
|
#Process NTLM negotiate responses
|
2005-09-19 23:35:51 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 17)
|
|
|
|
res = CONST::SMB_NEG_RES_NT_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
# Process LANMAN negotiate responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 13)
|
|
|
|
res = CONST::SMB_NEG_RES_LM_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
|
|
|
# Process ERROR negotiate responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 1)
|
|
|
|
res = CONST::SMB_NEG_RES_ERR_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidWordCount
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Process incoming SMB_COM_SESSION_SETUP_ANDX packets
|
|
|
|
def smb_parse_session_setup(pkt, data)
|
2011-03-07 19:57:53 +00:00
|
|
|
# Process NTLMSSP negotiate responses
|
2005-09-19 23:35:51 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 4)
|
|
|
|
res = CONST::SMB_SETUP_NTLMV2_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# Process LANMAN responses
|
2005-09-22 04:04:06 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
|
|
|
|
res = CONST::SMB_SETUP_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
# Process incoming SMB_COM_TREE_CONNECT_ANDX packets
|
|
|
|
def smb_parse_tree_connect(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
|
|
|
|
res = CONST::SMB_TREE_CONN_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-22 09:04:40 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
# Process incoming SMB_COM_TREE_DISCONNECT packets
|
|
|
|
def smb_parse_tree_disconnect(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
res = CONST::SMB_TREE_DISCONN_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2006-04-26 16:59:44 +00:00
|
|
|
# Process incoming SMB_COM_NT_CREATE_ANDX packets
|
2005-09-22 09:04:40 +00:00
|
|
|
def smb_parse_create(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
# Windows says 42, but Samba says 34, same structure :-/
|
2005-09-22 09:04:40 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 42)
|
|
|
|
res = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2005-11-15 23:02:17 +00:00
|
|
|
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 34)
|
|
|
|
res = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-22 09:04:40 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-22 09:04:40 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process incoming SMB_COM_TRANSACTION packets
|
2005-09-22 09:04:40 +00:00
|
|
|
def smb_parse_trans(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 10)
|
|
|
|
res = CONST::SMB_TRANS_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-22 09:04:40 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
# Process incoming SMB_COM_NT_TRANSACT packets
|
|
|
|
def smb_parse_nttrans(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2006-09-14 05:41:54 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] >= 18)
|
2010-09-14 18:20:17 +00:00
|
|
|
res = CONST::SMB_NTTRANS_RES_PKT.make_struct
|
2006-09-14 05:41:54 +00:00
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process incoming SMB_COM_OPEN_ANDX packets
|
|
|
|
def smb_parse_open(pkt, data)
|
2006-01-27 05:28:16 +00:00
|
|
|
# Process open responses
|
2005-09-23 03:43:04 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 15)
|
|
|
|
res = CONST::SMB_OPEN_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
# Process incoming SMB_COM_WRITE_ANDX packets
|
|
|
|
def smb_parse_write(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-01-27 05:28:16 +00:00
|
|
|
# Process write responses
|
2005-09-23 03:43:04 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 6)
|
|
|
|
res = CONST::SMB_WRITE_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process incoming SMB_COM_READ_ANDX packets
|
|
|
|
def smb_parse_read(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-15 16:44:44 +00:00
|
|
|
# Process read responses
|
2005-09-23 03:43:04 +00:00
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 12)
|
|
|
|
res = CONST::SMB_READ_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process incoming SMB_COM_CLOSE packets
|
|
|
|
def smb_parse_close(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
return pkt
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process incoming SMB_COM_DELETE packets
|
|
|
|
def smb_parse_delete(pkt, data)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Process SMB error responses
|
|
|
|
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
|
|
res = CONST::SMB_DELETE_RES_PKT.make_struct
|
|
|
|
res.from_s(data)
|
|
|
|
return res
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
raise XCEPT::InvalidWordCount
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Request a SMB session over NetBIOS
|
2010-08-18 17:20:55 +00:00
|
|
|
def session_request(name = '*SMBSERVER', do_recv = true)
|
2008-03-26 22:36:42 +00:00
|
|
|
|
|
|
|
name ||= '*SMBSERVER'
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
data = ''
|
|
|
|
data << "\x20" + UTILS.nbname_encode(name) + "\x00"
|
|
|
|
data << "\x20" + CONST::NETBIOS_REDIR + "\x00"
|
|
|
|
|
|
|
|
pkt = CONST::NBRAW_PKT.make_struct
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt.v['Type'] = 0x81
|
|
|
|
pkt['Payload'].v['Payload'] = data
|
2005-09-19 23:35:51 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Most SMB implementations can't handle this being fragmented
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
res = self.smb_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
ack = CONST::NBRAW_PKT.make_struct
|
|
|
|
ack.from_s(res)
|
|
|
|
|
|
|
|
if (ack.v['Type'] != 130)
|
2005-09-22 09:04:40 +00:00
|
|
|
raise XCEPT::NetbiosSessionFailed
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
return ack
|
2005-09-16 09:27:41 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
|
|
|
# Negotiate a SMB dialect
|
2011-03-07 19:57:53 +00:00
|
|
|
def negotiate(smb_extended_security=true, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-31 21:49:46 +00:00
|
|
|
dialects = ['LANMAN1.0', 'LM1.2X002' ]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-03 04:43:19 +00:00
|
|
|
if (self.encrypt_passwords)
|
2006-05-31 21:49:46 +00:00
|
|
|
dialects.push('NT LANMAN 1.0', 'NT LM 0.12')
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-30 17:18:27 +00:00
|
|
|
data = dialects.collect { |dialect| "\x02" + dialect + "\x00" }.join('')
|
2005-09-19 23:35:51 +00:00
|
|
|
|
|
|
|
pkt = CONST::SMB_NEG_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
if(smb_extended_security)
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
2007-07-03 04:20:50 +00:00
|
|
|
else
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
|
2007-07-03 04:20:50 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
|
2010-08-18 17:20:55 +00:00
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_NEGOTIATE)
|
2005-09-19 23:35:51 +00:00
|
|
|
|
|
|
|
idx = ack['Payload'].v['Dialect']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Check for failed dialect selection
|
|
|
|
if (idx < 0 or idx >= dialects.length)
|
|
|
|
return nil
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the selected dialect
|
|
|
|
self.dialect = dialects[idx]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Does the server support extended security negotiation?
|
2006-08-12 23:07:25 +00:00
|
|
|
if (ack['Payload'].v['Capabilities'] & 0x80000000 != 0)
|
2006-05-03 04:43:19 +00:00
|
|
|
self.extended_security = true
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the security mode
|
|
|
|
self.security_mode = ack['Payload'].v['SecurityMode']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
#set require_signing
|
|
|
|
if (ack['Payload'].v['SecurityMode'] & 0x08 != 0)
|
|
|
|
self.require_signing = true
|
|
|
|
end
|
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the challenge key
|
|
|
|
if (ack['Payload'].v['EncryptionKey'] != nil)
|
|
|
|
self.challenge_key = ack['Payload'].v['EncryptionKey']
|
2006-08-12 23:07:25 +00:00
|
|
|
else
|
|
|
|
# Handle Windows NT 4.0 responses
|
|
|
|
if (ack['Payload'].v['KeyLength'] > 0)
|
|
|
|
self.challenge_key = ack['Payload'].v['Payload'][0, ack['Payload'].v['KeyLength']]
|
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the session identifier
|
|
|
|
if (ack['Payload'].v['SessionKey'] != nil)
|
|
|
|
self.session_id = ack['Payload'].v['SessionKey']
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-03 04:43:19 +00:00
|
|
|
# Extract the payload (GUID/SecurityBlob)
|
|
|
|
buf = ack['Payload'].v['Payload'] || ''
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Set the server GUID
|
2006-05-03 04:43:19 +00:00
|
|
|
if (self.extended_security and buf.length >= 16)
|
|
|
|
self.server_guid = buf[0,16]
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2006-05-03 04:43:19 +00:00
|
|
|
|
|
|
|
# Set the server SecurityBlob
|
|
|
|
if (self.extended_security and buf.length > 16)
|
|
|
|
# buf[16, buf.length - 16]
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-09-18 01:12:44 +00:00
|
|
|
# The number of 100-nanosecond intervals that have elapsed since January 1, 1601, in
|
|
|
|
# Coordinated Universal Time (UTC) format.
|
|
|
|
# We convert it to a friendly Time object here
|
|
|
|
self.system_time = UTILS.time_smb_to_unix(ack['Payload'].v['SystemTimeHigh'],ack['Payload'].v['SystemTimeLow'])
|
|
|
|
self.system_time = ::Time.at( self.system_time )
|
|
|
|
|
2010-09-21 16:24:18 +00:00
|
|
|
# A signed 16-bit signed integer that represents the server's time zone, in minutes,
|
|
|
|
# from UTC. The time zone of the server MUST be expressed in minutes, plus or minus,
|
|
|
|
# from UTC.
|
|
|
|
# NOTE: althought the spec says +/- it doesn't say that it should be inverted :-/
|
2010-09-18 01:12:44 +00:00
|
|
|
system_zone = ack['Payload'].v['ServerTimeZone']
|
2010-09-21 16:24:18 +00:00
|
|
|
# Convert the ServerTimeZone to _seconds_ and back into a signed integer :-/
|
|
|
|
if (system_zone & 0x8000) == 0x8000
|
|
|
|
system_zone = (( (~system_zone) & 0x0FFF ) + 1 )
|
2010-09-21 14:21:38 +00:00
|
|
|
else
|
2010-09-21 16:24:18 +00:00
|
|
|
system_zone *= -1
|
2010-09-21 14:21:38 +00:00
|
|
|
end
|
2010-09-21 16:24:18 +00:00
|
|
|
self.system_zone = system_zone * 60
|
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
return ack
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Authenticate and establish a session
|
2006-04-30 19:49:27 +00:00
|
|
|
def session_setup(*args)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
|
2011-03-07 19:57:53 +00:00
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
if (self.challenge_key)
|
2011-03-07 19:57:53 +00:00
|
|
|
return self.session_setup_no_ntlmssp(*args)
|
2006-09-14 05:41:54 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
if ( self.extended_security )
|
2011-03-07 19:57:53 +00:00
|
|
|
return self.session_setup_with_ntlmssp(*args)
|
2006-09-14 05:41:54 +00:00
|
|
|
end
|
2011-03-07 19:57:53 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
return self.session_setup_clear(*args)
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2005-09-22 04:04:06 +00:00
|
|
|
|
|
|
|
# Authenticate using clear-text passwords
|
2010-08-18 17:20:55 +00:00
|
|
|
def session_setup_clear(user = '', pass = '', domain = '', do_recv = true)
|
2005-09-22 04:04:06 +00:00
|
|
|
|
2006-05-30 17:18:27 +00:00
|
|
|
data = [ pass, user, domain, self.native_os, self.native_lm ].collect{ |a| a + "\x00" }.join('');
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 10
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2006-05-30 17:18:27 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload'].v['PasswordLen'] = pass.length + 1
|
|
|
|
pkt['Payload'].v['Capabilities'] = 64
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
|
|
self.auth_user = user
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
info = ack['Payload'].v['Payload'].split(/\x00/)
|
|
|
|
self.peer_native_os = info[0]
|
|
|
|
self.peer_native_lm = info[1]
|
|
|
|
self.default_domain = info[2]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
return ack
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# Authenticate without NTLMSSP
|
|
|
|
def session_setup_no_ntlmssp(user = '', pass = '', domain = '', do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-06-17 17:36:19 +00:00
|
|
|
raise XCEPT::NTLM1MissingChallenge if not self.challenge_key
|
2011-03-07 19:57:53 +00:00
|
|
|
#we can not yet handle signing in this situation
|
|
|
|
raise XCEPT::NTLM2MissingChallenge if self.require_signing
|
2006-06-17 17:36:19 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
hash_lm = pass.length > 0 ? NTLM_CRYPT.lanman_des(pass, self.challenge_key) : ''
|
|
|
|
hash_nt = pass.length > 0 ? NTLM_CRYPT.ntlm_md4(pass, self.challenge_key) : ''
|
2005-09-22 04:04:06 +00:00
|
|
|
|
|
|
|
data = ''
|
|
|
|
data << hash_lm
|
|
|
|
data << hash_nt
|
|
|
|
data << user + "\x00"
|
|
|
|
data << domain + "\x00"
|
|
|
|
data << self.native_os + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
data << self.native_lm + "\x00"
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
|
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 13
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
|
|
|
|
pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
|
|
|
|
pkt['Payload'].v['Capabilities'] = 64
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
|
|
self.auth_user = user
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
|
|
|
|
|
|
info = ack['Payload'].v['Payload'].split(/\x00/)
|
2005-11-15 23:02:17 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
self.peer_native_os = info[0]
|
|
|
|
self.peer_native_lm = info[1]
|
|
|
|
self.default_domain = info[2]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
return ack
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2007-07-03 04:20:50 +00:00
|
|
|
|
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# Authenticate without ntlmssp with a precomputed hash pair
|
|
|
|
def session_setup_no_ntlmssp_prehash(user, domain, hash_lm, hash_nt, do_recv = true)
|
|
|
|
|
|
|
|
raise XCEPT::NTLM2MissingChallenge if self.require_signing
|
2007-07-03 04:20:50 +00:00
|
|
|
|
|
|
|
data = ''
|
|
|
|
data << hash_lm
|
|
|
|
data << hash_nt
|
|
|
|
data << user + "\x00"
|
|
|
|
data << domain + "\x00"
|
|
|
|
data << self.native_os + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
data << self.native_lm + "\x00"
|
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
|
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 13
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2007-07-03 04:20:50 +00:00
|
|
|
pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
|
|
|
|
pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
|
|
|
|
pkt['Payload'].v['Capabilities'] = 64
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
|
|
self.auth_user = user
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
|
|
|
|
|
|
info = ack['Payload'].v['Payload'].split(/\x00/)
|
|
|
|
|
|
|
|
self.peer_native_os = info[0]
|
|
|
|
self.peer_native_lm = info[1]
|
|
|
|
self.default_domain = info[2]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
return ack
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# Authenticate using extended security negotiation
|
|
|
|
def session_setup_with_ntlmssp(user = '', pass = '', domain = '', name = nil, do_recv = true)
|
|
|
|
|
|
|
|
if require_signing
|
|
|
|
ntlmssp_flags = 0xe2088215
|
|
|
|
else
|
|
|
|
|
|
|
|
ntlmssp_flags = 0xa2080205
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.usentlm2_session
|
|
|
|
if self.use_ntlmv2
|
|
|
|
#set Negotiate Target Info
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_TARGET_INFO
|
|
|
|
end
|
|
|
|
|
|
|
|
else
|
|
|
|
#remove the ntlm2_session flag
|
|
|
|
ntlmssp_flags &= 0xfff7ffff
|
|
|
|
#set lanmanflag only when lm and ntlm are sent
|
|
|
|
if self.send_lm
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_LMKEY if self.use_lanman_key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#we can also downgrade ntlm2_session when we send only lmv1
|
|
|
|
ntlmssp_flags &= 0xfff7ffff if self.usentlm2_session && (not self.use_ntlmv2) && (not self.send_ntlm)
|
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
if (name == nil)
|
|
|
|
name = Rex::Text.rand_text_alphanumeric(16)
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
native_data = ''
|
|
|
|
native_data << self.native_os + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
native_data << self.native_lm + "\x00"
|
2005-09-16 09:27:41 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
2011-03-07 19:57:53 +00:00
|
|
|
pkt['Payload'].v['Capabilities'] = 0x800000d4
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['Payload'] = blob + native_data
|
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
2011-03-07 19:57:53 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# The server doesn't know about NTLM_NEGOTIATE
|
2005-12-31 18:03:02 +00:00
|
|
|
if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
|
2011-03-07 19:57:53 +00:00
|
|
|
return session_setup_no_ntlmssp(user, pass, domain)
|
2005-12-31 18:03:02 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Make sure the error code tells us to continue processing
|
2005-09-19 23:35:51 +00:00
|
|
|
if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
|
2005-09-23 03:43:04 +00:00
|
|
|
failure = XCEPT::ErrorCode.new
|
2005-09-23 09:14:03 +00:00
|
|
|
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
|
|
failure.command = ack['Payload']['SMB'].v['Command']
|
|
|
|
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
2005-09-23 03:43:04 +00:00
|
|
|
raise failure
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Extract the SecurityBlob from the response
|
|
|
|
data = ack['Payload'].v['Payload']
|
|
|
|
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
|
|
|
|
|
|
|
# Extract the native lanman and os strings
|
|
|
|
info = data.split(/\x00/)
|
|
|
|
self.peer_native_os = info[0]
|
|
|
|
self.peer_native_lm = info[1]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Save the temporary UserID for use in the next request
|
|
|
|
temp_user_id = ack['Payload']['SMB'].v['UserID']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Extract the NTLM challenge key the lazy way
|
|
|
|
cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00")
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
if (cidx == -1)
|
2006-06-17 17:36:19 +00:00
|
|
|
raise XCEPT::NTLM2MissingChallenge
|
2005-09-19 23:35:51 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
# Store the challenge key
|
|
|
|
self.challenge_key = blob[cidx + 24, 8]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
# Extract the address list from the blob
|
|
|
|
alist_len,alist_mlen,alist_off = blob[cidx + 40, 8].unpack("vvV")
|
|
|
|
alist_buf = blob[cidx + alist_off, alist_len]
|
2011-03-07 19:57:53 +00:00
|
|
|
chall_MsvAvTimestamp = nil
|
2009-12-29 14:00:49 +00:00
|
|
|
while(alist_buf.length > 0)
|
|
|
|
atype, alen = alist_buf.slice!(0,4).unpack('vv')
|
|
|
|
break if atype == 0x00
|
|
|
|
addr = alist_buf.slice!(0, alen)
|
|
|
|
case atype
|
|
|
|
when 1
|
2011-03-07 19:57:53 +00:00
|
|
|
#netbios name
|
2009-12-29 14:00:49 +00:00
|
|
|
self.default_name = addr.gsub("\x00", '')
|
|
|
|
when 2
|
2011-03-07 19:57:53 +00:00
|
|
|
#netbios domain
|
2009-12-29 14:00:49 +00:00
|
|
|
self.default_domain = addr.gsub("\x00", '')
|
|
|
|
when 3
|
2011-03-07 19:57:53 +00:00
|
|
|
#dns name
|
2009-12-29 14:00:49 +00:00
|
|
|
self.dns_host_name = addr.gsub("\x00", '')
|
|
|
|
when 4
|
2011-03-07 19:57:53 +00:00
|
|
|
#dns domain
|
2009-12-29 14:00:49 +00:00
|
|
|
self.dns_domain_name = addr.gsub("\x00", '')
|
|
|
|
when 5
|
2011-03-07 19:57:53 +00:00
|
|
|
#The FQDN of the forest.
|
|
|
|
when 6
|
|
|
|
#A 32-bit value indicating server or client configuration
|
2009-12-29 14:00:49 +00:00
|
|
|
when 7
|
|
|
|
# client time
|
2011-03-07 19:57:53 +00:00
|
|
|
chall_MsvAvTimestamp = addr
|
|
|
|
when 8
|
|
|
|
#A Restriction_Encoding structure
|
|
|
|
when 9
|
|
|
|
#The SPN of the target server.
|
|
|
|
when 10
|
|
|
|
#A channel bindings hash.
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
|
|
|
end
|
2011-03-07 19:57:53 +00:00
|
|
|
|
|
|
|
#calculate the lm/ntlm response
|
|
|
|
resp_lm = "\x00" * 24
|
|
|
|
resp_ntlm = "\x00" * 24
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
client_challenge = Rex::Text.rand_text(8)
|
2011-03-07 19:57:53 +00:00
|
|
|
ntlm_cli_challenge = ''
|
|
|
|
if self.send_ntlm #should be default
|
|
|
|
if self.usentlm2_session
|
|
|
|
|
|
|
|
if self.use_ntlmv2
|
|
|
|
#This is only a partial implementation, in some situation servers may send STATUS_INVALID_PARAMETER
|
|
|
|
#answer must then be somewhere in [MS-NLMP].pdf around 3.1.5.2.1 :-/
|
|
|
|
|
|
|
|
ntlm_cli_challenge = NTLM_UTILS::make_ntlmv2_clientchallenge(default_domain, default_name, dns_domain_name,
|
|
|
|
dns_host_name,client_challenge , chall_MsvAvTimestamp)
|
|
|
|
argntlm = { :ntlmv2_hash => NTLM_CRYPT::ntlmv2_hash(user, pass, domain),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
optntlm = { :nt_client_challenge => ntlm_cli_challenge}
|
|
|
|
ntlmv2_response = NTLM_CRYPT::ntlmv2_response(argntlm,optntlm)
|
|
|
|
resp_ntlm = ntlmv2_response
|
|
|
|
if self.send_lm
|
|
|
|
arglm = { :ntlmv2_hash => NTLM_CRYPT::ntlmv2_hash(user,pass, domain),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
optlm = { :client_challenge => client_challenge}
|
|
|
|
resp_lm = NTLM_CRYPT::lmv2_response(arglm, optlm)
|
|
|
|
else
|
|
|
|
resp_lm = "\x00" * 24
|
|
|
|
end
|
|
|
|
|
|
|
|
else # ntlm2_session
|
|
|
|
|
|
|
|
argntlm = { :ntlm_hash => NTLM_CRYPT::ntlm_hash(pass),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
optntlm = { :client_challenge => client_challenge}
|
|
|
|
|
|
|
|
resp_ntlm = NTLM_CRYPT::ntlm2_session(argntlm,optntlm).join[24,24]
|
|
|
|
# Generate the fake LANMAN hash
|
|
|
|
resp_lm = client_challenge + ("\x00" * 16)
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
else #we use lmv1/ntlmv1
|
2005-09-19 23:35:51 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
argntlm = { :ntlm_hash => NTLM_CRYPT::ntlm_hash(pass),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
|
|
|
|
resp_ntlm = NTLM_CRYPT::ntlm_response(argntlm)
|
|
|
|
if self.send_lm
|
|
|
|
arglm = { :lm_hash => NTLM_CRYPT::lm_hash(pass),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
resp_lm = NTLM_CRYPT::lm_response(arglm)
|
|
|
|
else
|
|
|
|
#when windows does not send lm in ntlmv1 type response,
|
|
|
|
# it gives lm response the same value as ntlm response
|
|
|
|
resp_lm = resp_ntlm
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else #send_ntlm = false
|
|
|
|
#lmv2
|
|
|
|
if self.usentlm2_session && self.use_ntlmv2
|
|
|
|
arglm = { :ntlmv2_hash => NTLM_CRYPT::ntlmv2_hash(user,pass, domain),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
optlm = { :client_challenge => client_challenge}
|
|
|
|
resp_lm = NTLM_CRYPT::lmv2_response(arglm, optlm)
|
|
|
|
else
|
|
|
|
arglm = { :lm_hash => NTLM_CRYPT::lm_hash(pass),
|
|
|
|
:challenge => self.challenge_key }
|
|
|
|
resp_lm = NTLM_CRYPT::lm_response(arglm)
|
|
|
|
end
|
|
|
|
resp_ntlm = ""
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
#create the sessionkey (aka signing key, aka mackey) and encrypted session key
|
|
|
|
#server will decide for key_size and key_exchange
|
|
|
|
enc_session_key = ''
|
|
|
|
if self.require_signing
|
|
|
|
server_ntlmssp_flags = blob[cidx + 20, 4].unpack("V")[0]
|
|
|
|
#set default key size and key exchange values
|
|
|
|
key_size = 40
|
|
|
|
key_exchange = false
|
|
|
|
#remove ntlmssp.negotiate56
|
|
|
|
ntlmssp_flags &= 0x7fffffff
|
|
|
|
#remove ntlmssp.negotiatekeyexch
|
|
|
|
ntlmssp_flags &= 0xbfffffff
|
|
|
|
#remove ntlmssp.negotiate128
|
|
|
|
ntlmssp_flags &= 0xdfffffff
|
|
|
|
#check the keyexchange
|
|
|
|
if server_ntlmssp_flags & NTLM_CONST::NEGOTIATE_KEY_EXCH != 0 then
|
|
|
|
key_exchange = true
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_KEY_EXCH
|
|
|
|
end
|
|
|
|
#check 128bits
|
|
|
|
if server_ntlmssp_flags & NTLM_CONST::NEGOTIATE_128 != 0 then
|
|
|
|
key_size = 128
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_128
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_56
|
|
|
|
#check 56bits
|
|
|
|
else
|
|
|
|
if server_ntlmssp_flags & NTLM_CONST::NEGOTIATE_56 != 0 then
|
|
|
|
key_size = 56
|
|
|
|
ntlmssp_flags |= NTLM_CONST::NEGOTIATE_56
|
|
|
|
end
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
#generate the user session key
|
|
|
|
lanman_weak = false
|
|
|
|
if self.send_ntlm #should be default
|
|
|
|
if self.usentlm2_session
|
|
|
|
if self.use_ntlmv2
|
|
|
|
user_session_key = NTLM_CRYPT::ntlmv2_user_session_key(user, pass, domain,
|
|
|
|
self.challenge_key, ntlm_cli_challenge)
|
|
|
|
else
|
|
|
|
user_session_key = NTLM_CRYPT::ntlm2_session_user_session_key(pass, self.challenge_key, client_challenge)
|
|
|
|
end
|
|
|
|
else #lmv1 / ntlmv1
|
|
|
|
if self.send_lm
|
|
|
|
if self.use_lanman_key
|
|
|
|
user_session_key = NTLM_CRYPT::lanman_session_key(pass, self.challenge_key)
|
|
|
|
lanman_weak = true
|
|
|
|
else
|
|
|
|
user_session_key = NTLM_CRYPT::ntlmv1_user_session_key(pass )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if self.usentlm2_session && self.use_ntlmv2
|
|
|
|
user_session_key = NTLM_CRYPT::lmv2_user_session_key(user, pass, domain,
|
|
|
|
self.challenge_key, client_challenge)
|
|
|
|
else
|
|
|
|
user_session_key = NTLM_CRYPT::lmv1_user_session_key(pass )
|
|
|
|
end
|
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
user_session_key = NTLM_CRYPT::make_weak_sessionkey(user_session_key,key_size, lanman_weak)
|
|
|
|
self.sequence_counter = 0
|
|
|
|
#sessionkey and encrypted session key
|
|
|
|
if key_exchange
|
|
|
|
self.signing_key = Rex::Text.rand_text(16)
|
|
|
|
enc_session_key = NTLM_CRYPT::encrypt_sessionkey(self.signing_key, user_session_key)
|
|
|
|
else
|
|
|
|
self.signing_key = user_session_key
|
|
|
|
end
|
|
|
|
|
|
|
|
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)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
|
|
pkt['Payload']['SMB'].v['UserID'] = temp_user_id
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2005-09-19 23:35:51 +00:00
|
|
|
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
2011-03-07 19:57:53 +00:00
|
|
|
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['Payload'] = blob + native_data
|
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
# NOTE: if do_recv is set to false, we cant reach here...
|
2005-09-19 23:35:51 +00:00
|
|
|
self.smb_send(pkt.to_s)
|
2010-08-18 17:20:55 +00:00
|
|
|
|
2005-09-23 09:14:03 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 09:14:03 +00:00
|
|
|
# Make sure that authentication succeeded
|
|
|
|
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
|
|
|
|
if (user.length == 0)
|
2011-03-07 19:57:53 +00:00
|
|
|
return self.session_setup_no_ntlmssp(user, pass, domain)
|
2005-09-23 09:14:03 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 09:14:03 +00:00
|
|
|
failure = XCEPT::ErrorCode.new
|
|
|
|
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
|
|
failure.command = ack['Payload']['SMB'].v['Command']
|
|
|
|
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
|
|
raise failure
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2007-07-03 04:20:50 +00:00
|
|
|
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
|
|
self.auth_user = user
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
2005-09-19 23:35:51 +00:00
|
|
|
return ack
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-09-22 04:04:06 +00:00
|
|
|
|
|
|
|
|
2005-11-26 02:34:39 +00:00
|
|
|
# An exploit helper function for sending arbitrary SPNEGO blobs
|
2011-03-07 19:57:53 +00:00
|
|
|
def session_setup_with_ntlmssp_blob(blob = '', do_recv = true)
|
2005-11-26 02:34:39 +00:00
|
|
|
native_data = ''
|
|
|
|
native_data << self.native_os + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
native_data << self.native_lm + "\x00"
|
|
|
|
|
2005-11-26 02:34:39 +00:00
|
|
|
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-11-26 02:34:39 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
|
|
pkt['Payload']['SMB'].v['UserID'] = 0
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2005-11-26 02:34:39 +00:00
|
|
|
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
|
|
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['Payload'] = blob + native_data
|
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-11-26 02:34:39 +00:00
|
|
|
self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, false)
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2005-11-26 02:34:39 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
# Authenticate using extended security negotiation (NTLMSSP), but stop half-way, using the temporary ID
|
|
|
|
def session_setup_with_ntlmssp_temp(domain = '', name = nil, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
if (name == nil)
|
|
|
|
name = Rex::Text.rand_text_alphanumeric(16)
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2011-03-07 19:57:53 +00:00
|
|
|
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
native_data = ''
|
|
|
|
native_data << self.native_os + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
native_data << self.native_lm + "\x00"
|
2008-03-02 04:46:13 +00:00
|
|
|
|
|
|
|
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
|
|
pkt['Payload'].v['MaxMPX'] = 2
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['VCNum'] = 1
|
2008-03-02 04:46:13 +00:00
|
|
|
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
|
|
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
|
|
pkt['Payload'].v['SessionKey'] = self.session_id
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['Payload'] = blob + native_data
|
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
# The server doesn't know about NTLM_NEGOTIATE, try ntlmv1
|
|
|
|
if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
|
2011-03-07 19:57:53 +00:00
|
|
|
return session_setup_no_ntlmssp(user, pass, domain)
|
2008-03-02 04:46:13 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
# Make sure the error code tells us to continue processing
|
|
|
|
if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
|
|
|
|
failure = XCEPT::ErrorCode.new
|
|
|
|
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
|
|
failure.command = ack['Payload']['SMB'].v['Command']
|
|
|
|
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
|
|
raise failure
|
|
|
|
end
|
|
|
|
|
|
|
|
# Extract the SecurityBlob from the response
|
|
|
|
data = ack['Payload'].v['Payload']
|
|
|
|
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
|
|
|
|
|
|
|
# Extract the native lanman and os strings
|
|
|
|
info = data.split(/\x00/)
|
|
|
|
self.peer_native_os = info[0]
|
|
|
|
self.peer_native_lm = info[1]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
# Save the temporary UserID for use in the next request
|
|
|
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
# Extract the NTLM challenge key the lazy way
|
|
|
|
cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00")
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
if (cidx == -1)
|
|
|
|
raise XCEPT::NTLM2MissingChallenge
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
# Store the challenge key
|
|
|
|
self.challenge_key = blob[cidx + 24, 8]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
return ack
|
2009-12-29 14:00:49 +00:00
|
|
|
end
|
2008-03-02 04:46:13 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
# Connect to a specified share with an optional password
|
2010-08-18 17:20:55 +00:00
|
|
|
def tree_connect(share = 'IPC$', pass = '', do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-05-31 21:49:46 +00:00
|
|
|
data = [ pass, share, '?????' ].collect{ |a| a + "\x00" }.join('');
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt = CONST::SMB_TREE_CONN_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_CONNECT_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 4
|
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['PasswordLen'] = pass.length + 1
|
|
|
|
pkt['Payload'].v['Capabilities'] = 64
|
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_TREE_CONNECT_ANDX)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
self.last_tree_id = ack['Payload']['SMB'].v['TreeID']
|
2006-05-31 21:49:46 +00:00
|
|
|
# why bother?
|
|
|
|
# info = ack['Payload'].v['Payload'].split(/\x00/)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
return ack
|
|
|
|
end
|
2005-09-22 04:04:06 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Disconnect from the current tree
|
2010-08-18 17:20:55 +00:00
|
|
|
def tree_disconnect(tree_id = self.last_tree_id, do_recv = true)
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
pkt = CONST::SMB_TREE_DISCONN_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_DISCONNECT
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 0
|
|
|
|
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_TREE_DISCONNECT)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
if (tree_id == self.last_tree_id)
|
|
|
|
self.last_tree_id = 0
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
return ack
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Returns a SMB_CREATE_RES response for a given named pipe
|
2006-04-30 19:49:27 +00:00
|
|
|
def create_pipe(filename, disposition = 1, impersonation = 2)
|
2006-07-11 20:02:45 +00:00
|
|
|
self.create(filename)
|
2005-09-23 03:43:04 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Creates a file or opens an existing pipe
|
2010-08-18 17:20:55 +00:00
|
|
|
def create(filename, disposition = 1, impersonation = 2, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt = CONST::SMB_CREATE_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-26 16:59:44 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 24
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['AndX'] = 255
|
2005-10-02 06:53:39 +00:00
|
|
|
pkt['Payload'].v['FileNameLen'] = filename.length
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['CreateFlags'] = 0x16
|
2005-10-03 13:51:05 +00:00
|
|
|
pkt['Payload'].v['AccessMask'] = 0x02000000 # Maximum Allowed
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['ShareAccess'] = 7
|
2005-10-03 13:51:05 +00:00
|
|
|
pkt['Payload'].v['CreateOptions'] = 0
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['Impersonation'] = impersonation
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['Disposition'] = disposition
|
2005-10-02 06:53:39 +00:00
|
|
|
pkt['Payload'].v['Payload'] = filename + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-26 16:59:44 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_NT_CREATE_ANDX)
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
# Save off the FileID
|
|
|
|
if (ack['Payload'].v['FileID'] > 0)
|
2009-12-29 14:00:49 +00:00
|
|
|
self.last_file_id = ack['Payload'].v['FileID']
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
return ack
|
|
|
|
end
|
|
|
|
|
|
|
|
# Deletes a file from a share
|
2010-08-18 17:20:55 +00:00
|
|
|
def delete(filename, tree_id = self.last_tree_id, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt = CONST::SMB_DELETE_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_DELETE
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 1
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['SearchAttributes'] = 0x06
|
|
|
|
pkt['Payload'].v['BufferFormat'] = 4
|
2005-10-02 06:53:39 +00:00
|
|
|
pkt['Payload'].v['Payload'] = filename + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_DELETE)
|
|
|
|
|
|
|
|
return ack
|
|
|
|
end
|
|
|
|
|
|
|
|
# Opens an existing file or creates a new one
|
2010-08-18 17:20:55 +00:00
|
|
|
def open(filename, mode = 0x12, access = 0x42, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt = CONST::SMB_OPEN_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_OPEN_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 15
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['AndX'] = 255
|
2005-10-02 06:53:39 +00:00
|
|
|
pkt['Payload'].v['Access'] = access
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['SearchAttributes'] = 0x06
|
2009-12-29 14:00:49 +00:00
|
|
|
pkt['Payload'].v['OpenFunction'] = mode
|
2005-10-02 06:53:39 +00:00
|
|
|
pkt['Payload'].v['Payload'] = filename + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_OPEN_ANDX)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Save off the FileID
|
|
|
|
if (ack['Payload'].v['FileID'] > 0)
|
2009-12-29 14:00:49 +00:00
|
|
|
self.last_file_id = ack['Payload'].v['FileID']
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
return ack
|
2005-09-23 03:43:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Closes an open file handle
|
2010-08-18 17:20:55 +00:00
|
|
|
def close(file_id = self.last_file_id, tree_id = self.last_tree_id, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt = CONST::SMB_CLOSE_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 09:14:03 +00:00
|
|
|
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 3
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['FileID'] = file_id
|
|
|
|
pkt['Payload'].v['LastWrite'] = -1
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_CLOSE)
|
|
|
|
|
|
|
|
return ack
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
2005-09-22 04:04:06 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Writes data to an open file handle
|
2010-08-18 17:20:55 +00:00
|
|
|
def write(file_id = self.last_file_id, offset = 0, data = '', do_recv = true)
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt = CONST::SMB_WRITE_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
data_offset = pkt.to_s.length - 4
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
filler = EVADE.make_offset_filler(evasion_opts['pad_data'], 4096 - data.length - data_offset)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_WRITE_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2805
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 14
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['FileID'] = file_id
|
|
|
|
pkt['Payload'].v['Offset'] = offset
|
|
|
|
pkt['Payload'].v['Reserved2'] = -1
|
|
|
|
pkt['Payload'].v['WriteMode'] = 8
|
|
|
|
pkt['Payload'].v['Remaining'] = data.length
|
|
|
|
# pkt['Payload'].v['DataLenHigh'] = (data.length / 65536).to_i
|
|
|
|
pkt['Payload'].v['DataLenLow'] = (data.length % 65536).to_i
|
2005-09-23 06:27:22 +00:00
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset + filler.length
|
|
|
|
pkt['Payload'].v['Payload'] = filler + data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_WRITE_ANDX)
|
|
|
|
|
|
|
|
return ack
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Reads data from an open file handle
|
2010-08-18 17:20:55 +00:00
|
|
|
def read(file_id = self.last_file_id, offset = 0, data_length = 64000, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt = CONST::SMB_READ_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 10
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['AndX'] = 255
|
|
|
|
pkt['Payload'].v['FileID'] = file_id
|
|
|
|
pkt['Payload'].v['Offset'] = offset
|
|
|
|
# pkt['Payload'].v['MaxCountHigh'] = (data_length / 65536).to_i
|
|
|
|
pkt['Payload'].v['MaxCountLow'] = (data_length % 65536).to_i
|
|
|
|
pkt['Payload'].v['MinCount'] = data_length
|
2006-05-15 16:44:44 +00:00
|
|
|
pkt['Payload'].v['Reserved2'] = -1
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
2005-10-03 13:51:05 +00:00
|
|
|
|
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_READ_ANDX, true)
|
2005-12-13 06:08:40 +00:00
|
|
|
|
2005-10-03 13:51:05 +00:00
|
|
|
err = ack['Payload']['SMB'].v['ErrorClass']
|
2005-12-13 06:08:40 +00:00
|
|
|
|
2006-01-27 05:28:16 +00:00
|
|
|
# Catch some non-fatal error codes
|
2005-10-03 13:51:05 +00:00
|
|
|
if (err != 0 && err != CONST::SMB_ERROR_BUFFER_OVERFLOW)
|
|
|
|
failure = XCEPT::ErrorCode.new
|
|
|
|
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
|
|
failure.command = ack['Payload']['SMB'].v['Command']
|
|
|
|
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
|
|
raise failure
|
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
return ack
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Perform a transaction against a named pipe
|
2006-06-01 15:18:53 +00:00
|
|
|
def trans_named_pipe(file_id, data = '', no_response = nil)
|
2006-04-30 19:49:27 +00:00
|
|
|
pipe = EVADE.make_trans_named_pipe_name(evasion_opts['pad_file'])
|
2006-06-01 15:18:53 +00:00
|
|
|
self.trans(pipe, '', data, 2, [0x26, file_id].pack('vv'), no_response)
|
2005-09-22 09:04:40 +00:00
|
|
|
end
|
|
|
|
|
2006-07-11 20:02:45 +00:00
|
|
|
# Perform a mailslot write over SMB
|
|
|
|
# Warning: This can kill srv.sys unless MS06-035 is applied
|
|
|
|
def trans_mailslot (name, data = '')
|
|
|
|
# Setup data must be:
|
|
|
|
# Operation: 1 (write)
|
|
|
|
# Priority: 0
|
|
|
|
# Class: Reliable
|
2006-07-13 03:04:53 +00:00
|
|
|
self.trans_maxzero(name, '', data, 3, [1, 0, 1].pack('vvv'), true )
|
2006-07-11 20:02:45 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
# Perform a transaction against a given pipe name
|
2010-08-18 17:20:55 +00:00
|
|
|
def trans(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
2005-09-22 04:04:06 +00:00
|
|
|
|
2005-09-23 06:27:22 +00:00
|
|
|
# Null-terminate the pipe parameter if needed
|
2010-03-14 16:20:24 +00:00
|
|
|
if (pipe[-1,1] != "\x00")
|
2005-09-22 04:04:06 +00:00
|
|
|
pipe << "\x00"
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2005-09-23 06:27:22 +00:00
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
2005-09-23 06:27:22 +00:00
|
|
|
mlen = 4200
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 06:27:22 +00:00
|
|
|
# Figure out how much space is taken up by our current arguments
|
|
|
|
xlen = pipe.length + param.length + body.length
|
|
|
|
|
|
|
|
filler1 = ''
|
|
|
|
filler2 = ''
|
|
|
|
|
|
|
|
# Fill any available space depending on the evasion settings
|
|
|
|
if (xlen < mlen)
|
2006-04-30 19:49:27 +00:00
|
|
|
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
|
|
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
2005-09-23 06:27:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Squish the whole thing together
|
|
|
|
data = pipe + filler1 + param + filler2 + body
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 06:27:22 +00:00
|
|
|
# Throw some form of a warning out?
|
|
|
|
if (data.length > mlen)
|
2006-06-01 15:18:53 +00:00
|
|
|
# XXX This call will more than likely fail :-(
|
2005-09-23 06:27:22 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 06:27:22 +00:00
|
|
|
# Calculate all of the offsets
|
2005-09-22 09:04:40 +00:00
|
|
|
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
2005-09-23 06:27:22 +00:00
|
|
|
param_offset = base_offset + pipe.length + filler1.length
|
|
|
|
data_offset = param_offset + filler2.length + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
|
|
pkt['Payload'].v['DataCountMax'] = 65504
|
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
|
|
|
pkt['Payload'].v['SetupCount'] = setup_count
|
|
|
|
pkt['Payload'].v['SetupData'] = setup_data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
if no_response
|
|
|
|
pkt['Payload'].v['Flags'] = 2
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if no_response or not do_recv
|
2006-07-13 03:04:53 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
2006-07-13 03:04:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Perform a transaction against a given pipe name
|
|
|
|
# Difference from trans: sets MaxParam/MaxData to zero
|
|
|
|
# This is required to trigger mailslot bug :-(
|
2010-08-18 17:20:55 +00:00
|
|
|
def trans_maxzero(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
2006-07-13 03:04:53 +00:00
|
|
|
|
|
|
|
# Null-terminate the pipe parameter if needed
|
|
|
|
if (pipe[-1] != 0)
|
|
|
|
pipe << "\x00"
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
2006-07-13 03:04:53 +00:00
|
|
|
mlen = 4200
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
# Figure out how much space is taken up by our current arguments
|
|
|
|
xlen = pipe.length + param.length + body.length
|
|
|
|
|
|
|
|
filler1 = ''
|
|
|
|
filler2 = ''
|
|
|
|
|
|
|
|
# Fill any available space depending on the evasion settings
|
|
|
|
if (xlen < mlen)
|
|
|
|
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
|
|
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Squish the whole thing together
|
|
|
|
data = pipe + filler1 + param + filler2 + body
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
# Throw some form of a warning out?
|
|
|
|
if (data.length > mlen)
|
|
|
|
# XXX This call will more than likely fail :-(
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
# Calculate all of the offsets
|
|
|
|
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
|
|
param_offset = base_offset + pipe.length + filler1.length
|
|
|
|
data_offset = param_offset + filler2.length + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
2006-07-11 20:02:45 +00:00
|
|
|
pkt['Payload'].v['ParamCountMax'] = 0
|
|
|
|
pkt['Payload'].v['DataCountMax'] = 0
|
2005-09-22 09:04:40 +00:00
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
|
|
|
pkt['Payload'].v['SetupCount'] = setup_count
|
|
|
|
pkt['Payload'].v['SetupData'] = setup_data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 04:04:06 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-06-01 15:18:53 +00:00
|
|
|
if no_response
|
|
|
|
pkt['Payload'].v['Flags'] = 2
|
2006-04-08 06:35:35 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if no_response or not do_recv
|
2006-04-08 06:35:35 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
2006-06-01 15:18:53 +00:00
|
|
|
end
|
2006-04-08 06:35:35 +00:00
|
|
|
|
2006-07-13 03:04:53 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
# Perform a transaction against a given pipe name (no null terminator)
|
2010-08-18 17:20:55 +00:00
|
|
|
def trans_nonull(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
|
|
|
|
2009-12-29 14:00:49 +00:00
|
|
|
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
2006-08-28 00:24:34 +00:00
|
|
|
mlen = 4200
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
# Figure out how much space is taken up by our current arguments
|
|
|
|
xlen = pipe.length + param.length + body.length
|
|
|
|
|
|
|
|
filler1 = ''
|
|
|
|
filler2 = ''
|
|
|
|
|
|
|
|
# Fill any available space depending on the evasion settings
|
|
|
|
if (xlen < mlen)
|
|
|
|
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
|
|
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Squish the whole thing together
|
|
|
|
data = pipe + filler1 + param + filler2 + body
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
# Throw some form of a warning out?
|
|
|
|
if (data.length > mlen)
|
|
|
|
# XXX This call will more than likely fail :-(
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
# Calculate all of the offsets
|
|
|
|
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
|
|
param_offset = base_offset + pipe.length + filler1.length
|
|
|
|
data_offset = param_offset + filler2.length + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
|
|
pkt['Payload'].v['ParamCountMax'] = 0
|
|
|
|
pkt['Payload'].v['DataCountMax'] = 0
|
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
|
|
|
pkt['Payload'].v['SetupCount'] = setup_count
|
|
|
|
pkt['Payload'].v['SetupData'] = setup_data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-08-28 00:24:34 +00:00
|
|
|
if no_response
|
|
|
|
pkt['Payload'].v['Flags'] = 2
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if no_response or not do_recv
|
2006-08-28 00:24:34 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
2006-08-28 00:24:34 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
# Perform a transaction2 request using the specified subcommand, parameters, and data
|
2010-08-18 17:20:55 +00:00
|
|
|
def trans2(subcommand, param = '', body = '', do_recv = true)
|
2005-09-23 03:43:04 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
setup_count = 1
|
|
|
|
setup_data = [subcommand].pack('v')
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
data = param + body
|
|
|
|
|
|
|
|
pkt = CONST::SMB_TRANS2_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
2006-04-30 19:49:27 +00:00
|
|
|
param_offset = base_offset
|
2005-09-23 03:43:04 +00:00
|
|
|
data_offset = param_offset + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
|
|
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
|
|
pkt['Payload'].v['DataCountMax'] = 65504
|
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
|
|
|
pkt['Payload'].v['SetupCount'] = setup_count
|
|
|
|
pkt['Payload'].v['SetupData'] = setup_data
|
2006-04-30 19:49:27 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_TRANSACTION2)
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-22 09:04:40 +00:00
|
|
|
return ack
|
2005-09-23 03:43:04 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
# Perform a nttransaction request using the specified subcommand, parameters, and data
|
2010-08-18 17:20:55 +00:00
|
|
|
def nttrans(subcommand, param = '', body = '', setup_count = 0, setup_data = '', do_recv = true)
|
2005-09-23 03:43:04 +00:00
|
|
|
|
|
|
|
data = param + body
|
|
|
|
|
|
|
|
pkt = CONST::SMB_NTTRANS_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
2006-09-14 05:41:54 +00:00
|
|
|
param_offset = base_offset
|
2005-09-23 03:43:04 +00:00
|
|
|
data_offset = param_offset + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 19 + setup_count
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
|
|
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
|
|
pkt['Payload'].v['DataCountMax'] = 65504
|
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
|
|
|
pkt['Payload'].v['SetupCount'] = setup_count
|
|
|
|
pkt['Payload'].v['SetupData'] = setup_data
|
|
|
|
pkt['Payload'].v['Subcommand'] = subcommand
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2005-09-23 03:43:04 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT)
|
|
|
|
return ack
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
# Perform a nttransaction request using the specified subcommand, parameters, and data
|
2010-08-18 17:20:55 +00:00
|
|
|
def nttrans_secondary(param = '', body = '', do_recv = true)
|
2006-09-14 05:41:54 +00:00
|
|
|
|
|
|
|
data = param + body
|
|
|
|
|
|
|
|
pkt = CONST::SMB_NTTRANS_SECONDARY_PKT.make_struct
|
|
|
|
self.smb_defaults(pkt['Payload']['SMB'])
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
base_offset = pkt.to_s.length - 4
|
|
|
|
param_offset = base_offset
|
|
|
|
data_offset = param_offset + param.length
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT_SECONDARY
|
|
|
|
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
2011-03-07 19:57:53 +00:00
|
|
|
if self.require_signing
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
|
|
else
|
|
|
|
#ascii
|
|
|
|
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
|
|
end
|
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
pkt['Payload']['SMB'].v['WordCount'] = 18
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
|
|
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
|
|
pkt['Payload'].v['ParamCount'] = param.length
|
|
|
|
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
|
|
pkt['Payload'].v['DataCount'] = body.length
|
|
|
|
pkt['Payload'].v['DataOffset'] = data_offset
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
pkt['Payload'].v['Payload'] = data
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2010-08-18 17:20:55 +00:00
|
|
|
ret = self.smb_send(pkt.to_s)
|
|
|
|
return ret if not do_recv
|
|
|
|
|
2006-09-14 05:41:54 +00:00
|
|
|
ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT_SECONDARY)
|
|
|
|
return ack
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
def queryfs(level)
|
|
|
|
parm = [level].pack('v')
|
|
|
|
|
|
|
|
begin
|
|
|
|
resp = trans2(CONST::TRANS2_QUERY_FS_INFO, parm, '')
|
|
|
|
|
|
|
|
pcnt = resp['Payload'].v['ParamCount']
|
|
|
|
dcnt = resp['Payload'].v['DataCount']
|
|
|
|
poff = resp['Payload'].v['ParamOffset']
|
|
|
|
doff = resp['Payload'].v['DataOffset']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Get the raw packet bytes
|
|
|
|
resp_rpkt = resp.to_s
|
2010-02-05 06:38:24 +00:00
|
|
|
|
|
|
|
# Remove the NetBIOS header
|
|
|
|
resp_rpkt.slice!(0, 4)
|
|
|
|
|
|
|
|
resp_parm = resp_rpkt[poff, pcnt]
|
|
|
|
resp_data = resp_rpkt[doff, dcnt]
|
|
|
|
return resp_data
|
|
|
|
|
|
|
|
rescue ::Exception
|
|
|
|
raise $!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def symlink(src,dst)
|
|
|
|
parm = [513, 0x00000000].pack('vV') + src + "\x00"
|
|
|
|
|
|
|
|
begin
|
|
|
|
resp = trans2(CONST::TRANS2_SET_PATH_INFO, parm, dst + "\x00")
|
|
|
|
|
|
|
|
pcnt = resp['Payload'].v['ParamCount']
|
|
|
|
dcnt = resp['Payload'].v['DataCount']
|
|
|
|
poff = resp['Payload'].v['ParamOffset']
|
|
|
|
doff = resp['Payload'].v['DataOffset']
|
|
|
|
|
|
|
|
# Get the raw packet bytes
|
|
|
|
resp_rpkt = resp.to_s
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Remove the NetBIOS header
|
|
|
|
resp_rpkt.slice!(0, 4)
|
|
|
|
|
|
|
|
resp_parm = resp_rpkt[poff, pcnt]
|
|
|
|
resp_data = resp_rpkt[doff, dcnt]
|
|
|
|
return resp_data
|
|
|
|
|
|
|
|
rescue ::Exception
|
|
|
|
raise $!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Obtains allocation information on the mounted tree
|
|
|
|
def queryfs_info_allocation
|
|
|
|
data = queryfs(CONST::SMB_INFO_ALLOCATION)
|
|
|
|
head = %w{fs_id sectors_per_unit unit_total units_available bytes_per_sector}
|
|
|
|
vals = data.unpack('VVVVv')
|
|
|
|
info = { }
|
|
|
|
head.each_index {|i| info[head[i]]=vals[i]}
|
|
|
|
return info
|
|
|
|
end
|
|
|
|
|
|
|
|
# Obtains volume information on the mounted tree
|
|
|
|
def queryfs_info_volume
|
|
|
|
data = queryfs(CONST::SMB_INFO_VOLUME)
|
|
|
|
vals = data.unpack('VCA*')
|
|
|
|
return {
|
|
|
|
'serial' => vals[0],
|
|
|
|
'label' => vals[2][0,vals[1]].gsub("\x00", '')
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Obtains file system volume information on the mounted tree
|
|
|
|
def queryfs_fs_volume
|
|
|
|
data = queryfs(CONST::SMB_QUERY_FS_VOLUME_INFO)
|
|
|
|
vals = data.unpack('VVVVCCA*')
|
|
|
|
return {
|
|
|
|
'create_time' => (vals[1] << 32) + vals[0],
|
|
|
|
'serial' => vals[2],
|
|
|
|
'label' => vals[6][0,vals[3]].gsub("\x00", '')
|
2009-12-29 14:00:49 +00:00
|
|
|
}
|
|
|
|
end
|
2006-04-30 19:49:27 +00:00
|
|
|
|
|
|
|
# Obtains file system size information on the mounted tree
|
|
|
|
def queryfs_fs_size
|
|
|
|
data = queryfs(CONST::SMB_QUERY_FS_SIZE_INFO)
|
|
|
|
vals = data.unpack('VVVVVV')
|
|
|
|
return {
|
|
|
|
'total_alloc_units' => (vals[1] << 32) + vals[0],
|
|
|
|
'total_free_units' => (vals[3] << 32) + vals[2],
|
|
|
|
'sectors_per_unit' => vals[4],
|
|
|
|
'bytes_per_sector' => vals[5]
|
2009-12-29 14:00:49 +00:00
|
|
|
}
|
2006-04-30 19:49:27 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Obtains file system device information on the mounted tree
|
|
|
|
def queryfs_fs_device
|
|
|
|
data = queryfs(CONST::SMB_QUERY_FS_DEVICE_INFO)
|
|
|
|
vals = data.unpack('VV')
|
|
|
|
return {
|
|
|
|
'device_type' => vals[0],
|
|
|
|
'device_chars' => vals[1],
|
2009-12-29 14:00:49 +00:00
|
|
|
}
|
2006-04-30 19:49:27 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Obtains file system attribute information on the mounted tree
|
|
|
|
def queryfs_fs_attribute
|
|
|
|
data = queryfs(CONST::SMB_QUERY_FS_ATTRIBUTE_INFO)
|
|
|
|
vals = data.unpack('VVVA*')
|
|
|
|
return {
|
|
|
|
'fs_attributes' => vals[0],
|
|
|
|
'max_file_name' => vals[1],
|
|
|
|
'fs_name' => vals[3][0, vals[2]].gsub("\x00", '')
|
2009-12-29 14:00:49 +00:00
|
|
|
}
|
2006-04-30 19:49:27 +00:00
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Enumerates a specific path on the mounted tree
|
|
|
|
def find_first(path)
|
|
|
|
files = { }
|
|
|
|
parm = [
|
|
|
|
26, # Search for ALL files
|
|
|
|
512, # Maximum search count
|
|
|
|
6, # Resume and Close on End of Search
|
|
|
|
260, # Level of interest
|
|
|
|
0, # Storage type is zero
|
|
|
|
].pack('vvvvV') + path + "\x00"
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
begin
|
|
|
|
resp = trans2(CONST::TRANS2_FIND_FIRST2, parm, '')
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
pcnt = resp['Payload'].v['ParamCount']
|
|
|
|
dcnt = resp['Payload'].v['DataCount']
|
|
|
|
poff = resp['Payload'].v['ParamOffset']
|
|
|
|
doff = resp['Payload'].v['DataOffset']
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Get the raw packet bytes
|
|
|
|
resp_rpkt = resp.to_s
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# Remove the NetBIOS header
|
|
|
|
resp_rpkt.slice!(0, 4)
|
|
|
|
|
|
|
|
resp_parm = resp_rpkt[poff, pcnt]
|
|
|
|
resp_data = resp_rpkt[doff, dcnt]
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# search id, search count, end of search, error offset, last name offset
|
|
|
|
sid, scnt, eos, eoff, loff = resp_parm.unpack('v5')
|
|
|
|
|
|
|
|
didx = 0
|
|
|
|
while (didx < resp_data.length)
|
|
|
|
info_buff = resp_data[didx, 70]
|
|
|
|
break if info_buff.length != 70
|
|
|
|
info = info_buff.unpack(
|
|
|
|
'V'+ # Next Entry Offset
|
|
|
|
'V'+ # File Index
|
|
|
|
'VV'+ # Time Create
|
|
|
|
'VV'+ # Time Last Access
|
|
|
|
'VV'+ # Time Last Write
|
|
|
|
'VV'+ # Time Change
|
|
|
|
'VV'+ # End of File
|
|
|
|
'VV'+ # Allocation Size
|
|
|
|
'V'+ # File Attributes
|
|
|
|
'V'+ # File Name Length
|
|
|
|
'V'+ # Extended Attr List Length
|
|
|
|
'C'+ # Short File Name Length
|
|
|
|
'C' # Reserved
|
|
|
|
)
|
|
|
|
name = resp_data[didx + 70 + 24, info[15]].sub!(/\x00+$/, '')
|
2009-12-29 14:00:49 +00:00
|
|
|
files[name] =
|
2006-04-30 19:49:27 +00:00
|
|
|
{
|
|
|
|
'type' => (info[14] & 0x10) ? 'D' : 'F',
|
|
|
|
'attr' => info[14],
|
|
|
|
'info' => info
|
|
|
|
}
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
break if info[0] == 0
|
|
|
|
didx += info[0]
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
last_search_id = sid
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
rescue ::Exception
|
|
|
|
raise $!
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
return files
|
|
|
|
end
|
2005-09-23 03:43:04 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# TODO: Finish this method... requires search_id, resume_key, and filename from first
|
|
|
|
=begin
|
|
|
|
def find_next(path, sid = last_search_id)
|
|
|
|
|
|
|
|
parm = [
|
|
|
|
sid, # Search ID
|
|
|
|
512, # Maximum search count
|
|
|
|
260, # Level of interest
|
|
|
|
0, # Resume key from previous
|
|
|
|
1, # Close search if end of search
|
|
|
|
].pack('vvvVv') + path + "\x00"
|
|
|
|
|
|
|
|
return files
|
|
|
|
end
|
|
|
|
=end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# 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, '')
|
|
|
|
end
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# public read/write methods
|
2010-09-18 01:12:44 +00:00
|
|
|
attr_accessor :native_os, :native_lm, :encrypt_passwords, :extended_security, :read_timeout, :evasion_opts
|
2011-03-07 19:57:53 +00:00
|
|
|
attr_accessor :verify_signature, :use_ntlmv2, :usentlm2_session, :send_lm, :use_lanman_key, :send_ntlm
|
|
|
|
attr_accessor :system_time, :system_zone
|
2005-09-23 03:43:04 +00:00
|
|
|
|
2006-04-30 19:49:27 +00:00
|
|
|
# public read methods
|
2005-09-16 09:27:41 +00:00
|
|
|
attr_reader :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
|
|
|
|
attr_reader :default_domain, :default_name, :auth_user, :auth_user_id
|
2006-04-30 19:49:27 +00:00
|
|
|
attr_reader :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
|
2010-03-31 02:25:44 +00:00
|
|
|
attr_reader :dns_host_name, :dns_domain_name
|
2005-09-19 23:35:51 +00:00
|
|
|
attr_reader :security_mode, :server_guid
|
2011-03-07 19:57:53 +00:00
|
|
|
#signing related
|
|
|
|
attr_reader :sequence_counter,:signing_key, :require_signing
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-16 09:27:41 +00:00
|
|
|
# private methods
|
|
|
|
attr_writer :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
|
|
|
|
attr_writer :default_domain, :default_name, :auth_user, :auth_user_id
|
2009-12-29 14:00:49 +00:00
|
|
|
attr_writer :dns_host_name, :dns_domain_name
|
2006-04-30 19:49:27 +00:00
|
|
|
attr_writer :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
|
2005-09-19 23:35:51 +00:00
|
|
|
attr_writer :security_mode, :server_guid
|
2011-03-07 19:57:53 +00:00
|
|
|
#signing related
|
|
|
|
attr_writer :sequence_counter,:signing_key, :require_signing
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-16 09:27:41 +00:00
|
|
|
attr_accessor :socket
|
2009-12-29 14:00:49 +00:00
|
|
|
|
2005-09-16 09:27:41 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2008-11-11 22:57:18 +00:00
|
|
|
end
|