Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/spec/lib/msf/util/dot_net_deserialization_spec.rb
Views: 11704
require 'rex'12RSpec.shared_examples 'a valid serialized stream' do |stream|3it 'should start with a SerializedStreamHeader record' do4expect(stream.records[0].record_type).to eq Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:SerializedStreamHeader]5end67it 'should end with a MessageEnd record' do8expect(stream.records[-1].record_type).to eq Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MessageEnd]9end10end1112RSpec.describe Msf::Util::DotNetDeserialization do13describe '#generate' do14COMMAND = 'ping 127.0.0.1'151617# this is a quick but important check to ensure consistency of the18# serialized payloads which are deterministic19{20:ClaimsPrincipal => '3f7232efeed59104840b199c5261e5769f4dc30a',21:DataSet => 'cc0ad32c20348282eab964c42caef34a52f8deb4',22:DataSetTypeSpoof => '2142f7810a10264b8d431648c5d0c555396a7635',23:TextFormattingRunProperties => '8aa639e141b325e8bf138d09380bdf7714f70c72',24:TypeConfuseDelegate => '97cf63717ea751f81c382bd178fdf56d0ec3edb1',25:WindowsIdentity => '8dab1805a165cabea8ce96a7721317096f072166'26}.each do |gadget_chain, correct_digest|27it "generates the correct data for: #{gadget_chain}" do28stream = Msf::Util::DotNetDeserialization.generate(COMMAND, gadget_chain: gadget_chain)29expect(stream).to be_kind_of String30real_digest = OpenSSL::Digest::SHA1.hexdigest(stream)31expect(real_digest).to eq correct_digest32end33end3435Msf::Util::DotNetDeserialization.formatter_compatible_gadget_chains(:BinaryFormatter).each do |gadget_chain|36describe "parsed gadget chain: #{gadget_chain}" do37serialized = Msf::Util::DotNetDeserialization.generate(COMMAND, gadget_chain: gadget_chain, formatter: :BinaryFormatter)38stream = Msf::Util::DotNetDeserialization::Types::SerializedStream.read(serialized)3940it_behaves_like 'a valid serialized stream', stream4142it 'should be the same when serialized' do43expect(stream.to_binary_s).to eq serialized44end45end46end47end4849describe '#generate_formatted' do50stream = Msf::Util::DotNetDeserialization.generate_gadget_chain(COMMAND, gadget_chain: :TextFormattingRunProperties)5152it 'should raise a NotImplementedError for an unsupported formatter' do53expect {54Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :DoesNotExist)55}.to raise_error(NotImplementedError)56end5758context 'when formatting using the BinaryFormatter it' do59formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :BinaryFormatter)6061it 'should be a string' do62expect(formatted).to be_kind_of String63end6465it_behaves_like 'a valid serialized stream', Msf::Util::DotNetDeserialization::Types::SerializedStream.read(formatted)66end6768context 'when formatting using the LosFormatter it' do69formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :LosFormatter)7071it 'should be a string' do72expect(formatted).to be_kind_of String73end7475it 'should start with ObjectStateFormatter' do76osf = Msf::Util::DotNetDeserialization::Formatters::LosFormatter::ObjectStateFormatter.new77osf.read(formatted)78expect(osf.marker_format).to eq 0xff79expect(osf.marker_version).to eq 180expect(osf.token).to eq 50 # Token_BinarySerialized81end82end8384context 'when formatting using the SoapFormatter it' do85formatted = Msf::Util::DotNetDeserialization.generate_formatted(stream, formatter: :SoapFormatter)8687it 'should be a string' do88expect(formatted).to be_kind_of String89end9091it 'should be valid XML' do92xml = Nokogiri::XML(formatted)93expect(xml.errors.select { |error| error.fatal? }.length).to eq 094end95end96end9798describe '#generate_gadget_chain' do99it 'should raise a NotImplementedError for an unsupported gadget chain' do100expect {101Msf::Util::DotNetDeserialization.generate_gadget_chain('command', gadget_chain: :DoesNotExist)102}.to raise_error(NotImplementedError)103end104105context 'when generating a TextFormattingRunProperties it' do106gadget_chain = Msf::Util::DotNetDeserialization.generate_gadget_chain(107'command',108gadget_chain: :TextFormattingRunProperties109).to_binary_s110it 'should start with a SerializationHeaderRecord' do111record = Msf::Util::DotNetDeserialization::Types::Record.new112record.read(gadget_chain)113114expect(record.record_type).to eq Msf::Util::DotNetDeserialization::Types::RecordValues::SerializationHeaderRecord::RECORD_TYPE115116header = record.record_value117expect(header.major_version).to eq 1118expect(header.minor_version).to eq 0119expect(header.root_id).to eq 1120end121122it 'should end with MessageEnd' do123message_end = Msf::Util::DotNetDeserialization::Types::Record.from_value(124Msf::Util::DotNetDeserialization::Types::RecordValues::MessageEnd.new125)126expect(gadget_chain.ends_with? message_end.to_binary_s).to be_truthy127end128end129end130131describe 'Assemblies' do132Assemblies = Msf::Util::DotNetDeserialization::Assemblies133mscorlib = Assemblies::VERSIONS['4.0.0.0']['mscorlib']134describe 'StrongName' do135it 'should convert to a string correctly' do136expect("#{mscorlib}").to be_kind_of String137expect(mscorlib.to_s =~ /mscorlib, Version=\S+, Culture=\S+, PublicKeyToken=[a-f0-9]{16}/).to be_truthy138end139140it 'should provide QualifiedName objects from key lookups' do141expect(mscorlib['System.String']).to be_kind_of Msf::Util::DotNetDeserialization::Assemblies::QualifiedName142end143end144end145146describe 'Types::Primitives::EnumArray' do147EnumArray = Msf::Util::DotNetDeserialization::Types::Primitives::EnumArray148it 'accepts an array of symbols' do149ea = EnumArray.new(%i{ Boolean Byte Char }, enum: Msf::Util::DotNetDeserialization::Enums::PrimitiveTypeEnum)150expect(ea.length).to eq 3151expect(ea.to_binary_s).to eq "\x01\x02\x03"152end153154it 'accepts an array of integers' do155ea = EnumArray.new([1, 2, 3], enum: Msf::Util::DotNetDeserialization::Enums::PrimitiveTypeEnum)156expect(ea.length).to eq 3157expect(ea.to_binary_s).to eq "\x01\x02\x03"158end159end160161describe 'Types::Primitives::LengthPrefixedString' do162LengthPrefixedString = Msf::Util::DotNetDeserialization::Types::Primitives::LengthPrefixedString163164it 'parses well-formed strings' do165lps = LengthPrefixedString.new166expect(lps.read("\x01A")).to eq "A"167expect(lps.read([0x80, 0x01].pack('C*') + ('A' * 0x80))).to eq ('A' * 0x80)168end169170it 'generates well-formed strings' do171expect(LengthPrefixedString.new('A').to_binary_s).to eq "\x01A"172expect(LengthPrefixedString.new('A' * 0x80).to_binary_s).to eq [0x80, 0x01].pack('C*') + ('A' * 0x80)173end174end175176describe 'Types::RecordValues::ClassWithMembersAndTypes' do177ClassWithMembersAndTypes = Msf::Util::DotNetDeserialization::Types::RecordValues::SystemClassWithMembersAndTypes178179it 'raises an ArgumentError when there is a member count mismatch' do180expect {181ClassWithMembersAndTypes.from_member_values(182class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new,183member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new,184member_values: [ 1 ]185)186}.to raise_error(ArgumentError)187end188end189190describe 'Types::RecordValues::SystemClassWithMembersAndTypes' do191SystemClassWithMembersAndTypes = Msf::Util::DotNetDeserialization::Types::RecordValues::SystemClassWithMembersAndTypes192193it 'raises an ArgumentError when there is a member count mismatch' do194expect {195SystemClassWithMembersAndTypes.from_member_values(196class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new,197member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new,198member_values: [ 1 ]199)200}.to raise_error(ArgumentError)201end202end203204describe 'Types::SerializedStream' do205SerializedStream = Msf::Util::DotNetDeserialization::Types::SerializedStream206207it 'stops parsing a stream on EoF' do208stream = SerializedStream.new.read("")209expect(stream.records.length).to eq 0210end211212it 'stops parsing a stream at a MessageEnd record' do213stream = SerializedStream.new.read("\x0b\xff")214expect(stream.records.length).to eq 1215end216217it 'should raise a IndexError for an unsupported record type' do218expect{219SerializedStream.new.read("\xff")220}.to raise_error(IndexError)221end222223describe '#get_object' do224it 'should fetch values with a primitive id argument' do225id = BinData::Int8.new(rand(0xff))226value = rand(0x1000)227stream = SerializedStream.new228stream.set_object(id, value)229expect(id).to be_kind_of BinData::BasePrimitive230expect(stream.get_object(id)).to eq value231expect(stream.get_object(id.value)).to eq value232end233end234end235end236237238