Skip to content

Commit

Permalink
use choice for AccessMasks
Browse files Browse the repository at this point in the history
use the BinData choice type to alternate
between DirectoryaccessMask and FileAccessMask
so we can use the appropriate one

MS-2655
  • Loading branch information
David Maloney authored and David Maloney committed Aug 10, 2017
1 parent f9d16b3 commit 08c9e58
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 10 deletions.
41 changes: 41 additions & 0 deletions examples/list_directory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/ruby

# This example script is used for testing directory listing functionality
# It will attempt to connect to a specific share and then list all files in a
# specified directory..
# Example usage: ruby list_directory.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE subdir1
# This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials,
# and then list the contents of the directory 'subdir1'

require 'bundler/setup'
require 'ruby_smb'

address = ARGV[0]
username = ARGV[1]
password = ARGV[2]
share = ARGV[3]
dir = ARGV[4]
path = "\\\\#{address}\\#{share}"

sock = TCPSocket.new address, 445
dispatcher = RubySMB::Dispatcher::Socket.new(sock)

client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
protocol = client.negotiate
status = client.authenticate

puts "#{protocol} : #{status}"

begin
tree = client.tree_connect(path)
puts "Connected to #{path} successfully!"
rescue Exception => e
puts "Failed to connect to #{path}: #{e.message}"
end

files = tree.list(directory: dir)

require 'pry'
binding.pry


7 changes: 6 additions & 1 deletion lib/ruby_smb/smb1/packet/nt_trans/create_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ class Trans2Parameters < BinData::Record
end

uint32 :root_directory_fid, label: 'Root Directory FID'
file_access_mask :desired_access

choice :desired_access, selection: lambda { ext_file_attribute.directory } do
file_access_mask 0, label: 'Desired Access'
directory_access_mask 1, label: 'Desired Access'
end

uint64 :allocation_size, label: 'Allocation Size'
smb_ext_file_attributes :ext_file_attribute
share_access :share_access, label: 'Share Access'
Expand Down
9 changes: 7 additions & 2 deletions lib/ruby_smb/smb2/packet/create_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ class CreateRequest < RubySMB::GenericPacket
uint32 :impersonation_level, label: 'Impersonation Level'
uint64 :create_flags, label: 'Create Flags(Do not use)', initial_value: 0
uint64 :reserved, label: 'Reserved', initial_value: 0
file_access_mask :desired_access, label: 'Desired Access'
file_attributes :file_attributes, label: 'File Attributes'

choice :desired_access, selection: lambda { file_attributes.directory } do
file_access_mask 0, label: 'Desired Access'
directory_access_mask 1, label: 'Desired Access'
end

file_attributes :file_attributes, label: 'File Attributes'

struct :share_access do
bit5 :reserved, label: 'Reserved Space'
Expand Down
46 changes: 43 additions & 3 deletions lib/ruby_smb/smb2/tree.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,54 @@ def initialize(client:, share:, response:)
# @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
def disconnect!
request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
request.smb2_header.tree_id = self.id
request.smb2_header.credit_charge = 1
request.smb2_header.credits = 256
request = set_header_fields(request)
raw_response = self.client.send_recv(request)
response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
response.status_code
end

# List `directory` on the remote share.
#
# @example
# tree = client.tree_connect("\\\\192.168.99.134\\Share")
# tree.list(directory: "path\\to\\directory")
#
# @param directory [String] path to the directory to be listed
# @param pattern [String] search pattern
# @param type [Class] file information class
# @return [Array] array of directory structures
def list(directory: nil, pattern: '*', type: RubySMB::Fscc::FileInformation::FileIdFullDirectoryInformation )
create_request = RubySMB::SMB2::Packet::CreateRequest.new
create_request = set_header_fields(create_request)

create_request.impersonation_level = RubySMB::ImpersonationLevels::SEC_IMPERSONATE
create_request.create_options.directory_file = 1
create_request.file_attributes.directory = 1
create_request.desired_access.list = 1
create_request.share_access.read_access = 1
create_request.create_disposition = RubySMB::Dispositions::FILE_OPEN



if directory.nil? || directory.empty?
create_request.name = "\x00"
create_request.length = 0
else
create_request.name = directory
end

raw_response = self.client.send_recv(create_request)
create_response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)

end


def set_header_fields(request)
request.smb2_header.tree_id = self.id
request.smb2_header.credit_charge = 1
request.smb2_header.credits = 256
request
end

end
end
Expand Down
12 changes: 10 additions & 2 deletions spec/lib/ruby_smb/smb1/packet/nt_trans/create_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,16 @@
it { is_expected.to respond_to :name }

describe '#desired_access' do
it 'is a File Access Mask' do
expect(parameters.desired_access).to be_a RubySMB::SMB1::BitField::FileAccessMask
it 'should be a DirectoryAccessMask when the file is a directory' do
parameters.ext_file_attribute.directory = 1
access_mask = parameters.desired_access.send(:current_choice)
expect(access_mask.class).to eq RubySMB::SMB1::BitField::DirectoryAccessMask
end

it 'should be a FileAccessMask when the file is not a directory' do
parameters.ext_file_attribute.directory = 0
access_mask = parameters.desired_access.send(:current_choice)
expect(access_mask.class).to eq RubySMB::SMB1::BitField::FileAccessMask
end
end

Expand Down
14 changes: 12 additions & 2 deletions spec/lib/ruby_smb/smb2/packet/create_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,18 @@
expect(packet.structure_size).to eq 57
end

it 'should have a File Access Mask for #desired_access' do
expect(packet.desired_access).to be_a RubySMB::SMB2::BitField::FileAccessMask
describe '#desired_access' do
it 'should be a DirectoryAccessMask when the file is a directory' do
packet.file_attributes.directory = 1
access_mask = packet.desired_access.send(:current_choice)
expect(access_mask.class).to eq RubySMB::SMB2::BitField::DirectoryAccessMask
end

it 'should be a FileAccessMask when the file is not a directory' do
packet.file_attributes.directory = 0
access_mask = packet.desired_access.send(:current_choice)
expect(access_mask.class).to eq RubySMB::SMB2::BitField::FileAccessMask
end
end

describe '#share_accesss' do
Expand Down

0 comments on commit 08c9e58

Please sign in to comment.