Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions lib/ruby_smb/field/security_descriptor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,33 @@ class SecurityDescriptor < BinData::Record
uint8 :revision, label: 'Revision', initial_value: 0x01
uint8 :sbz1, label: 'Resource Manager Control Bits'

# The Control field is an unsigned 16-bit value transmitted little-endian.
# MS-DTYP 2.4.6 numbers the bits most-significant-first, so the low byte
# (read first) carries SS..OD and the high byte (read second) carries
# SR..DC. The bit1 fields are therefore declared most-significant-first
# within each byte: low byte first, then high byte. This keeps each flag
# mapped to the bit value defined by MS-DTYP (for example SR/self_relative
# is 0x8000 and DP/dacl_present is 0x0004).
struct :control do
endian :little
bit1 :dacl_computed_inheritance, label: 'DACL Computed Inheritance'
bit1 :sacl_computed_inheritance, label: 'SACL Computed Inheritance'
bit1 :dacl_auto_inherited, label: 'DACL Auto-Inherited'
bit1 :sacl_auto_inherited, label: 'SACL Auto-Inherited'
bit1 :dacl_protected, label: 'DACL Protected'
bit1 :sacl_protected, label: 'SACL Protected'
bit1 :rm_control_valid, label: 'RM Control Valid'
bit1 :self_relative, label: 'Self-Relative Format', initial_value: 0x01
# Byte Boundary
bit1 :owner_defaulted, label: 'Owner Defaulted'
bit1 :group_defaulted, label: 'Group Defaulted'
bit1 :dacl_present, label: 'DACL Present'
bit1 :dacl_defaulted, label: 'DACL Defaulted'
bit1 :sacl_present, label: 'SACL Present'
bit1 :sacl_defaulted, label: 'SACL Defaulted'
bit1 :server_security, label: 'Server Security'
bit1 :dacl_trusted, label: 'DACL Trusted'
# Low byte (first byte read), most-significant bit first.
bit1 :server_security, label: 'Server Security' # 0x0080
bit1 :dacl_trusted, label: 'DACL Trusted' # 0x0040
bit1 :sacl_defaulted, label: 'SACL Defaulted' # 0x0020
bit1 :sacl_present, label: 'SACL Present' # 0x0010
bit1 :dacl_defaulted, label: 'DACL Defaulted' # 0x0008
bit1 :dacl_present, label: 'DACL Present' # 0x0004
bit1 :group_defaulted, label: 'Group Defaulted' # 0x0002
bit1 :owner_defaulted, label: 'Owner Defaulted' # 0x0001
# High byte (second byte read), most-significant bit first.
bit1 :self_relative, label: 'Self-Relative Format', initial_value: 0x01 # 0x8000
bit1 :rm_control_valid, label: 'RM Control Valid' # 0x4000
bit1 :sacl_protected, label: 'SACL Protected' # 0x2000
bit1 :dacl_protected, label: 'DACL Protected' # 0x1000
bit1 :sacl_auto_inherited, label: 'SACL Auto-Inherited' # 0x0800
bit1 :dacl_auto_inherited, label: 'DACL Auto-Inherited' # 0x0400
bit1 :sacl_computed_inheritance, label: 'SACL Computed Inheritance' # 0x0200
bit1 :dacl_computed_inheritance, label: 'DACL Computed Inheritance' # 0x0100
end

uint32 :offset_owner, label: 'Offset Owner', initial_value: -> { owner_sid.rel_offset }
Expand Down
71 changes: 55 additions & 16 deletions spec/lib/ruby_smb/field/security_descriptor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,45 @@
expect(descriptor.offset_dacl).to eq descriptor.dacl.rel_offset
end

# Regression for rapid7/ruby_smb#289: a self-relative security descriptor
# returned by the server (Control word 0x9404, little-endian bytes
# "\x04\x94") was parsed with dacl_present and self_relative cleared because
# the Control bit1 fields did not follow the MS-DTYP 2.4.6 bit numbering.
describe 'parsing a self-relative descriptor (issue #289)' do
let(:byte_stream) do
[
0x01, # Revision
0x00, # Sbz1
0x04, 0x94, # Control = 0x9404 (LE): SR + PD + DI + DP
0x8c, 0x00, 0x00, 0x00, # OffsetOwner
0x9c, 0x00, 0x00, 0x00, # OffsetGroup
0x00, 0x00, 0x00, 0x00, # OffsetSacl
0x14, 0x00, 0x00, 0x00 # OffsetDacl
].pack('C*')
end

subject(:control) { described_class.read(byte_stream).control }

it 'reports the DACL as present' do
expect(control.dacl_present).to eq 1
end

