From ff202a5f5b0103b4dcd98b237c30b52117678e75 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Thu, 26 Apr 2018 10:39:25 -0500 Subject: [PATCH] Simpleclient/SMB2 support --- lib/msf/core/exploit/smb/client.rb | 2 +- lib/msf/core/exploit/smb/client/psexec.rb | 2 +- lib/rex/proto/dcerpc/client.rb | 2 +- lib/rex/proto/smb/simpleclient.rb | 36 ++++++++++-------- lib/rex/proto/smb/simpleclient/open_file.rb | 39 +++++++++----------- modules/auxiliary/admin/smb/download_file.rb | 2 +- modules/auxiliary/admin/smb/upload_file.rb | 2 +- 7 files changed, 42 insertions(+), 43 deletions(-) diff --git a/lib/msf/core/exploit/smb/client.rb b/lib/msf/core/exploit/smb/client.rb index 09e9078b7e..e0d6ed23ef 100644 --- a/lib/msf/core/exploit/smb/client.rb +++ b/lib/msf/core/exploit/smb/client.rb @@ -218,7 +218,7 @@ module Msf # @raise [Rex::Proto::SMB::Exceptions::ErrorCode] def smb_file_exist?(file) begin - fd = simple.open(file, 'ro') + fd = simple.open(file, 'o') rescue XCEPT::ErrorCode => e # If attempting to open the file results in a "*_NOT_FOUND" error, # then we can be sure the file is not there. diff --git a/lib/msf/core/exploit/smb/client/psexec.rb b/lib/msf/core/exploit/smb/client/psexec.rb index 11f5e86983..9720f45ec3 100644 --- a/lib/msf/core/exploit/smb/client/psexec.rb +++ b/lib/msf/core/exploit/smb/client/psexec.rb @@ -75,7 +75,7 @@ module Exploit::Remote::SMB::Client::Psexec def smb_read_file(smbshare, host, file) begin simple.connect("\\\\#{host}\\#{smbshare}") - file = simple.open(file, 'ro') + file = simple.open(file, 'o') contents = file.read file.close simple.disconnect("\\\\#{host}\\#{smbshare}") diff --git a/lib/rex/proto/dcerpc/client.rb b/lib/rex/proto/dcerpc/client.rb index f8816e2d11..72500e53d4 100644 --- a/lib/rex/proto/dcerpc/client.rb +++ b/lib/rex/proto/dcerpc/client.rb @@ -158,7 +158,7 @@ require 'rex/proto/smb/exceptions' end end - data = self.socket.read( read_cnt, rand(1024)+1) + data = self.socket.read(read_cnt, rand(1024)+1) break if !(data and data.length > 0) raw_response += data diff --git a/lib/rex/proto/smb/simpleclient.rb b/lib/rex/proto/smb/simpleclient.rb index 839573b49f..4abcaffcd6 100644 --- a/lib/rex/proto/smb/simpleclient.rb +++ b/lib/rex/proto/smb/simpleclient.rb @@ -165,17 +165,26 @@ attr_accessor :socket, :client, :direct, :shares, :last_share end - def open(path, perm, chunk_size = 48000) - mode = UTILS.open_mode_to_mode(perm) - access = UTILS.open_mode_to_access(perm) + def open(path, perm, chunk_size = 48000, read: true, write: false) + mode = 0 + perm.each_byte { |c| + case [c].pack('C').downcase + when 'x', 'c' + mode |= RubySMB::Dispositions::FILE_CREATE + when 'o' + mode |= RubySMB::Dispositions::FILE_OPEN + when 's' + mode |= RubySMB::Dispositions::FILE_SUPERSEDE + end + } - ok = self.client.open(path, mode, access) - file_id = if ok.respond_to?(:guid) - ok.guid - elsif ok.respond_to?(:fid) - ok.fid - end - fh = OpenFile.new(self.client, path, self.client.last_tree_id, file_id) + if write + ok = self.client.open(path, mode, read: true, write: true) + else + ok = self.client.open(path, mode, read: true) + end + + fh = OpenFile.new(self.client, path, self.client.last_tree_id, ok) fh.chunk_size = chunk_size fh end @@ -186,12 +195,7 @@ attr_accessor :socket, :client, :direct, :shares, :last_share def create_pipe(path, perm = 'c') disposition = UTILS.create_mode_to_disposition(perm) - ok = self.client.create_pipe(path, disposition) - file_id = if ok.respond_to? :guid - ok.guid.to_binary_s - elsif ok.respond_to? :fid - ok.fid.to_binary_s - end + file_id = self.client.create_pipe(path, disposition) fh = OpenPipe.new(self.client, path, self.client.last_tree_id, file_id) end diff --git a/lib/rex/proto/smb/simpleclient/open_file.rb b/lib/rex/proto/smb/simpleclient/open_file.rb index b9db28c35e..6c028ed1ab 100644 --- a/lib/rex/proto/smb/simpleclient/open_file.rb +++ b/lib/rex/proto/smb/simpleclient/open_file.rb @@ -32,32 +32,27 @@ class OpenFile def read(length = nil, offset = 0) if (length == nil) data = '' + max_size = self.client.open_files[self.client.last_file_id].size fptr = offset - ok = self.client.read(self.file_id, fptr, self.chunk_size) - while (ok and ok['Payload'].v['DataLenLow'] > 0) - buff = ok.to_s.slice( - ok['Payload'].v['DataOffset'] + 4, - ok['Payload'].v['DataLenLow'] - ) - data << buff - if ok['Payload'].v['Remaining'] == 0 - break - end - fptr += ok['Payload'].v['DataLenLow'] - begin - ok = self.client.read(self.file_id, fptr, self.chunk_size) - rescue XCEPT::ErrorCode => e - case e.error_code - when 0x00050001 - # Novell fires off an access denied error on EOF - ok = nil - else - raise e - end - end + if max_size < self.chunk_size + chunk = max_size + else + chunk = self.chunk_size end + ok = self.client.read(self.file_id, fptr, chunk) + data << ok.pack('C*') + fptr = data.length + + while (ok && data.length < max_size) + if (max_size - data.length) < chunk + chunk = max_size - data.length + end + ok = self.client.read(self.file_id, fptr, chunk) + data << ok.pack('C*') + fptr = data.length + end return data else ok = self.client.read(self.file_id, offset, length) diff --git a/modules/auxiliary/admin/smb/download_file.rb b/modules/auxiliary/admin/smb/download_file.rb index 6d7da1c769..ef9e4f66b5 100644 --- a/modules/auxiliary/admin/smb/download_file.rb +++ b/modules/auxiliary/admin/smb/download_file.rb @@ -51,7 +51,7 @@ class MetasploitModule < Msf::Auxiliary vprint_status("Trying to download #{remote_path}...") data = '' - fd = simple.open("\\#{remote_path}", 'ro') + fd = simple.open("#{remote_path}", 'o') begin data = fd.read ensure diff --git a/modules/auxiliary/admin/smb/upload_file.rb b/modules/auxiliary/admin/smb/upload_file.rb index 81a4d11971..9cef6538e5 100644 --- a/modules/auxiliary/admin/smb/upload_file.rb +++ b/modules/auxiliary/admin/smb/upload_file.rb @@ -63,7 +63,7 @@ class MetasploitModule < Msf::Auxiliary begin vprint_status("Trying to upload #{local_path} to #{remote_path}...") - fd = simple.open("\\#{remote_path}", 'rwct') + fd = simple.open("#{remote_path}", 's', write: true) data = ::File.read(datastore['LPATH'], ::File.size(datastore['LPATH'])) fd.write(data) fd.close