CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/lib/msf/util/dot_net_deserialization_spec.rb
Views: 11704
1
require 'rex'
2
3
RSpec.shared_examples 'a valid serialized stream' do |stream|
4
it 'should start with a SerializedStreamHeader record' do
5
expect(stream.records[0].record_type).to eq Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:SerializedStreamHeader]
6
end
7
8
it 'should end with a MessageEnd record' do
9
expect(stream.records[-1].record_type).to eq Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MessageEnd]
10
end
11
end
12
13
RSpec.describe Msf::Util::DotNetDeserialization do
14
describe '#generate' do
15
COMMAND = 'ping 127.0.0.1'
16
17
18
# this is a quick but important check to ensure consistency of the
19
# serialized payloads which are deterministic
20
{
21
:ClaimsPrincipal => '3f7232efeed59104840b199c5261e5769f4dc30a',
22
:DataSet => 'cc0ad32c20348282eab964c42caef34a52f8deb4',
23
:DataSetTypeSpoof => '2142f7810a10264b8d431648c5d0c555396a7635',
24
:TextFormattingRunProperties => '8aa639e141b325e8bf138d09380bdf7714f70c72',
25
:TypeConfuseDelegate => '97cf63717ea751f81c382bd178fdf56d0ec3edb1',
26
:WindowsIdentity => '8dab1805a165cabea8ce96a7721317096f072166'
27
}.each do |gadget_chain, correct_digest|
28
it "generates the correct data for: #{gadget_chain}" do
29
stream = Msf::Util::DotNetDeserialization.generate(COMMAND, gadget_chain: gadget_chain)
30
expect(stream).to be_kind_of String
31
real_digest = OpenSSL::Digest::SHA1.hexdigest(stream)
32
expect(real_digest).to eq correct_digest
33
end
34
end
35
36
Msf::Util::DotNetDeserialization.formatter_compatible_gadget_chains(:BinaryFormatter).each do |gadget_chain|
37
describe "parsed gadget chain: #{gadget_chain}" do
38
serialized = Msf::Util::DotNetDeserialization.generate(COMMAND, gadget_chain: gadget_chain, formatter: :BinaryFormatter)
39
stream = Msf::Util::DotNetDeserialization::Types::SerializedStream.read(serialized)
40
41
it_behaves_like 'a valid serialized stream', stream
42
43
it 'should be the same when serialized' do
44
expect(stream.to_binary_s).to eq serialized
45
end
46
end
47
end
48
end
49
50
describe '#generate_formatted' do
51
stream = Msf::Util::DotNetDeserialization.generate_gadget_chain(COMMAND, gadget_chain: :TextFormattingRunProperties)
52
53
it 'should raise a NotImplementedError for an unsupported formatter' do
54
expect {
55
Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :DoesNotExist)
56
}.to raise_error(NotImplementedError)
57
end
58
59
context 'when formatting using the BinaryFormatter it' do
60
formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :BinaryFormatter)
61
62
it 'should be a string' do
63
expect(formatted).to be_kind_of String
64
end
65
66
it_behaves_like 'a valid serialized stream', Msf::Util::DotNetDeserialization::Types::SerializedStream.read(formatted)
67
end
68
69
context 'when formatting using the LosFormatter it' do
70
formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :LosFormatter)
71
72
it 'should be a string' do
73
expect(formatted).to be_kind_of String
74
end
75
76
it 'should start with ObjectStateFormatter' do
77
osf = Msf::Util::DotNetDeserialization::Formatters::LosFormatter::ObjectStateFormatter.new
78
osf.read(formatted)
79
expect(osf.marker_format).to eq 0xff
80
expect(osf.marker_version).to eq 1
81
expect(osf.token).to eq 50 # Token_BinarySerialized
82
end
83
end
84
85
context 'when formatting using the SoapFormatter it' do
86
formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :SoapFormatter)
87
88
it 'should be a string' do
89
expect(formatted).to be_kind_of String
90
end
91
92
it 'should be valid XML' do
93
xml = Nokogiri::XML(formatted)
94
expect(xml.errors.select { |error| error.fatal? }.length).to eq 0
95
end
96
end
97
end
98
99
describe '#generate_gadget_chain' do
100
it 'should raise a NotImplementedError for an unsupported gadget chain' do
101
expect {
102
Msf::Util::DotNetDeserialization.generate_gadget_chain('command', gadget_chain: :DoesNotExist)
103
}.to raise_error(NotImplementedError)
104
end
105
106
context 'when generating a TextFormattingRunProperties it' do
107
gadget_chain = Msf::Util::DotNetDeserialization.generate_gadget_chain(
108
'command',
109
gadget_chain: :TextFormattingRunProperties
110
).to_binary_s
111
it 'should start with a SerializationHeaderRecord' do
112
record = Msf::Util::DotNetDeserialization::Types::Record.new
113
record.read(gadget_chain)
114
115
expect(record.record_type).to eq Msf::Util::DotNetDeserialization::Types::RecordValues::SerializationHeaderRecord::RECORD_TYPE
116
117
header = record.record_value
118
expect(header.major_version).to eq 1
119
expect(header.minor_version).to eq 0
120
expect(header.root_id).to eq 1
121
end
122
123
it 'should end with MessageEnd' do
124
message_end = Msf::Util::DotNetDeserialization::Types::Record.from_value(
125
Msf::Util::DotNetDeserialization::Types::RecordValues::MessageEnd.new
126
)
127
expect(gadget_chain.ends_with? message_end.to_binary_s).to be_truthy
128
end
129
end
130
end
131
132
describe 'Assemblies' do
133
Assemblies = Msf::Util::DotNetDeserialization::Assemblies
134
mscorlib = Assemblies::VERSIONS['4.0.0.0']['mscorlib']
135
describe 'StrongName' do
136
it 'should convert to a string correctly' do
137
expect("#{mscorlib}").to be_kind_of String
138
expect(mscorlib.to_s =~ /mscorlib, Version=\S+, Culture=\S+, PublicKeyToken=[a-f0-9]{16}/).to be_truthy
139
end
140
141
it 'should provide QualifiedName objects from key lookups' do
142
expect(mscorlib['System.String']).to be_kind_of Msf::Util::DotNetDeserialization::Assemblies::QualifiedName
143
end
144
end
145
end
146
147
describe 'Types::Primitives::EnumArray' do
148
EnumArray = Msf::Util::DotNetDeserialization::Types::Primitives::EnumArray
149
it 'accepts an array of symbols' do
150
ea = EnumArray.new(%i{ Boolean Byte Char }, enum: Msf::Util::DotNetDeserialization::Enums::PrimitiveTypeEnum)
151
expect(ea.length).to eq 3
152
expect(ea.to_binary_s).to eq "\x01\x02\x03"
153
end
154
155
it 'accepts an array of integers' do
156
ea = EnumArray.new([1, 2, 3], enum: Msf::Util::DotNetDeserialization::Enums::PrimitiveTypeEnum)
157
expect(ea.length).to eq 3
158
expect(ea.to_binary_s).to eq "\x01\x02\x03"
159
end
160
end
161
162
describe 'Types::Primitives::LengthPrefixedString' do
163
LengthPrefixedString = Msf::Util::DotNetDeserialization::Types::Primitives::LengthPrefixedString
164
165
it 'parses well-formed strings' do
166
lps = LengthPrefixedString.new
167
expect(lps.read("\x01A")).to eq "A"
168
expect(lps.read([0x80, 0x01].pack('C*') + ('A' * 0x80))).to eq ('A' * 0x80)
169
end
170
171
it 'generates well-formed strings' do
172
expect(LengthPrefixedString.new('A').to_binary_s).to eq "\x01A"
173
expect(LengthPrefixedString.new('A' * 0x80).to_binary_s).to eq [0x80, 0x01].pack('C*') + ('A' * 0x80)
174
end
175
end
176
177
describe 'Types::RecordValues::ClassWithMembersAndTypes' do
178
ClassWithMembersAndTypes = Msf::Util::DotNetDeserialization::Types::RecordValues::SystemClassWithMembersAndTypes
179
180
it 'raises an ArgumentError when there is a member count mismatch' do
181
expect {
182
ClassWithMembersAndTypes.from_member_values(
183
class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new,
184
member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new,
185
member_values: [ 1 ]
186
)
187
}.to raise_error(ArgumentError)
188
end
189
end
190
191
describe 'Types::RecordValues::SystemClassWithMembersAndTypes' do
192
SystemClassWithMembersAndTypes = Msf::Util::DotNetDeserialization::Types::RecordValues::SystemClassWithMembersAndTypes
193
194
it 'raises an ArgumentError when there is a member count mismatch' do
195
expect {
196
SystemClassWithMembersAndTypes.from_member_values(
197
class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new,
198
member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new,
199
member_values: [ 1 ]
200
)
201
}.to raise_error(ArgumentError)
202
end
203
end
204
205
describe 'Types::SerializedStream' do
206
SerializedStream = Msf::Util::DotNetDeserialization::Types::SerializedStream
207
208
it 'stops parsing a stream on EoF' do
209
stream = SerializedStream.new.read("")
210
expect(stream.records.length).to eq 0
211
end
212
213
it 'stops parsing a stream at a MessageEnd record' do
214
stream = SerializedStream.new.read("\x0b\xff")
215
expect(stream.records.length).to eq 1
216
end
217
218
it 'should raise a IndexError for an unsupported record type' do
219
expect{
220
SerializedStream.new.read("\xff")
221
}.to raise_error(IndexError)
222
end
223
224
describe '#get_object' do
225
it 'should fetch values with a primitive id argument' do
226
id = BinData::Int8.new(rand(0xff))
227
value = rand(0x1000)
228
stream = SerializedStream.new
229
stream.set_object(id, value)
230
expect(id).to be_kind_of BinData::BasePrimitive
231
expect(stream.get_object(id)).to eq value
232
expect(stream.get_object(id.value)).to eq value
233
end
234
end
235
end
236
end
237
238