it 'reports the descriptor as self-relative' do
expect(control.self_relative).to eq 1
end

it 'sets exactly the SR, PD, DI and DP flags' do
set_flags = control.field_names.select { |name| control.send(name) == 1 }
expect(set_flags).to contain_exactly(
:self_relative, :dacl_protected, :dacl_auto_inherited, :dacl_present
)
end

it 'reads the DACL offset' do
expect(described_class.read(byte_stream).offset_dacl).to eq 20
end
end

describe '#control' do
subject(:control) { descriptor.control }

Expand All @@ -67,127 +106,127 @@
expect(control.self_relative).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :self_relative, 'v', 0x0001
it_behaves_like 'bit field with one flag set', :self_relative, 'v', 0x8000
end

describe '#rm_control_valid' do
it 'is a 1-bit flag' do
expect(control.rm_control_valid).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :rm_control_valid, 'v', 0x0002
it_behaves_like 'bit field with one flag set', :rm_control_valid, 'v', 0x4000
end

describe '#sacl_protected' do
it 'is a 1-bit flag' do
expect(control.sacl_protected).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :sacl_protected, 'v', 0x0004
it_behaves_like 'bit field with one flag set', :sacl_protected, 'v', 0x2000
end

describe '#dacl_protected' do
it 'is a 1-bit flag' do
expect(control.dacl_protected).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_protected, 'v', 0x0008
it_behaves_like 'bit field with one flag set', :dacl_protected, 'v', 0x1000
end

describe '#sacl_auto_inherited' do
it 'is a 1-bit flag' do
expect(control.sacl_auto_inherited).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :sacl_auto_inherited, 'v', 0x0010
it_behaves_like 'bit field with one flag set', :sacl_auto_inherited, 'v', 0x0800
end

describe '#dacl_auto_inherited' do
it 'is a 1-bit flag' do
expect(control.dacl_auto_inherited).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_auto_inherited, 'v', 0x0020
it_behaves_like 'bit field with one flag set', :dacl_auto_inherited, 'v', 0x0400
end

describe '#sacl_computed_inheritance' do
it 'is a 1-bit flag' do
expect(control.sacl_computed_inheritance).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :sacl_computed_inheritance, 'v', 0x0040
it_behaves_like 'bit field with one flag set', :sacl_computed_inheritance, 'v', 0x0200
end

describe '#dacl_computed_inheritance' do
it 'is a 1-bit flag' do
expect(control.dacl_computed_inheritance).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_computed_inheritance, 'v', 0x0080
it_behaves_like 'bit field with one flag set', :dacl_computed_inheritance, 'v', 0x0100
end

describe '#dacl_trusted' do
it 'is a 1-bit flag' do
expect(control.dacl_trusted).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_trusted, 'v', 0x0100
it_behaves_like 'bit field with one flag set', :dacl_trusted, 'v', 0x0040
end

describe '#server_security' do
it 'is a 1-bit flag' do
expect(control.server_security).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :server_security, 'v', 0x0200
it_behaves_like 'bit field with one flag set', :server_security, 'v', 0x0080
end

describe '#sacl_defaulted' do
it 'is a 1-bit flag' do
expect(control.sacl_defaulted).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :sacl_defaulted, 'v', 0x0400
it_behaves_like 'bit field with one flag set', :sacl_defaulted, 'v', 0x0020
end

describe '#sacl_present' do
it 'is a 1-bit flag' do
expect(control.sacl_present).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :sacl_present, 'v', 0x0800
it_behaves_like 'bit field with one flag set', :sacl_present, 'v', 0x0010
end

describe '#dacl_defaulted' do
it 'is a 1-bit flag' do
expect(control.dacl_defaulted).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_defaulted, 'v', 0x1000
it_behaves_like 'bit field with one flag set', :dacl_defaulted, 'v', 0x0008
end

describe '#dacl_present' do
it 'is a 1-bit flag' do
expect(control.dacl_present).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :dacl_present, 'v', 0x2000
it_behaves_like 'bit field with one flag set', :dacl_present, 'v', 0x0004
end

describe '#group_defaulted' do
it 'is a 1-bit flag' do
expect(control.group_defaulted).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :group_defaulted, 'v', 0x4000
it_behaves_like 'bit field with one flag set', :group_defaulted, 'v', 0x0002
end

describe '#owner_defaulted' do
it 'is a 1-bit flag' do
expect(control.owner_defaulted).to be_a BinData::Bit1
end

it_behaves_like 'bit field with one flag set', :owner_defaulted, 'v', 0x8000
it_behaves_like 'bit field with one flag set', :owner_defaulted, 'v', 0x0001
end
end
end