Module: Msf::Exploit::Remote::HTTP::Exchange
- Includes:
- Msf::Exploit::Remote::HttpClient
- Defined in:
- lib/msf/core/exploit/remote/http/exchange.rb
Overview
This module provides a way of interacting with Exchange installations
Defined Under Namespace
Modules: ProxyMaybeShell
Instance Attribute Summary
Attributes included from Msf::Exploit::Remote::HttpClient
Instance Method Summary collapse
-
#exchange_get_version(exchange_builds: nil) ⇒ Rex::Version?
Get the Exchange version number.
-
#get_exchange_builds ⇒ Array
Build the array of Exchange Servers using the JSON file at data/exchange_versions.json.
-
#target_running_exchange? ⇒ Boolean
Determine if the target is running Exchange Server or not.
Methods included from Msf::Exploit::Remote::HttpClient
#basic_auth, #cleanup, #configure_http_login_scanner, #connect, #connect_ws, #deregister_http_client_options, #disconnect, #download, #full_uri, #handler, #http_fingerprint, #initialize, #lookup_http_fingerprints, #normalize_uri, #path_from_uri, #peer, #proxies, #reconfig_redirect_opts!, #request_opts_from_url, #request_url, #rhost, #rport, #send_request_cgi, #send_request_cgi!, #send_request_raw, #service_details, #setup, #ssl, #ssl_version, #strip_tags, #target_uri, #validate_fingerprint, #vhost
Methods included from Auxiliary::LoginScanner
Methods included from Auxiliary::Report
#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot
Methods included from Metasploit::Framework::Require
optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines
Instance Method Details
#exchange_get_version(exchange_builds: nil) ⇒ Rex::Version?
Get the Exchange version number.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/msf/core/exploit/remote/http/exchange.rb', line 57 def exchange_get_version(exchange_builds: nil) # First check target is actually Exchange return nil unless target_running_exchange? # If no exchange_builds parameter, call get_exchange_builds to build the Exchange version array. # Otherwise use supplied exchange_builds parameter after first checking to make sure its a non-empty Array. exchange_builds = get_exchange_builds if !exchange_builds.is_a?(Array) || exchange_builds.nil? # Unless lets try a cheap way of doing this via a leak of the X-OWA-Version header. # If we get this we know the version number for sure and we can skip a lot of leg work. res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/owa/service') ) unless res print_error('Target did not respond!') return nil end if res.headers['X-OWA-Version'] build = res.headers['X-OWA-Version'] return Rex::Version.new(build) end # Next, determine if we are up against an older version of Exchange Server where # the /owa/auth/logon.aspx page gives the full version. Recent versions of Exchange # give only a partial version without the build number. res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/owa/auth/logon.aspx') ) unless res print_error('Target did not respond!') return nil end if res.code == 200 && res.body =~ %r{/owa/(?>auth/)?(?<build>\d+(?>\.\d+){3})} return Rex::Version.new(Regexp.last_match('build')) end # Next try @tseller's way and try /ecp/Current/exporttool/microsoft.exchange.ediscovery.exporttool.application # URL which if successful should provide some XML with entries like the following: # # <assemblyIdentity name="microsoft.exchange.ediscovery.exporttool.application" # version="15.2.986.5" publicKeyToken="b1d1a6c45aa418ce" language="neutral" # processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /> # # This only works on Exchange Server 2013 and later and may not always work, but if it # does work it provides the full version number so its a nice strategy. res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/ecp/current/exporttool/microsoft.exchange.ediscovery.exporttool.application') ) unless res print_error('Target did not respond!') return nil end if res.code == 200 && res.body =~ /name="microsoft.exchange.ediscovery.exporttool" version="(?<build>\d+(?>\.\d+){3})"/ return Rex::Version.new(Regexp.last_match('build')) end # Finally, try a variation on the above and use a well known trick of grabbing /owa/auth/logon.aspx # to get a partial version number, then use the URL at /ecp/<version here>/exporttool/. If we get a 200 # OK response, we found the target version number, otherwise we didn't find it. # # Props go to @jmartin-r7 for improving my original code for this and suggestion the use of # canonical_segments to make this close to the Rex::Version code format. Also for noticing that # version_range is a Rex::Version object already and cleaning up some of my original code to simplify # things on this premise. exchange_builds.each do |version| res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, "/ecp/#{version}/exporttool/") ) unless res print_error('Target did not respond!') return nil end if res && res.code == 200 return Rex::Version.new(version) end end # If we reach here we couldn't find the Exchange Server version, so just return nil to indicate this. nil end |
#get_exchange_builds ⇒ Array
Build the array of Exchange Servers using the JSON file at data/exchange_versions.json. If the array has already been built then return it.
14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/msf/core/exploit/remote/http/exchange.rb', line 14 def get_exchange_builds # If we already built the exchange builds array, then just return it. return @exchange_builds if @exchange_builds @exchange_builds = [] raw_exchange_build_json = JSON.parse(File.read(::File.join(Msf::Config.data_directory, 'exchange_versions.json'), mode: 'rb')) for server_version in raw_exchange_build_json['exchange_builds'] for build in server_version['builds'] @exchange_builds << build end end end |
#target_running_exchange? ⇒ Boolean
Determine if the target is running Exchange Server or not
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/msf/core/exploit/remote/http/exchange.rb', line 31 def target_running_exchange? res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/owa/auth/logon.aspx') ) unless res print_error('Target did not respond!') return false end if res && res.code == 200 && (res.body =~ /function IsOwaPremiumBrowser/ || res.body =~ /To use Outlook, browser settings must allow scripts to run./) print_status('Target is an Exchange Server!') true else print_status('Target is NOT an Exchange Server!') false end end |