ruby_smb 3.2.3 → 3.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/examples/dump_secrets_from_sid.rb +1 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +118 -0
- data/lib/ruby_smb/dcerpc/samr.rb +2 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +198 -0
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f850321711ac70e25f6b483f82454520f2b567cc349ee02eb99bba5c48dfeb4
|
4
|
+
data.tar.gz: 22ee0ab297710e76071fa8302165b903b39d211205ca1d6b95d697bf3eecae67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8708897bda47dd2c07b064eaafbbfe8641af469a1b5688a98bbef9e38119675de9ce52287fdb00c75f908e29e70499d14203fc53a11c6824691c315a5ebeb746
|
7
|
+
data.tar.gz: aad169c776223bb67198ba223f0b53d640706540f67ec125d4527a05fa4ac8c42676588b84f5e0385c4db846631783159c2a44801964284b6ae0b78b83c0a031
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/ruby_smb/dcerpc/ndr.rb
CHANGED
@@ -1315,5 +1315,123 @@ module RubySMB::Dcerpc::Ndr
|
|
1315
1315
|
end
|
1316
1316
|
end
|
1317
1317
|
|
1318
|
+
# (IDL/NDR) Pickles as defined in
|
1319
|
+
# [(IDL/NDR) # Pickles](https://pubs.opengroup.org/onlinepubs/9668899/chap2.htm#tagcjh_05_01_07)
|
1320
|
+
# and
|
1321
|
+
# [2.2.6 Type Serialization Version # 1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/9a1d0f97-eac0-49ab-a197-f1a581c2d6a0)
|
1322
|
+
|
1323
|
+
# [2.2.6.1 Common Type Header for the Serialization Stream](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/6d75d40e-e2d2-4420-b9e9-8508a726a9ae)
|
1324
|
+
class TypeSerialization1CommonTypeHeader < BinData::Record
|
1325
|
+
default_parameter byte_align: 8
|
1326
|
+
endian :little
|
1327
|
+
|
1328
|
+
uint8 :version, initial_value: 1
|
1329
|
+
uint8 :endianness, initial_value: 0x10
|
1330
|
+
uint16 :common_header_length, initial_value: 8
|
1331
|
+
uint32 :filler, initial_value: 0xCCCCCCCC
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
# [2.2.6.2 Private Header for Constructed Type](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/63949ba8-bc88-4c0c-9377-23f14b197827)
|
1335
|
+
class TypeSerialization1PrivateHeader < BinData::Record
|
1336
|
+
default_parameter byte_align: 8
|
1337
|
+
endian :little
|
1338
|
+
|
1339
|
+
uint32 :object_buffer_length, initial_value: -> { buffer_length(@obj) }
|
1340
|
+
uint32 :filler, initial_value: 0x00000000
|
1341
|
+
|
1342
|
+
def buffer_length(obj)
|
1343
|
+
parent.respond_to?(:field_length) ? parent.field_length(obj.parent) : 0
|
1344
|
+
end
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
# [2.2.6 Type Serialization Version 1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/9a1d0f97-eac0-49ab-a197-f1a581c2d6a0)
|
1348
|
+
#
|
1349
|
+
# This structure is not meant to be instantiated directly. Instead, the
|
1350
|
+
# structure with the fields to be serialized needs to inherit from
|
1351
|
+
# TypeSerialization1. This class will take care of adding the
|
1352
|
+
# TypeSerialization1PrivateHeader fields in front of any NDR constructed type
|
1353
|
+
# structures and setting the buffer length field (:object_buffer_length) to
|
1354
|
+
# the correct value.
|
1355
|
+
#
|
1356
|
+
# Example:
|
1357
|
+
#
|
1358
|
+
# class TestStruct < RubySMB::Dcerpc::Ndr::NdrStruct
|
1359
|
+
# default_parameters byte_align: 8
|
1360
|
+
# endian :little
|
1361
|
+
|
1362
|
+
# rpc_unicode_string :full_name
|
1363
|
+
# ndr_uint32 :user_id
|
1364
|
+
# end
|
1365
|
+
|
1366
|
+
# class TestTypeSerialization1 < RubySMB::Dcerpc::Ndr::TypeSerialization1
|
1367
|
+
# default_parameter byte_align: 8
|
1368
|
+
# endian :little
|
1369
|
+
#
|
1370
|
+
# test_struct :data1
|
1371
|
+
# uint32 :value1, initial_value: 5
|
1372
|
+
# uint32 :value2, initial_value: 6
|
1373
|
+
# test_struct :data2
|
1374
|
+
# uint32 :value3, initial_value: 7
|
1375
|
+
# test_struct :data3
|
1376
|
+
# end
|
1377
|
+
#
|
1378
|
+
# This will result in the following structure:
|
1379
|
+
# {
|
1380
|
+
# :common_header => {:version=>1, :endianness=>16, :common_header_length=>8, :filler=>3435973836},
|
1381
|
+
# :private_header1 => {:object_buffer_length=>12, :filler=>0},
|
1382
|
+
# :data1 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0},
|
1383
|
+
# :value1 => 5,
|
1384
|
+
# :value2 => 6,
|
1385
|
+
# :private_header2 => {:object_buffer_length=>12, :filler=>0},
|
1386
|
+
# :data2 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0},
|
1387
|
+
# :value3 => 7,
|
1388
|
+
# :private_header3 => {:object_buffer_length=>12, :filler=>0},
|
1389
|
+
# :data3 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0}
|
1390
|
+
# }
|
1391
|
+
#
|
1392
|
+
class TypeSerialization1 < BinData::Record
|
1393
|
+
PRIVATE_HEADER_BASE_NAME = 'private_header'.freeze
|
1394
|
+
|
1395
|
+
default_parameter byte_align: 8
|
1396
|
+
endian :little
|
1397
|
+
search_prefix :type_serialization1
|
1398
|
+
|
1399
|
+
common_type_header :common_header
|
1400
|
+
|
1401
|
+
def field_length(obj)
|
1402
|
+
length = 0
|
1403
|
+
index = find_index_of(obj)
|
1404
|
+
if index
|
1405
|
+
each_pair {|n, o| length = o.num_bytes if n == field_names[index + 1]}
|
1406
|
+
end
|
1407
|
+
length
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
def self.method_missing(symbol, *args, &block)
|
1411
|
+
return super if dsl_parser.respond_to?(symbol)
|
1412
|
+
|
1413
|
+
klass = BinData::RegisteredClasses.lookup(symbol, {endian: dsl_parser.endian, search_prefix: dsl_parser.search_prefix})
|
1414
|
+
if klass.new.is_a?(ConstructedTypePlugin)
|
1415
|
+
# We cannot have two fields with the same name. So, here we look for
|
1416
|
+
# existing TypeSerialization1PrivateHeader fields and just increment
|
1417
|
+
# the ending number of the last TypeSerialization1PrivateHeader field
|
1418
|
+
# to make the new name unique.
|
1419
|
+
names = dsl_parser.fields.find_all do |field|
|
1420
|
+
field.prototype.instance_variable_get(:@obj_class) == TypeSerialization1PrivateHeader
|
1421
|
+
end.map(&:name).sort
|
1422
|
+
if names.empty?
|
1423
|
+
new_name = "#{PRIVATE_HEADER_BASE_NAME}1"
|
1424
|
+
else
|
1425
|
+
num = names.last.match(/#{PRIVATE_HEADER_BASE_NAME}(\d)$/)[1].to_i
|
1426
|
+
new_name = "#{PRIVATE_HEADER_BASE_NAME}#{num + 1}"
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
super(:private_header, new_name.to_sym)
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
super
|
1433
|
+
end
|
1434
|
+
end
|
1435
|
+
|
1318
1436
|
end
|
1319
1437
|
|
data/lib/ruby_smb/dcerpc/samr.rb
CHANGED
@@ -259,6 +259,8 @@ module RubySMB
|
|
259
259
|
3 => 'des-cbc-md5',
|
260
260
|
17 => 'aes128-cts-hmac-sha1-96',
|
261
261
|
18 => 'aes256-cts-hmac-sha1-96',
|
262
|
+
# Windows Server 2008 and later DC includes a KeyType of -140. Not present when the domain functional level is raised to DS_BEHAVIOR_WIN2008 or greater
|
263
|
+
# [Appendix_A_24](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/fa61e5fc-f8fb-4d5b-9695-c724af0c3829#Appendix_A_24)
|
262
264
|
0xffffff74 => 'rc4_hmac'
|
263
265
|
}
|
264
266
|
|
data/lib/ruby_smb/version.rb
CHANGED
@@ -4146,3 +4146,201 @@ RSpec.describe 'Alignment' do
|
|
4146
4146
|
end
|
4147
4147
|
end
|
4148
4148
|
end
|
4149
|
+
|
4150
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::TypeSerialization1CommonTypeHeader do
|
4151
|
+
it 'is a BinData::Record class' do
|
4152
|
+
expect(described_class).to be < BinData::Record
|
4153
|
+
end
|
4154
|
+
it 'has :byte_align parameter set to the expected value' do
|
4155
|
+
expect(described_class.default_parameters[:byte_align]).to eq(8)
|
4156
|
+
end
|
4157
|
+
|
4158
|
+
subject { described_class.new }
|
4159
|
+
|
4160
|
+
it { is_expected.to respond_to :version }
|
4161
|
+
it { is_expected.to respond_to :endianness }
|
4162
|
+
it { is_expected.to respond_to :common_header_length }
|
4163
|
+
it { is_expected.to respond_to :filler }
|
4164
|
+
|
4165
|
+
context 'with #version' do
|
4166
|
+
it 'is a BinData::Uint8' do
|
4167
|
+
expect(subject.version).to be_a BinData::Uint8
|
4168
|
+
end
|
4169
|
+
it 'returns 1 by default' do
|
4170
|
+
expect(subject.version).to eq(1)
|
4171
|
+
end
|
4172
|
+
end
|
4173
|
+
|
4174
|
+
context 'with #endianness' do
|
4175
|
+
it 'is a BinData::Uint8' do
|
4176
|
+
expect(subject.endianness).to be_a BinData::Uint8
|
4177
|
+
end
|
4178
|
+
it 'returns 0x10 by default' do
|
4179
|
+
expect(subject.endianness).to eq(0x10)
|
4180
|
+
end
|
4181
|
+
end
|
4182
|
+
|
4183
|
+
context 'with #common_header_length' do
|
4184
|
+
it 'is a BinData::Uint16le' do
|
4185
|
+
expect(subject.common_header_length).to be_a BinData::Uint16le
|
4186
|
+
end
|
4187
|
+
it 'returns 8 by default' do
|
4188
|
+
expect(subject.common_header_length).to eq(8)
|
4189
|
+
end
|
4190
|
+
end
|
4191
|
+
|
4192
|
+
context 'with #filler' do
|
4193
|
+
it 'is a BinData::Uint32le' do
|
4194
|
+
expect(subject.filler).to be_a BinData::Uint32le
|
4195
|
+
end
|
4196
|
+
it 'returns 0xCCCCCCCC by default' do
|
4197
|
+
expect(subject.filler).to eq(0xCCCCCCCC)
|
4198
|
+
end
|
4199
|
+
end
|
4200
|
+
|
4201
|
+
it 'reads itself' do
|
4202
|
+
values = {version: 4, endianness: 0x33, common_header_length: 44, filler: 0xFFFFFFFF}
|
4203
|
+
struct_instance = described_class.new(values)
|
4204
|
+
expect(described_class.read(struct_instance.to_binary_s)).to eq(values)
|
4205
|
+
end
|
4206
|
+
end
|
4207
|
+
|
4208
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::TypeSerialization1PrivateHeader do
|
4209
|
+
it 'is a BinData::Record class' do
|
4210
|
+
expect(described_class).to be < BinData::Record
|
4211
|
+
end
|
4212
|
+
it 'has :byte_align parameter set to the expected value' do
|
4213
|
+
expect(described_class.default_parameters[:byte_align]).to eq(8)
|
4214
|
+
end
|
4215
|
+
|
4216
|
+
subject { described_class.new }
|
4217
|
+
|
4218
|
+
it { is_expected.to respond_to :object_buffer_length }
|
4219
|
+
it { is_expected.to respond_to :filler }
|
4220
|
+
|
4221
|
+
context 'with #object_buffer_length' do
|
4222
|
+
it 'is a BinData::Uint32le' do
|
4223
|
+
expect(subject.object_buffer_length).to be_a BinData::Uint32le
|
4224
|
+
end
|
4225
|
+
it 'calls its parent\'s #field_length method to set its default value' do
|
4226
|
+
test_struct = Class.new(BinData::Record) do
|
4227
|
+
endian :little
|
4228
|
+
type_serialization1_private_header :header
|
4229
|
+
|
4230
|
+
def field_length(obj);end
|
4231
|
+
end.new
|
4232
|
+
expect(test_struct).to receive(:field_length).and_return(4)
|
4233
|
+
expect(test_struct.header.object_buffer_length).to eq(4)
|
4234
|
+
end
|
4235
|
+
it 'sets the default value to 0 when its parent doesn\'t implemet #field_length' do
|
4236
|
+
expect(subject.object_buffer_length).to eq(0)
|
4237
|
+
end
|
4238
|
+
end
|
4239
|
+
|
4240
|
+
context 'with #filler' do
|
4241
|
+
it 'is a BinData::Uint32le' do
|
4242
|
+
expect(subject.filler).to be_a BinData::Uint32le
|
4243
|
+
end
|
4244
|
+
it 'returns 0x00000000 by default' do
|
4245
|
+
expect(subject.filler).to eq(0x00000000)
|
4246
|
+
end
|
4247
|
+
end
|
4248
|
+
|
4249
|
+
it 'reads itself' do
|
4250
|
+
values = {object_buffer_length: 4, filler: 0xFFFFFFFF}
|
4251
|
+
struct_instance = described_class.new(values)
|
4252
|
+
expect(described_class.read(struct_instance.to_binary_s)).to eq(values)
|
4253
|
+
end
|
4254
|
+
end
|
4255
|
+
|
4256
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::TypeSerialization1 do
|
4257
|
+
it 'is a BinData::Record class' do
|
4258
|
+
expect(described_class).to be < BinData::Record
|
4259
|
+
end
|
4260
|
+
it 'has :byte_align parameter set to the expected value' do
|
4261
|
+
expect(described_class.default_parameters[:byte_align]).to eq(8)
|
4262
|
+
end
|
4263
|
+
|
4264
|
+
subject { described_class.new }
|
4265
|
+
|
4266
|
+
it { is_expected.to respond_to :common_header }
|
4267
|
+
|
4268
|
+
context 'with #common_header' do
|
4269
|
+
it 'is a TypeSerialization1CommonTypeHeader structure' do
|
4270
|
+
expect(subject.common_header).to be_a RubySMB::Dcerpc::Ndr::TypeSerialization1CommonTypeHeader
|
4271
|
+
end
|
4272
|
+
end
|
4273
|
+
|
4274
|
+
it 'reads itself' do
|
4275
|
+
values = {
|
4276
|
+
common_header: {version: 4, endianness: 0x33, common_header_length: 44, filler: 0xFFFFFFFF}
|
4277
|
+
}
|
4278
|
+
struct_instance = described_class.new(values)
|
4279
|
+
expect(described_class.read(struct_instance.to_binary_s)).to eq(values)
|
4280
|
+
end
|
4281
|
+
|
4282
|
+
context 'when inherited' do
|
4283
|
+
let(:test_struct) do
|
4284
|
+
Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
4285
|
+
default_parameters byte_align: 8
|
4286
|
+
endian :little
|
4287
|
+
|
4288
|
+
rpc_unicode_string :full_name
|
4289
|
+
ndr_uint32 :user_id
|
4290
|
+
end
|
4291
|
+
end
|
4292
|
+
before :example do
|
4293
|
+
BinData::RegisteredClasses.register('test_struct', test_struct)
|
4294
|
+
end
|
4295
|
+
after :example do
|
4296
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
4297
|
+
end
|
4298
|
+
|
4299
|
+
subject do
|
4300
|
+
Class.new(described_class) do
|
4301
|
+
default_parameter byte_align: 8
|
4302
|
+
endian :little
|
4303
|
+
|
4304
|
+
test_struct :data1
|
4305
|
+
uint32 :value1, initial_value: 5
|
4306
|
+
uint32 :value2, initial_value: 6
|
4307
|
+
test_struct :data2
|
4308
|
+
uint32 :value3, initial_value: 7
|
4309
|
+
test_struct :data3
|
4310
|
+
end.new
|
4311
|
+
end
|
4312
|
+
|
4313
|
+
it { is_expected.to respond_to :common_header }
|
4314
|
+
it { is_expected.to respond_to :private_header1 }
|
4315
|
+
it { is_expected.to respond_to :data1 }
|
4316
|
+
it { is_expected.to respond_to :value1 }
|
4317
|
+
it { is_expected.to respond_to :value2 }
|
4318
|
+
it { is_expected.to respond_to :private_header2 }
|
4319
|
+
it { is_expected.to respond_to :data2 }
|
4320
|
+
it { is_expected.to respond_to :value3 }
|
4321
|
+
it { is_expected.to respond_to :private_header3 }
|
4322
|
+
it { is_expected.to respond_to :data3 }
|
4323
|
+
|
4324
|
+
it 'sets the expected default values' do
|
4325
|
+
data_obj = test_struct.new
|
4326
|
+
expect(subject.data1).to eq(data_obj)
|
4327
|
+
expect(subject.value1).to eq(5)
|
4328
|
+
expect(subject.value2).to eq(6)
|
4329
|
+
expect(subject.data2).to eq(data_obj)
|
4330
|
+
expect(subject.value3).to eq(7)
|
4331
|
+
expect(subject.data3).to eq(data_obj)
|
4332
|
+
end
|
4333
|
+
|
4334
|
+
it 'sets the correct private header\'s object_buffer_length field value' do
|
4335
|
+
data1 = test_struct.new(full_name: 'test string')
|
4336
|
+
subject.data1 = data1
|
4337
|
+
expect(subject.private_header1.object_buffer_length).to eq(data1.num_bytes)
|
4338
|
+
data2 = test_struct.new(full_name: 'another test string')
|
4339
|
+
subject.data2 = data2
|
4340
|
+
expect(subject.private_header2.object_buffer_length).to eq(data2.num_bytes)
|
4341
|
+
data3 = test_struct.new(full_name: 'more string!!!')
|
4342
|
+
subject.data3 = data3
|
4343
|
+
expect(subject.private_header3.object_buffer_length).to eq(data3.num_bytes)
|
4344
|
+
end
|
4345
|
+
end
|
4346
|
+
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_smb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -97,7 +97,7 @@ cert_chain:
|
|
97
97
|
EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
|
98
98
|
9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
|
99
99
|
-----END CERTIFICATE-----
|
100
|
-
date: 2023-01-
|
100
|
+
date: 2023-01-30 00:00:00.000000000 Z
|
101
101
|
dependencies:
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: redcarpet
|
metadata.gz.sig
CHANGED
Binary file
|